├── .github ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── question.yml └── workflows │ └── gradle.yml ├── .gitignore ├── LICENSE ├── README.md ├── api ├── build.gradle.kts └── src │ └── main │ ├── java │ └── com │ │ └── imaginarycode │ │ └── minecraft │ │ └── redisbungee │ │ ├── AbstractRedisBungeeAPI.java │ │ ├── Constants.java │ │ └── api │ │ ├── PlayerDataManager.java │ │ ├── ProxyDataManager.java │ │ ├── RedisBungeeMode.java │ │ ├── RedisBungeePlugin.java │ │ ├── config │ │ ├── LangConfiguration.java │ │ ├── RedisBungeeConfiguration.java │ │ └── loaders │ │ │ ├── ConfigLoader.java │ │ │ ├── GenericConfigLoader.java │ │ │ └── LangConfigLoader.java │ │ ├── events │ │ ├── EventsPlatform.java │ │ ├── IPlayerChangedServerNetworkEvent.java │ │ ├── IPlayerJoinedNetworkEvent.java │ │ ├── IPlayerLeftNetworkEvent.java │ │ ├── IPubSubMessageEvent.java │ │ └── RedisBungeeEvent.java │ │ ├── payloads │ │ ├── AbstractPayload.java │ │ ├── gson │ │ │ └── AbstractPayloadSerializer.java │ │ └── proxy │ │ │ ├── DeathPayload.java │ │ │ ├── HeartbeatPayload.java │ │ │ ├── PubSubPayload.java │ │ │ ├── RunCommandPayload.java │ │ │ └── gson │ │ │ ├── DeathPayloadSerializer.java │ │ │ ├── HeartbeatPayloadSerializer.java │ │ │ ├── PubSubPayloadSerializer.java │ │ │ └── RunCommandPayloadSerializer.java │ │ ├── summoners │ │ ├── JedisClusterSummoner.java │ │ ├── JedisPooledSummoner.java │ │ ├── NotClosableJedisCluster.java │ │ ├── NotClosableJedisPooled.java │ │ └── Summoner.java │ │ ├── tasks │ │ ├── RedisPipelineTask.java │ │ ├── RedisTask.java │ │ └── UUIDCleanupTask.java │ │ └── util │ │ ├── InitialUtils.java │ │ ├── RedisUtil.java │ │ ├── serialize │ │ └── MultiMapSerialization.java │ │ └── uuid │ │ ├── CachedUUIDEntry.java │ │ ├── NameFetcher.java │ │ ├── UUIDFetcher.java │ │ └── UUIDTranslator.java │ └── resources │ ├── REDISBUNGEE_LICENSE │ ├── config.yml │ └── lang.yml ├── build.gradle.kts ├── commands ├── build.gradle.kts └── src │ └── main │ └── java │ └── com │ └── imaginarycode │ └── minecraft │ └── redisbungee │ └── commands │ ├── CommandLoader.java │ ├── CommandRedisBungee.java │ ├── legacy │ ├── CommandFind.java │ ├── CommandGList.java │ ├── CommandIp.java │ ├── CommandLastSeen.java │ ├── CommandPProxy.java │ ├── CommandPlist.java │ ├── CommandSendToAll.java │ ├── CommandServerId.java │ ├── CommandServerIds.java │ └── LegacyRedisBungeeCommands.java │ └── utils │ ├── AdventureBaseCommand.java │ ├── CommandPlatformHelper.java │ └── StopperUUIDCleanupTask.java ├── copyright_print.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── proxies ├── bungeecord │ ├── build.gradle.kts │ ├── bungeecord-api │ │ ├── build.gradle.kts │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── imaginarycode │ │ │ └── minecraft │ │ │ └── redisbungee │ │ │ ├── RedisBungeeAPI.java │ │ │ └── events │ │ │ ├── PlayerChangedServerNetworkEvent.java │ │ │ ├── PlayerJoinedNetworkEvent.java │ │ │ ├── PlayerLeftNetworkEvent.java │ │ │ └── PubSubMessageEvent.java │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── imaginarycode │ │ │ └── minecraft │ │ │ └── redisbungee │ │ │ ├── BungeeCommandPlatformHelper.java │ │ │ ├── BungeePlayerDataManager.java │ │ │ ├── RedisBungee.java │ │ │ ├── RedisBungeeCommandSender.java │ │ │ └── RedisBungeeListener.java │ │ └── resources │ │ └── plugin.yml └── velocity │ ├── build.gradle.kts │ ├── src │ └── main │ │ └── java │ │ └── com │ │ └── imaginarycode │ │ └── minecraft │ │ └── redisbungee │ │ ├── RedisBungeeCommandSource.java │ │ ├── RedisBungeeListener.java │ │ ├── RedisBungeeVelocityPlugin.java │ │ ├── VelocityCommandPlatformHelper.java │ │ └── VelocityPlayerDataManager.java │ └── velocity-api │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── com │ └── imaginarycode │ └── minecraft │ └── redisbungee │ ├── RedisBungeeAPI.java │ ├── ServerObjectFetcher.java │ └── events │ ├── PlayerChangedServerNetworkEvent.java │ ├── PlayerJoinedNetworkEvent.java │ ├── PlayerLeftNetworkEvent.java │ └── PubSubMessageEvent.java └── settings.gradle.kts /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | # used https://github.com/PaperMC/Paper/blob/master/.github/ISSUE_TEMPLATE/behavior-bug-or-plugin-incompatibility.yml as template 2 | name: Bug or incompatibility 3 | description: report issues within RedisBungee 4 | labels: [ "waiting" ] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: intended behavior 9 | description: what you expected to happen. 10 | validations: 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: what the behavior you actually saw 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: Steps to reproduce 21 | description: either a video, or way you want to present it. 22 | validations: 23 | required: true 24 | 25 | - type: textarea 26 | attributes: 27 | label: Velocity or Bungeecord Versions 28 | description: | 29 | Please provide Proxy version for either Bungeecord or Velocity 30 | validations: 31 | required: true 32 | 33 | - type: textarea 34 | attributes: 35 | label: RedisBungee Version & Redis Version 36 | description: | 37 | RedisBungee version is Different from Redis Version! 38 | good example: 39 | 40 | Redis Version: 7.2 41 | RedisBungee Version: 0.12.0 42 | 43 | in-case you used development branch you can use git commit hash Instead of the version 44 | validations: 45 | required: true 46 | - type: textarea 47 | attributes: 48 | label: Other 49 | description: | 50 | extra information that we might need to know? 51 | validations: 52 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | # used https://github.com/PaperMC/Paper/blob/master/.github/ISSUE_TEMPLATE/behavior-bug-or-plugin-incompatibility.yml as template 2 | name: Ask Question 3 | description: Ask any questions to the developers 4 | labels: [ "question"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Your question? 9 | validations: 10 | required: true -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: RedisBungee Build 5 | 6 | on: 7 | push: 8 | branches: [ stable, develop ] 9 | pull_request: 10 | branches: [ stable, develop ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up JDK 17 20 | uses: actions/setup-java@v2 21 | with: 22 | java-version: '17' 23 | distribution: 'adopt' 24 | - name: Build with gradle 25 | run: ./gradlew shadowJar 26 | - name: Upload Bungee 27 | uses: actions/upload-artifact@v4.4.0 28 | with: 29 | # Artifact name 30 | name: RedisBungee-Bungee 31 | # Destination path 32 | path: proxies/bungeecord/build/libs/* 33 | - name: Upload Velocity 34 | uses: actions/upload-artifact@v4.4.0 35 | with: 36 | name: RedisBungee-Velocity 37 | path: proxies/velocity/build/libs/* 38 | - name: Upload API 39 | uses: actions/upload-artifact@v4.4.0 40 | with: 41 | name: RedisBungee-API 42 | path: api/build/libs/* 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse stuff 2 | .classpath 3 | .project 4 | .settings 5 | 6 | # random files 7 | .png 8 | .jpg 9 | 10 | # netbeans 11 | nbproject 12 | nbactions.xml 13 | nb-configuration.xml 14 | 15 | # we use maven! 16 | build.xml 17 | 18 | # maven 19 | target 20 | dependency-reduced-pom.xml 21 | # vim 22 | .*.sw[a-p] 23 | 24 | # various other potential build files 25 | build 26 | bin 27 | dist 28 | manifest.mf 29 | 30 | # Mac filesystem dust 31 | .DS_Store 32 | 33 | # intellij 34 | *.iml 35 | *.ipr 36 | *.iws 37 | .idea/ 38 | 39 | 40 | *.versionBackup 41 | *.versionsBackup 42 | # gradle 43 | .gradle 44 | 45 | # java docs 46 | javadoc 47 | 48 | # run-server folders 49 | proxies/*/run 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial code and documentation 12 | distributed under this Agreement, and 13 | b) in the case of each subsequent Contributor: 14 | i) changes to the Program, and 15 | ii) additions to the Program; 16 | 17 | where such changes and/or additions to the Program originate from and are 18 | distributed by that particular Contributor. A Contribution 'originates' 19 | from a Contributor if it was added to the Program by such Contributor 20 | itself or anyone acting on such Contributor's behalf. Contributions do not 21 | include additions to the Program which: (i) are separate modules of 22 | software distributed in conjunction with the Program under their own 23 | license agreement, and (ii) are not derivative works of the Program. 24 | 25 | "Contributor" means any person or entity that distributes the Program. 26 | 27 | "Licensed Patents" mean patent claims licensable by a Contributor which are 28 | necessarily infringed by the use or sale of its Contribution alone or when 29 | combined with the Program. 30 | 31 | "Program" means the Contributions distributed in accordance with this 32 | Agreement. 33 | 34 | "Recipient" means anyone who receives the Program under this Agreement, 35 | including all Contributors. 36 | 37 | 2. GRANT OF RIGHTS 38 | a) Subject to the terms of this Agreement, each Contributor hereby grants 39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 40 | reproduce, prepare derivative works of, publicly display, publicly 41 | perform, distribute and sublicense the Contribution of such Contributor, 42 | if any, and such derivative works, in source code and object code form. 43 | b) Subject to the terms of this Agreement, each Contributor hereby grants 44 | Recipient a non-exclusive, worldwide, royalty-free patent license under 45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 46 | transfer the Contribution of such Contributor, if any, in source code and 47 | object code form. This patent license shall apply to the combination of 48 | the Contribution and the Program if, at the time the Contribution is 49 | added by the Contributor, such addition of the Contribution causes such 50 | combination to be covered by the Licensed Patents. The patent license 51 | shall not apply to any other combinations which include the Contribution. 52 | No hardware per se is licensed hereunder. 53 | c) Recipient understands that although each Contributor grants the licenses 54 | to its Contributions set forth herein, no assurances are provided by any 55 | Contributor that the Program does not infringe the patent or other 56 | intellectual property rights of any other entity. Each Contributor 57 | disclaims any liability to Recipient for claims brought by any other 58 | entity based on infringement of intellectual property rights or 59 | otherwise. As a condition to exercising the rights and licenses granted 60 | hereunder, each Recipient hereby assumes sole responsibility to secure 61 | any other intellectual property rights needed, if any. For example, if a 62 | third party patent license is required to allow Recipient to distribute 63 | the Program, it is Recipient's responsibility to acquire that license 64 | before distributing the Program. 65 | d) Each Contributor represents that to its knowledge it has sufficient 66 | copyright rights in its Contribution, if any, to grant the copyright 67 | license set forth in this Agreement. 68 | 69 | 3. REQUIREMENTS 70 | 71 | A Contributor may choose to distribute the Program in object code form under 72 | its own license agreement, provided that: 73 | 74 | a) it complies with the terms and conditions of this Agreement; and 75 | b) its license agreement: 76 | i) effectively disclaims on behalf of all Contributors all warranties 77 | and conditions, express and implied, including warranties or 78 | conditions of title and non-infringement, and implied warranties or 79 | conditions of merchantability and fitness for a particular purpose; 80 | ii) effectively excludes on behalf of all Contributors all liability for 81 | damages, including direct, indirect, special, incidental and 82 | consequential damages, such as lost profits; 83 | iii) states that any provisions which differ from this Agreement are 84 | offered by that Contributor alone and not by any other party; and 85 | iv) states that source code for the Program is available from such 86 | Contributor, and informs licensees how to obtain it in a reasonable 87 | manner on or through a medium customarily used for software exchange. 88 | 89 | When the Program is made available in source code form: 90 | 91 | a) it must be made available under this Agreement; and 92 | b) a copy of this Agreement must be included with each copy of the Program. 93 | Contributors may not remove or alter any copyright notices contained 94 | within the Program. 95 | 96 | Each Contributor must identify itself as the originator of its Contribution, 97 | if 98 | any, in a manner that reasonably allows subsequent Recipients to identify the 99 | originator of the Contribution. 100 | 101 | 4. COMMERCIAL DISTRIBUTION 102 | 103 | Commercial distributors of software may accept certain responsibilities with 104 | respect to end users, business partners and the like. While this license is 105 | intended to facilitate the commercial use of the Program, the Contributor who 106 | includes the Program in a commercial product offering should do so in a manner 107 | which does not create potential liability for other Contributors. Therefore, 108 | if a Contributor includes the Program in a commercial product offering, such 109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify 110 | every other Contributor ("Indemnified Contributor") against any losses, 111 | damages and costs (collectively "Losses") arising from claims, lawsuits and 112 | other legal actions brought by a third party against the Indemnified 113 | Contributor to the extent caused by the acts or omissions of such Commercial 114 | Contributor in connection with its distribution of the Program in a commercial 115 | product offering. The obligations in this section do not apply to any claims 116 | or Losses relating to any actual or alleged intellectual property 117 | infringement. In order to qualify, an Indemnified Contributor must: 118 | a) promptly notify the Commercial Contributor in writing of such claim, and 119 | b) allow the Commercial Contributor to control, and cooperate with the 120 | Commercial Contributor in, the defense and any related settlement 121 | negotiations. The Indemnified Contributor may participate in any such claim at 122 | its own expense. 123 | 124 | For example, a Contributor might include the Program in a commercial product 125 | offering, Product X. That Contributor is then a Commercial Contributor. If 126 | that Commercial Contributor then makes performance claims, or offers 127 | warranties related to Product X, those performance claims and warranties are 128 | such Commercial Contributor's responsibility alone. Under this section, the 129 | Commercial Contributor would have to defend claims against the other 130 | Contributors related to those performance claims and warranties, and if a 131 | court requires any other Contributor to pay any damages as a result, the 132 | Commercial Contributor must pay those damages. 133 | 134 | 5. NO WARRANTY 135 | 136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN 137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each 140 | Recipient is solely responsible for determining the appropriateness of using 141 | and distributing the Program and assumes all risks associated with its 142 | exercise of rights under this Agreement , including but not limited to the 143 | risks and costs of program errors, compliance with applicable laws, damage to 144 | or loss of data, programs or equipment, and unavailability or interruption of 145 | operations. 146 | 147 | 6. DISCLAIMER OF LIABILITY 148 | 149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 156 | OF SUCH DAMAGES. 157 | 158 | 7. GENERAL 159 | 160 | If any provision of this Agreement is invalid or unenforceable under 161 | applicable law, it shall not affect the validity or enforceability of the 162 | remainder of the terms of this Agreement, and without further action by the 163 | parties hereto, such provision shall be reformed to the minimum extent 164 | necessary to make such provision valid and enforceable. 165 | 166 | If Recipient institutes patent litigation against any entity (including a 167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 168 | (excluding combinations of the Program with other software or hardware) 169 | infringes such Recipient's patent(s), then such Recipient's rights granted 170 | under Section 2(b) shall terminate as of the date such litigation is filed. 171 | 172 | All Recipient's rights under this Agreement shall terminate if it fails to 173 | comply with any of the material terms or conditions of this Agreement and does 174 | not cure such failure in a reasonable period of time after becoming aware of 175 | such noncompliance. If all Recipient's rights under this Agreement terminate, 176 | Recipient agrees to cease use and distribution of the Program as soon as 177 | reasonably practicable. However, Recipient's obligations under this Agreement 178 | and any licenses granted by Recipient relating to the Program shall continue 179 | and survive. 180 | 181 | Everyone is permitted to copy and distribute copies of this Agreement, but in 182 | order to avoid inconsistency the Agreement is copyrighted and may only be 183 | modified in the following manner. The Agreement Steward reserves the right to 184 | publish new versions (including revisions) of this Agreement from time to 185 | time. No one other than the Agreement Steward has the right to modify this 186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 187 | Eclipse Foundation may assign the responsibility to serve as the Agreement 188 | Steward to a suitable separate entity. Each new version of the Agreement will 189 | be given a distinguishing version number. The Program (including 190 | Contributions) may always be distributed subject to the version of the 191 | Agreement under which it was received. In addition, after a new version of the 192 | Agreement is published, Contributor may elect to distribute the Program 193 | (including its Contributions) under the new version. Except as expressly 194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 195 | licenses to the intellectual property of any Contributor under this Agreement, 196 | whether expressly, by implication, estoppel or otherwise. All rights in the 197 | Program not expressly granted under this Agreement are reserved. 198 | 199 | This Agreement is governed by the laws of the State of New York and the 200 | intellectual property laws of the United States of America. No party to this 201 | Agreement will bring a legal action under this Agreement more than one year 202 | after the cause of action arose. Each party waives its rights to a jury trial in 203 | any resulting litigation. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RedisBungee Limework's Fork 2 | 3 | The original project of RedisBungee is no longer maintained, so we have forked the plugin. 4 | RedisBungee uses [Redis](https://redis.io) with Java client [Jedis](https://github.com/redis/jedis/) 5 | to Synchronize players data between [BungeeCord](https://github.com/SpigotMC/BungeeCord) 6 | or [Velocity*](https://github.com/PaperMC/Velocity) proxies 7 | 8 | ## Downloads 9 | 10 | [![](https://raw.githubusercontent.com/Prospector/badges/master/modrinth-badge-72h-padded.png)](https://modrinth.com/plugin/redisbungee) 11 | 12 | ## Wiki 13 | 14 | https://github.com/ProxioDev/RedisBungee/wiki 15 | 16 | ## Support 17 | 18 | open an issue with question button 19 | 20 | ## License 21 | 22 | This project is distributed under Eclipse Public License 1.0 23 | 24 | You can find it [here](https://github.com/proxiodev/RedisBungee/blob/master/LICENSE) 25 | 26 | You can find the original RedisBungee is by [astei](https://github.com/astei) and project can be 27 | found [here](https://github.com/minecrafter/RedisBungee) or spigot 28 | page [here, but its no longer available](https://www.spigotmc.org/resources/redisbungee.13494/) 29 | 30 | -------------------------------------------------------------------------------- /api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.time.Instant 2 | import java.io.ByteArrayOutputStream 3 | 4 | plugins { 5 | `java-library` 6 | `maven-publish` 7 | id("net.kyori.blossom") version "1.2.0" 8 | 9 | } 10 | 11 | dependencies { 12 | api(libs.guava) 13 | api(libs.jedis) 14 | api(libs.okhttp) 15 | api(libs.configurate) 16 | api(libs.caffeine) 17 | api(libs.adventure.api) 18 | api(libs.adventure.gson) 19 | api(libs.adventure.legacy) 20 | api(libs.adventure.plain) 21 | api(libs.adventure.miniMessage) 22 | } 23 | 24 | description = "RedisBungee interfaces" 25 | 26 | blossom { 27 | replaceToken("@version@", "$version") 28 | // GIT 29 | val commit: String; 30 | val commitStdout = ByteArrayOutputStream() 31 | rootProject.exec { 32 | standardOutput = commitStdout 33 | commandLine("git", "rev-parse", "HEAD") 34 | } 35 | commit = "$commitStdout".replace("\n", "") // for some reason it adds new line so remove it. 36 | commitStdout.close() 37 | replaceToken("@git_commit@", commit) 38 | } 39 | 40 | 41 | java { 42 | withJavadocJar() 43 | withSourcesJar() 44 | } 45 | 46 | tasks { 47 | // thanks again for paper too 48 | withType { 49 | val options = options as StandardJavadocDocletOptions 50 | options.use() 51 | options.isDocFilesSubDirs = true 52 | val jedisVersion = libs.jedis.get().version 53 | val configurateVersion = libs.configurate.get().version 54 | val guavaVersion = libs.guava.get().version 55 | val adventureVersion = libs.adventure.plain.get().version 56 | options.links( 57 | "https://configurate.aoeu.xyz/$configurateVersion/apidocs/", // configurate 58 | "https://javadoc.io/doc/redis.clients/jedis/$jedisVersion/", // jedis 59 | "https://guava.dev/releases/$guavaVersion/api/docs/", // guava 60 | "https://javadoc.io/doc/com.github.ben-manes.caffeine/caffeine", 61 | "https://jd.advntr.dev/api/$adventureVersion" 62 | 63 | ) 64 | 65 | } 66 | 67 | compileJava { 68 | options.encoding = Charsets.UTF_8.name() 69 | options.release.set(17) 70 | } 71 | javadoc { 72 | options.encoding = Charsets.UTF_8.name() 73 | } 74 | processResources { 75 | filteringCharset = Charsets.UTF_8.name() 76 | } 77 | } 78 | 79 | publishing { 80 | publications { 81 | create("maven") { 82 | from(components["java"]) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | 12 | package com.imaginarycode.minecraft.redisbungee; 13 | 14 | public class Constants { 15 | 16 | public final static String VERSION = "@version@"; 17 | public final static String GIT_COMMIT = "@git_commit@"; 18 | 19 | public static String getGithubCommitLink() { 20 | return "https://github.com/ProxioDev/RedisBungee/commit/" + GIT_COMMIT; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/RedisBungeeMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api; 12 | 13 | public enum RedisBungeeMode { 14 | SINGLE, CLUSTER 15 | } 16 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/RedisBungeePlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.AbstractRedisBungeeAPI; 14 | import com.imaginarycode.minecraft.redisbungee.api.config.LangConfiguration; 15 | import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration; 16 | import com.imaginarycode.minecraft.redisbungee.api.events.EventsPlatform; 17 | import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner; 18 | import com.imaginarycode.minecraft.redisbungee.api.util.uuid.UUIDTranslator; 19 | import net.kyori.adventure.text.Component; 20 | 21 | import java.net.InetAddress; 22 | import java.util.UUID; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | 26 | /** 27 | * This Class has all internal methods needed by every redis bungee plugin, and it can be used to implement another platforms than bungeecord or another forks of RedisBungee 28 | *

29 | * Reason this is interface because some proxies implementations require the user to extend class for plugins for example bungeecord. 30 | * 31 | * @author Ham1255 32 | * @since 0.7.0 33 | */ 34 | public interface RedisBungeePlugin

extends EventsPlatform { 35 | 36 | default void initialize() { 37 | 38 | } 39 | 40 | default void stop() { 41 | 42 | } 43 | 44 | void logInfo(String msg); 45 | 46 | void logInfo(String format, Object... object); 47 | 48 | void logWarn(String msg); 49 | 50 | void logWarn(String format, Object... object); 51 | 52 | void logFatal(String msg); 53 | 54 | void logFatal(String format, Throwable throwable); 55 | 56 | RedisBungeeConfiguration configuration(); 57 | 58 | LangConfiguration langConfiguration(); 59 | 60 | Summoner getSummoner(); 61 | 62 | RedisBungeeMode getRedisBungeeMode(); 63 | 64 | AbstractRedisBungeeAPI getAbstractRedisBungeeApi(); 65 | 66 | ProxyDataManager proxyDataManager(); 67 | 68 | PlayerDataManager playerDataManager(); 69 | 70 | UUIDTranslator getUuidTranslator(); 71 | 72 | boolean isOnlineMode(); 73 | 74 | P getPlayer(UUID uuid); 75 | 76 | P getPlayer(String name); 77 | 78 | UUID getPlayerUUID(String player); 79 | 80 | 81 | String getPlayerName(UUID player); 82 | 83 | boolean handlePlatformKick(UUID uuid, Component message); 84 | 85 | String getPlayerServerName(P player); 86 | 87 | boolean isPlayerOnAServer(P player); 88 | 89 | InetAddress getPlayerIp(P player); 90 | 91 | void executeAsync(Runnable runnable); 92 | 93 | void executeAsyncAfter(Runnable runnable, TimeUnit timeUnit, int time); 94 | 95 | 96 | } 97 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/config/LangConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.config; 12 | 13 | import net.kyori.adventure.text.Component; 14 | import net.kyori.adventure.text.minimessage.MiniMessage; 15 | import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; 16 | 17 | import java.util.HashMap; 18 | import java.util.Locale; 19 | import java.util.Map; 20 | 21 | /** 22 | * This language support implementation is temporarily 23 | * until I come up with better system but for now we will use Maps instead :/ 24 | * Todo: possible usage of adventure api 25 | */ 26 | public class LangConfiguration { 27 | 28 | private interface RegistrableMessages { 29 | 30 | void register(String id, Locale locale, String miniMessage); 31 | 32 | void test(Locale locale); 33 | 34 | default void throwError(Locale locale, String where) { 35 | throw new IllegalStateException("Language system in `" + where + "` found missing entries for " + locale.toString()); 36 | } 37 | 38 | } 39 | 40 | public static class Messages implements RegistrableMessages{ 41 | 42 | private final Map LOGGED_IN_FROM_OTHER_LOCATION; 43 | private final Map ALREADY_LOGGED_IN; 44 | private final Map SERVER_CONNECTING; 45 | private final Map SERVER_NOT_FOUND; 46 | 47 | private final Locale defaultLocale; 48 | 49 | public Messages(Locale defaultLocale) { 50 | LOGGED_IN_FROM_OTHER_LOCATION = new HashMap<>(); 51 | ALREADY_LOGGED_IN = new HashMap<>(); 52 | SERVER_CONNECTING = new HashMap<>(); 53 | SERVER_NOT_FOUND = new HashMap<>(); 54 | this.defaultLocale = defaultLocale; 55 | } 56 | 57 | public void register(String id, Locale locale, String miniMessage) { 58 | switch (id) { 59 | case "server-not-found" -> SERVER_NOT_FOUND.put(locale, miniMessage); 60 | case "server-connecting" -> SERVER_CONNECTING.put(locale, miniMessage); 61 | case "logged-in-other-location" -> LOGGED_IN_FROM_OTHER_LOCATION.put(locale, MiniMessage.miniMessage().deserialize(miniMessage)); 62 | case "already-logged-in" -> ALREADY_LOGGED_IN.put(locale, MiniMessage.miniMessage().deserialize(miniMessage)); 63 | } 64 | } 65 | 66 | public Component alreadyLoggedIn(Locale locale) { 67 | if (ALREADY_LOGGED_IN.containsKey(locale)) return ALREADY_LOGGED_IN.get(locale); 68 | return ALREADY_LOGGED_IN.get(defaultLocale); 69 | } 70 | 71 | // there is no way to know whats client locale during login so just default to use default locale MESSAGES. 72 | public Component alreadyLoggedIn() { 73 | return this.alreadyLoggedIn(this.defaultLocale); 74 | } 75 | 76 | public Component loggedInFromOtherLocation(Locale locale) { 77 | if (LOGGED_IN_FROM_OTHER_LOCATION.containsKey(locale)) return LOGGED_IN_FROM_OTHER_LOCATION.get(locale); 78 | return LOGGED_IN_FROM_OTHER_LOCATION.get(defaultLocale); 79 | } 80 | 81 | // there is no way to know what's client locale during login so just default to use default locale MESSAGES. 82 | public Component loggedInFromOtherLocation() { 83 | return this.loggedInFromOtherLocation(this.defaultLocale); 84 | } 85 | 86 | public Component serverConnecting(Locale locale, String server) { 87 | String miniMessage; 88 | if (SERVER_CONNECTING.containsKey(locale)) { 89 | miniMessage = SERVER_CONNECTING.get(locale); 90 | } else { 91 | miniMessage = SERVER_CONNECTING.get(defaultLocale); 92 | } 93 | return MiniMessage.miniMessage().deserialize(miniMessage, Placeholder.parsed("server", server)); 94 | } 95 | 96 | public Component serverConnecting(String server) { 97 | return this.serverConnecting(this.defaultLocale, server); 98 | } 99 | 100 | public Component serverNotFound(Locale locale, String server) { 101 | String miniMessage; 102 | if (SERVER_NOT_FOUND.containsKey(locale)) { 103 | miniMessage = SERVER_NOT_FOUND.get(locale); 104 | } else { 105 | miniMessage = SERVER_NOT_FOUND.get(defaultLocale); 106 | } 107 | return MiniMessage.miniMessage().deserialize(miniMessage, Placeholder.parsed("server", server)); 108 | } 109 | 110 | public Component serverNotFound(String server) { 111 | return this.serverNotFound(this.defaultLocale, server); 112 | } 113 | 114 | 115 | // tests locale if set CORRECTLY or just throw if not 116 | public void test(Locale locale) { 117 | if (!(LOGGED_IN_FROM_OTHER_LOCATION.containsKey(locale) && ALREADY_LOGGED_IN.containsKey(locale) && SERVER_CONNECTING.containsKey(locale) && SERVER_NOT_FOUND.containsKey(locale))) { 118 | throwError(locale, "messages"); 119 | } 120 | } 121 | 122 | } 123 | 124 | private final Component redisBungeePrefix; 125 | 126 | private final Locale defaultLanguage; 127 | 128 | private final boolean useClientLanguage; 129 | 130 | private final Messages messages; 131 | 132 | public LangConfiguration(Component redisBungeePrefix, Locale defaultLanguage, boolean useClientLanguage, Messages messages) { 133 | this.redisBungeePrefix = redisBungeePrefix; 134 | this.defaultLanguage = defaultLanguage; 135 | this.useClientLanguage = useClientLanguage; 136 | this.messages = messages; 137 | } 138 | 139 | public Component redisBungeePrefix() { 140 | return redisBungeePrefix; 141 | } 142 | 143 | public Locale defaultLanguage() { 144 | return defaultLanguage; 145 | } 146 | 147 | public boolean useClientLanguage() { 148 | return useClientLanguage; 149 | } 150 | 151 | public Messages messages() { 152 | return messages; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/config/RedisBungeeConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.config; 12 | 13 | import com.google.common.collect.ImmutableList; 14 | import com.google.common.net.InetAddresses; 15 | 16 | import javax.annotation.Nullable; 17 | import java.net.InetAddress; 18 | import java.util.List; 19 | 20 | public class RedisBungeeConfiguration { 21 | 22 | private final String proxyId; 23 | private final List exemptAddresses; 24 | private final boolean kickWhenOnline; 25 | 26 | private final boolean handleReconnectToLastServer; 27 | private final boolean handleMotd; 28 | 29 | private final CommandsConfiguration commandsConfiguration; 30 | private final String networkId; 31 | 32 | 33 | public RedisBungeeConfiguration(String networkId, String proxyId, List exemptAddresses, boolean kickWhenOnline, boolean handleReconnectToLastServer, boolean handleMotd, CommandsConfiguration commandsConfiguration) { 34 | this.proxyId = proxyId; 35 | ImmutableList.Builder addressBuilder = ImmutableList.builder(); 36 | for (String s : exemptAddresses) { 37 | addressBuilder.add(InetAddresses.forString(s)); 38 | } 39 | this.exemptAddresses = addressBuilder.build(); 40 | this.kickWhenOnline = kickWhenOnline; 41 | this.handleReconnectToLastServer = handleReconnectToLastServer; 42 | this.handleMotd = handleMotd; 43 | this.commandsConfiguration = commandsConfiguration; 44 | this.networkId = networkId; 45 | } 46 | 47 | public String getProxyId() { 48 | return proxyId; 49 | } 50 | 51 | public List getExemptAddresses() { 52 | return exemptAddresses; 53 | } 54 | 55 | public boolean kickWhenOnline() { 56 | return kickWhenOnline; 57 | } 58 | 59 | public boolean handleMotd() { 60 | return this.handleMotd; 61 | } 62 | 63 | public boolean handleReconnectToLastServer() { 64 | return this.handleReconnectToLastServer; 65 | } 66 | 67 | public record CommandsConfiguration(boolean redisbungeeEnabled, boolean redisbungeeLegacyEnabled, 68 | @Nullable LegacySubCommandsConfiguration legacySubCommandsConfiguration) { 69 | 70 | } 71 | 72 | public record LegacySubCommandsConfiguration(boolean findEnabled, boolean glistEnabled, boolean ipEnabled, 73 | boolean lastseenEnabled, boolean plistEnabled, boolean pproxyEnabled, 74 | boolean sendtoallEnabled, boolean serveridEnabled, 75 | boolean serveridsEnabled, boolean installFind, boolean installGlist, boolean installIp, 76 | boolean installLastseen, boolean installPlist, boolean installPproxy, 77 | boolean installSendtoall, boolean installServerid, 78 | boolean installServerids) { 79 | } 80 | 81 | public CommandsConfiguration commandsConfiguration() { 82 | return commandsConfiguration; 83 | } 84 | 85 | public String networkId() { 86 | return networkId; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/config/loaders/GenericConfigLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.config.loaders; 12 | 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.nio.file.Files; 18 | import java.nio.file.Path; 19 | import java.nio.file.StandardCopyOption; 20 | import java.time.Instant; 21 | 22 | 23 | public interface GenericConfigLoader { 24 | 25 | // CHANGES on every reboot 26 | String RANDOM_OLD = "backup-" + Instant.now().getEpochSecond(); 27 | 28 | default Path createConfigFile(Path dataFolder, String configFile, @Nullable String defaultResourceID) throws IOException { 29 | if (Files.notExists(dataFolder)) { 30 | Files.createDirectory(dataFolder); 31 | } 32 | Path file = dataFolder.resolve(configFile); 33 | if (Files.notExists(file) && defaultResourceID != null) { 34 | try (InputStream in = getClass().getClassLoader().getResourceAsStream(defaultResourceID)) { 35 | Files.createFile(file); 36 | assert in != null; 37 | Files.copy(in, file, StandardCopyOption.REPLACE_EXISTING); 38 | } 39 | } 40 | return file; 41 | } 42 | 43 | default void handleOldConfig(Path dataFolder, String configFile, @Nullable String defaultResourceID) throws IOException { 44 | Path oldConfigFolder = dataFolder.resolve("old_config"); 45 | if (Files.notExists(oldConfigFolder)) { 46 | Files.createDirectory(oldConfigFolder); 47 | } 48 | Path randomStoreConfigDirectory = oldConfigFolder.resolve(RANDOM_OLD); 49 | if (Files.notExists(randomStoreConfigDirectory)) { 50 | Files.createDirectory(randomStoreConfigDirectory); 51 | } 52 | Path oldConfigPath = dataFolder.resolve(configFile); 53 | 54 | Files.move(oldConfigPath, randomStoreConfigDirectory.resolve(configFile)); 55 | createConfigFile(dataFolder, configFile, defaultResourceID); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/config/loaders/LangConfigLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.config.loaders; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 14 | import com.imaginarycode.minecraft.redisbungee.api.config.LangConfiguration; 15 | import net.kyori.adventure.text.Component; 16 | import net.kyori.adventure.text.minimessage.MiniMessage; 17 | import ninja.leaping.configurate.ConfigurationNode; 18 | import ninja.leaping.configurate.yaml.YAMLConfigurationLoader; 19 | 20 | import java.io.IOException; 21 | import java.nio.file.Path; 22 | import java.util.Locale; 23 | 24 | public interface LangConfigLoader extends GenericConfigLoader { 25 | 26 | int CONFIG_VERSION = 1; 27 | 28 | default void loadLangConfig(RedisBungeePlugin plugin, Path dataFolder) throws IOException { 29 | Path configFile = createConfigFile(dataFolder, "lang.yml", "lang.yml"); 30 | final YAMLConfigurationLoader yamlConfigurationFileLoader = YAMLConfigurationLoader.builder().setPath(configFile).build(); 31 | ConfigurationNode node = yamlConfigurationFileLoader.load(); 32 | if (node.getNode("config-version").getInt(0) != CONFIG_VERSION) { 33 | handleOldConfig(dataFolder, "lang.yml", "lang.yml"); 34 | node = yamlConfigurationFileLoader.load(); 35 | } 36 | // MINI message serializer 37 | MiniMessage miniMessage = MiniMessage.miniMessage(); 38 | 39 | Component prefix = miniMessage.deserialize(node.getNode("prefix").getString("[RedisBungee]")); 40 | Locale defaultLocale = Locale.forLanguageTag(node.getNode("default-locale").getString("en-us")); 41 | boolean useClientLocale = node.getNode("use-client-locale").getBoolean(true); 42 | LangConfiguration.Messages messages = new LangConfiguration.Messages(defaultLocale); 43 | node.getNode("messages").getChildrenMap().forEach((key, childNode) -> childNode.getChildrenMap().forEach((childKey, childChildNode) -> { 44 | messages.register(key.toString(), Locale.forLanguageTag(childKey.toString()), childChildNode.getString()); 45 | })); 46 | messages.test(defaultLocale); 47 | 48 | onLangConfigLoad(new LangConfiguration(prefix, defaultLocale, useClientLocale, messages)); 49 | } 50 | 51 | 52 | void onLangConfigLoad(LangConfiguration langConfiguration); 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/events/EventsPlatform.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.events; 12 | 13 | import java.util.UUID; 14 | 15 | /** 16 | * Since each platform have their own events' implementation for example Bungeecord events extends Event while velocity don't 17 | * 18 | * @author Ham1255 19 | * @since 0.7.0 20 | */ 21 | public interface EventsPlatform { 22 | 23 | IPlayerChangedServerNetworkEvent createPlayerChangedServerNetworkEvent(UUID uuid, String previousServer, String server); 24 | 25 | IPlayerJoinedNetworkEvent createPlayerJoinedNetworkEvent(UUID uuid); 26 | 27 | IPlayerLeftNetworkEvent createPlayerLeftNetworkEvent(UUID uuid); 28 | 29 | IPubSubMessageEvent createPubSubEvent(String channel, String message); 30 | 31 | void fireEvent(Object event); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/events/IPlayerChangedServerNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.events; 12 | 13 | import java.util.UUID; 14 | 15 | public interface IPlayerChangedServerNetworkEvent extends RedisBungeeEvent { 16 | 17 | UUID getUuid(); 18 | 19 | String getServer(); 20 | 21 | String getPreviousServer(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/events/IPlayerJoinedNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.events; 12 | 13 | import java.util.UUID; 14 | 15 | public interface IPlayerJoinedNetworkEvent extends RedisBungeeEvent { 16 | 17 | UUID getUuid(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/events/IPlayerLeftNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.events; 12 | 13 | import java.util.UUID; 14 | 15 | public interface IPlayerLeftNetworkEvent extends RedisBungeeEvent { 16 | 17 | UUID getUuid(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/events/IPubSubMessageEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.events; 12 | 13 | public interface IPubSubMessageEvent extends RedisBungeeEvent { 14 | 15 | String getChannel(); 16 | 17 | String getMessage(); 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/events/RedisBungeeEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.events; 12 | 13 | interface RedisBungeeEvent { 14 | } 15 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/AbstractPayload.java: -------------------------------------------------------------------------------- 1 | 2 | package com.imaginarycode.minecraft.redisbungee.api.payloads; 3 | 4 | public abstract class AbstractPayload { 5 | 6 | private final String senderProxy; 7 | 8 | public AbstractPayload(String proxyId) { 9 | this.senderProxy = proxyId; 10 | } 11 | 12 | public AbstractPayload(String senderProxy, String className) { 13 | this.senderProxy = senderProxy; 14 | } 15 | 16 | public String senderProxy() { 17 | return senderProxy; 18 | } 19 | 20 | public String getClassName() { 21 | return getClass().getName(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/gson/AbstractPayloadSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.gson; 12 | 13 | import com.google.gson.*; 14 | import com.imaginarycode.minecraft.redisbungee.api.payloads.AbstractPayload; 15 | 16 | import java.lang.reflect.Type; 17 | 18 | public class AbstractPayloadSerializer implements JsonSerializer, JsonDeserializer { 19 | 20 | 21 | @Override 22 | public AbstractPayload deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 23 | JsonObject jsonObject = json.getAsJsonObject(); 24 | return new AbstractPayload(jsonObject.get("proxy").getAsString(), jsonObject.get("class").getAsString()) { 25 | }; 26 | } 27 | 28 | @Override 29 | public JsonElement serialize(AbstractPayload src, Type typeOfSrc, JsonSerializationContext context) { 30 | JsonObject jsonObject = new JsonObject(); 31 | jsonObject.add("proxy", new JsonPrimitive(src.senderProxy())); 32 | return jsonObject; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/DeathPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.payloads.AbstractPayload; 14 | 15 | public class DeathPayload extends AbstractPayload { 16 | public DeathPayload(String proxyId) { 17 | super(proxyId); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/HeartbeatPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.payloads.AbstractPayload; 14 | 15 | public class HeartbeatPayload extends AbstractPayload { 16 | 17 | public record HeartbeatData(long heartbeat, int players) { 18 | 19 | } 20 | 21 | private final HeartbeatData data; 22 | 23 | public HeartbeatPayload(String proxyId, HeartbeatData data) { 24 | super(proxyId); 25 | this.data = data; 26 | } 27 | 28 | public HeartbeatData data() { 29 | return data; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/PubSubPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.payloads.AbstractPayload; 14 | 15 | public class PubSubPayload extends AbstractPayload { 16 | 17 | private final String channel; 18 | private final String message; 19 | 20 | 21 | public PubSubPayload(String proxyId, String channel, String message) { 22 | super(proxyId); 23 | this.channel = channel; 24 | this.message = message; 25 | } 26 | 27 | public String channel() { 28 | return channel; 29 | } 30 | 31 | public String message() { 32 | return message; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/RunCommandPayload.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.payloads.AbstractPayload; 14 | 15 | public class RunCommandPayload extends AbstractPayload { 16 | 17 | 18 | private final String proxyToRun; 19 | 20 | private final String command; 21 | 22 | 23 | public RunCommandPayload(String proxyId, String proxyToRun, String command) { 24 | super(proxyId); 25 | this.proxyToRun = proxyToRun; 26 | this.command = command; 27 | } 28 | 29 | public String proxyToRun() { 30 | return proxyToRun; 31 | } 32 | 33 | public String command() { 34 | return command; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/gson/DeathPayloadSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.gson; 12 | 13 | import com.google.gson.*; 14 | import com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.DeathPayload; 15 | 16 | import java.lang.reflect.Type; 17 | 18 | public class DeathPayloadSerializer implements JsonSerializer, JsonDeserializer { 19 | 20 | private static final Gson gson = new Gson(); 21 | 22 | 23 | @Override 24 | public DeathPayload deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 25 | JsonObject jsonObject = json.getAsJsonObject(); 26 | String senderProxy = jsonObject.get("proxy").getAsString(); 27 | return new DeathPayload(senderProxy); 28 | } 29 | 30 | @Override 31 | public JsonElement serialize(DeathPayload src, Type typeOfSrc, JsonSerializationContext context) { 32 | JsonObject jsonObject = new JsonObject(); 33 | jsonObject.add("proxy", new JsonPrimitive(src.senderProxy())); 34 | return jsonObject; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/gson/HeartbeatPayloadSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.gson; 12 | 13 | import com.google.gson.*; 14 | import com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.HeartbeatPayload; 15 | 16 | import java.lang.reflect.Type; 17 | 18 | public class HeartbeatPayloadSerializer implements JsonSerializer, JsonDeserializer { 19 | 20 | 21 | @Override 22 | public HeartbeatPayload deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 23 | JsonObject jsonObject = json.getAsJsonObject(); 24 | String senderProxy = jsonObject.get("proxy").getAsString(); 25 | long heartbeat = jsonObject.get("heartbeat").getAsLong(); 26 | int players = jsonObject.get("players").getAsInt(); 27 | return new HeartbeatPayload(senderProxy, new HeartbeatPayload.HeartbeatData(heartbeat, players)); 28 | } 29 | 30 | @Override 31 | public JsonElement serialize(HeartbeatPayload src, Type typeOfSrc, JsonSerializationContext context) { 32 | JsonObject jsonObject = new JsonObject(); 33 | jsonObject.add("proxy", new JsonPrimitive(src.senderProxy())); 34 | jsonObject.add("heartbeat", new JsonPrimitive(src.data().heartbeat())); 35 | jsonObject.add("players", new JsonPrimitive(src.data().players())); 36 | return jsonObject; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/gson/PubSubPayloadSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.gson; 12 | 13 | import com.google.gson.*; 14 | import com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.PubSubPayload; 15 | 16 | import java.lang.reflect.Type; 17 | 18 | public class PubSubPayloadSerializer implements JsonSerializer, JsonDeserializer { 19 | 20 | private static final Gson gson = new Gson(); 21 | 22 | 23 | @Override 24 | public PubSubPayload deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 25 | JsonObject jsonObject = json.getAsJsonObject(); 26 | String senderProxy = jsonObject.get("proxy").getAsString(); 27 | String channel = jsonObject.get("channel").getAsString(); 28 | String message = jsonObject.get("message").getAsString(); 29 | return new PubSubPayload(senderProxy, channel, message); 30 | } 31 | 32 | @Override 33 | public JsonElement serialize(PubSubPayload src, Type typeOfSrc, JsonSerializationContext context) { 34 | JsonObject jsonObject = new JsonObject(); 35 | jsonObject.add("proxy", new JsonPrimitive(src.senderProxy())); 36 | jsonObject.add("channel", new JsonPrimitive(src.channel())); 37 | jsonObject.add("message", context.serialize(src.message())); 38 | return jsonObject; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/payloads/proxy/gson/RunCommandPayloadSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.gson; 12 | 13 | import com.google.gson.*; 14 | import com.imaginarycode.minecraft.redisbungee.api.payloads.proxy.RunCommandPayload; 15 | 16 | import java.lang.reflect.Type; 17 | 18 | public class RunCommandPayloadSerializer implements JsonSerializer, JsonDeserializer { 19 | 20 | 21 | @Override 22 | public RunCommandPayload deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 23 | JsonObject jsonObject = json.getAsJsonObject(); 24 | String senderProxy = jsonObject.get("proxy").getAsString(); 25 | String proxyToRun = jsonObject.get("proxy-to-run").getAsString(); 26 | String command = jsonObject.get("command").getAsString(); 27 | return new RunCommandPayload(senderProxy, proxyToRun, command); 28 | } 29 | 30 | @Override 31 | public JsonElement serialize(RunCommandPayload src, Type typeOfSrc, JsonSerializationContext context) { 32 | JsonObject jsonObject = new JsonObject(); 33 | jsonObject.add("proxy", new JsonPrimitive(src.senderProxy())); 34 | jsonObject.add("proxy-to-run", new JsonPrimitive(src.proxyToRun())); 35 | jsonObject.add("command", context.serialize(src.command())); 36 | return jsonObject; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/summoners/JedisClusterSummoner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.summoners; 12 | 13 | import redis.clients.jedis.JedisCluster; 14 | import redis.clients.jedis.providers.ClusterConnectionProvider; 15 | 16 | import java.io.IOException; 17 | import java.time.Duration; 18 | 19 | public class JedisClusterSummoner implements Summoner { 20 | private final ClusterConnectionProvider clusterConnectionProvider; 21 | 22 | public JedisClusterSummoner(ClusterConnectionProvider clusterConnectionProvider) { 23 | this.clusterConnectionProvider = clusterConnectionProvider; 24 | // test the connection 25 | JedisCluster jedisCluster = obtainResource(); 26 | jedisCluster.set("random_data", "0"); 27 | jedisCluster.del("random_data"); 28 | } 29 | 30 | 31 | @Override 32 | public void close() throws IOException { 33 | this.clusterConnectionProvider.close(); 34 | } 35 | 36 | @Override 37 | public JedisCluster obtainResource() { 38 | return new NotClosableJedisCluster(this.clusterConnectionProvider, 60, Duration.ofSeconds(10)); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/summoners/JedisPooledSummoner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.summoners; 12 | 13 | import redis.clients.jedis.Jedis; 14 | import redis.clients.jedis.JedisPool; 15 | import redis.clients.jedis.JedisPooled; 16 | import redis.clients.jedis.providers.PooledConnectionProvider; 17 | 18 | import java.io.IOException; 19 | 20 | public class JedisPooledSummoner implements Summoner { 21 | 22 | private final PooledConnectionProvider connectionProvider; 23 | private final JedisPool jedisPool; 24 | 25 | public JedisPooledSummoner(PooledConnectionProvider connectionProvider, JedisPool jedisPool) { 26 | this.connectionProvider = connectionProvider; 27 | this.jedisPool = jedisPool; 28 | // test connections 29 | if (jedisPool != null) { 30 | try (Jedis jedis = this.jedisPool.getResource()) { 31 | // Test the connection to make sure configuration is right 32 | jedis.ping(); 33 | } 34 | 35 | } 36 | final JedisPooled jedisPooled = this.obtainResource(); 37 | jedisPooled.set("random_data", "0"); 38 | jedisPooled.del("random_data"); 39 | 40 | } 41 | 42 | @Override 43 | public JedisPooled obtainResource() { 44 | // create UnClosable JedisPool *disposable* 45 | return new NotClosableJedisPooled(this.connectionProvider); 46 | } 47 | 48 | public JedisPool getCompatibilityJedisPool() { 49 | return this.jedisPool; 50 | } 51 | 52 | @Override 53 | public void close() throws IOException { 54 | if (this.jedisPool != null) { 55 | this.jedisPool.close(); 56 | } 57 | this.connectionProvider.close(); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/summoners/NotClosableJedisCluster.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.summoners; 12 | 13 | import redis.clients.jedis.JedisCluster; 14 | import redis.clients.jedis.providers.ClusterConnectionProvider; 15 | 16 | import java.time.Duration; 17 | 18 | 19 | public class NotClosableJedisCluster extends JedisCluster { 20 | 21 | NotClosableJedisCluster(ClusterConnectionProvider provider, int maxAttempts, Duration maxTotalRetriesDuration) { 22 | super(provider, maxAttempts, maxTotalRetriesDuration); 23 | } 24 | 25 | @Override 26 | public void close() { 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/summoners/NotClosableJedisPooled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.summoners; 12 | 13 | import redis.clients.jedis.JedisPooled; 14 | import redis.clients.jedis.providers.PooledConnectionProvider; 15 | 16 | 17 | public class NotClosableJedisPooled extends JedisPooled { 18 | NotClosableJedisPooled(PooledConnectionProvider provider) { 19 | super(provider); 20 | } 21 | 22 | @Override 23 | public void close() { 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/summoners/Summoner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.summoners; 12 | 13 | import redis.clients.jedis.UnifiedJedis; 14 | 15 | import java.io.Closeable; 16 | 17 | 18 | /** 19 | * This class intended for future release to support redis sentinel or redis clusters 20 | * 21 | * @author Ham1255 22 | * @since 0.7.0 23 | */ 24 | public interface Summoner

extends Closeable { 25 | 26 | P obtainResource(); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/tasks/RedisPipelineTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.tasks; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.AbstractRedisBungeeAPI; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 15 | import redis.clients.jedis.*; 16 | 17 | public abstract class RedisPipelineTask extends RedisTask { 18 | 19 | 20 | public RedisPipelineTask(AbstractRedisBungeeAPI api) { 21 | super(api); 22 | } 23 | 24 | public RedisPipelineTask(RedisBungeePlugin plugin) { 25 | super(plugin); 26 | } 27 | 28 | 29 | @Override 30 | public T unifiedJedisTask(UnifiedJedis unifiedJedis) { 31 | if (unifiedJedis instanceof JedisPooled pooled) { 32 | try (Pipeline pipeline = pooled.pipelined()) { 33 | return doPooledPipeline(pipeline); 34 | } 35 | } else if (unifiedJedis instanceof JedisCluster jedisCluster) { 36 | try (ClusterPipeline pipeline = jedisCluster.pipelined()) { 37 | return clusterPipeline(pipeline); 38 | } 39 | } 40 | 41 | return null; 42 | } 43 | 44 | public abstract T doPooledPipeline(Pipeline pipeline); 45 | 46 | public abstract T clusterPipeline(ClusterPipeline pipeline); 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/tasks/RedisTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.tasks; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.AbstractRedisBungeeAPI; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode; 15 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 16 | import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisClusterSummoner; 17 | import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner; 18 | import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner; 19 | import redis.clients.jedis.UnifiedJedis; 20 | 21 | import java.util.concurrent.Callable; 22 | 23 | /** 24 | * Since Jedis now have UnifiedJedis which basically extended by cluster / single connections classes 25 | * can help us to have shared code. 26 | */ 27 | public abstract class RedisTask implements Runnable, Callable { 28 | 29 | protected final Summoner summoner; 30 | 31 | protected final RedisBungeeMode mode; 32 | 33 | @Override 34 | public V call() throws Exception { 35 | return this.execute(); 36 | } 37 | 38 | public RedisTask(AbstractRedisBungeeAPI api) { 39 | this.summoner = api.getSummoner(); 40 | this.mode = api.getMode(); 41 | } 42 | 43 | public RedisTask(RedisBungeePlugin plugin) { 44 | this.summoner = plugin.getSummoner(); 45 | this.mode = plugin.getRedisBungeeMode(); 46 | } 47 | 48 | public abstract V unifiedJedisTask(UnifiedJedis unifiedJedis); 49 | 50 | @Override 51 | public void run() { 52 | this.execute(); 53 | } 54 | 55 | public V execute() { 56 | // JedisCluster, JedisPooled in fact is just UnifiedJedis does not need new instance since its single instance anyway. 57 | if (mode == RedisBungeeMode.SINGLE) { 58 | JedisPooledSummoner jedisSummoner = (JedisPooledSummoner) summoner; 59 | return this.unifiedJedisTask(jedisSummoner.obtainResource()); 60 | } else if (mode == RedisBungeeMode.CLUSTER) { 61 | JedisClusterSummoner jedisClusterSummoner = (JedisClusterSummoner) summoner; 62 | return this.unifiedJedisTask(jedisClusterSummoner.obtainResource()); 63 | } 64 | return null; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/tasks/UUIDCleanupTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.tasks; 12 | 13 | import com.google.gson.Gson; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 15 | import com.imaginarycode.minecraft.redisbungee.api.util.uuid.CachedUUIDEntry; 16 | import redis.clients.jedis.UnifiedJedis; 17 | import redis.clients.jedis.exceptions.JedisException; 18 | 19 | import java.util.ArrayList; 20 | 21 | 22 | public class UUIDCleanupTask extends RedisTask{ 23 | 24 | private final Gson gson = new Gson(); 25 | private final RedisBungeePlugin plugin; 26 | 27 | public UUIDCleanupTask(RedisBungeePlugin plugin) { 28 | super(plugin); 29 | this.plugin = plugin; 30 | } 31 | 32 | // this code is inspired from https://github.com/minecrafter/redisbungeeclean 33 | @Override 34 | public Void unifiedJedisTask(UnifiedJedis unifiedJedis) { 35 | try { 36 | final long number = unifiedJedis.hlen("uuid-cache"); 37 | plugin.logInfo("Found {} entries", number); 38 | ArrayList fieldsToRemove = new ArrayList<>(); 39 | unifiedJedis.hgetAll("uuid-cache").forEach((field, data) -> { 40 | CachedUUIDEntry cachedUUIDEntry = gson.fromJson(data, CachedUUIDEntry.class); 41 | if (cachedUUIDEntry.expired()) { 42 | fieldsToRemove.add(field); 43 | } 44 | }); 45 | if (!fieldsToRemove.isEmpty()) { 46 | unifiedJedis.hdel("uuid-cache", fieldsToRemove.toArray(new String[0])); 47 | } 48 | plugin.logInfo("deleted {} entries", fieldsToRemove.size()); 49 | } catch (JedisException e) { 50 | plugin.logFatal("There was an error fetching information", e); 51 | } 52 | return null; 53 | } 54 | 55 | 56 | } -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/InitialUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.util; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 14 | import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask; 15 | import redis.clients.jedis.Protocol; 16 | import redis.clients.jedis.UnifiedJedis; 17 | 18 | 19 | public class InitialUtils { 20 | 21 | public static void checkRedisVersion(RedisBungeePlugin plugin) { 22 | new RedisTask(plugin) { 23 | @Override 24 | public Void unifiedJedisTask(UnifiedJedis unifiedJedis) { 25 | // This is more portable than INFO

26 | String info = new String((byte[]) unifiedJedis.sendCommand(Protocol.Command.INFO)); 27 | for (String s : info.split("\r\n")) { 28 | if (s.startsWith("redis_version:")) { 29 | String version = s.split(":")[1]; 30 | plugin.logInfo("Redis server version: " + version); 31 | if (!RedisUtil.isRedisVersionRight(version)) { 32 | plugin.logFatal("Your version of Redis (" + version + ") is not at least version " + RedisUtil.MAJOR_VERSION + "." + RedisUtil.MINOR_VERSION + " RedisBungee requires a newer version of Redis."); 33 | throw new RuntimeException("Unsupported Redis version detected"); 34 | } 35 | long uuidCacheSize = unifiedJedis.hlen("uuid-cache"); 36 | if (uuidCacheSize > 750000) { 37 | plugin.logInfo("Looks like you have a really big UUID cache! Run '/rb clean' to remove expired cache entries"); 38 | } 39 | break; 40 | } 41 | } 42 | return null; 43 | } 44 | }.execute(); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/RedisUtil.java: -------------------------------------------------------------------------------- 1 | package com.imaginarycode.minecraft.redisbungee.api.util; 2 | 3 | import com.google.common.annotations.VisibleForTesting; 4 | 5 | @VisibleForTesting 6 | public class RedisUtil { 7 | public final static int PROXY_TIMEOUT = 30; 8 | 9 | public static final int MAJOR_VERSION = 6; 10 | public static final int MINOR_VERSION = 2; 11 | 12 | public static boolean isRedisVersionRight(String redisVersion) { 13 | String[] args = redisVersion.split("\\."); 14 | if (args.length < 2) { 15 | return false; 16 | } 17 | int major = Integer.parseInt(args[0]); 18 | int minor = Integer.parseInt(args[1]); 19 | 20 | if (major > MAJOR_VERSION) return true; 21 | return major == MAJOR_VERSION && minor >= MINOR_VERSION; 22 | 23 | } 24 | 25 | // Ham1255: i am keeping this if some plugin uses this *IF* 26 | @Deprecated 27 | public static boolean canUseLua(String redisVersion) { 28 | // Need to use >=3 to use Lua optimizations. 29 | return isRedisVersionRight(redisVersion); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/serialize/MultiMapSerialization.java: -------------------------------------------------------------------------------- 1 | package com.imaginarycode.minecraft.redisbungee.api.util.serialize; 2 | 3 | import com.google.common.collect.Multimap; 4 | import com.google.common.collect.Multiset; 5 | import com.google.common.io.ByteArrayDataOutput; 6 | 7 | import java.util.Collection; 8 | import java.util.Map; 9 | 10 | public class MultiMapSerialization { 11 | 12 | public static void serializeMultiset(Multiset collection, ByteArrayDataOutput output) { 13 | output.writeInt(collection.elementSet().size()); 14 | for (Multiset.Entry entry : collection.entrySet()) { 15 | output.writeUTF(entry.getElement()); 16 | output.writeInt(entry.getCount()); 17 | } 18 | } 19 | 20 | @SuppressWarnings("SameParameterValue") 21 | public static void serializeMultimap(Multimap collection, boolean includeNames, ByteArrayDataOutput output) { 22 | output.writeInt(collection.keySet().size()); 23 | for (Map.Entry> entry : collection.asMap().entrySet()) { 24 | output.writeUTF(entry.getKey()); 25 | if (includeNames) { 26 | serializeCollection(entry.getValue(), output); 27 | } else { 28 | output.writeInt(entry.getValue().size()); 29 | } 30 | } 31 | } 32 | 33 | public static void serializeCollection(Collection collection, ByteArrayDataOutput output) { 34 | output.writeInt(collection.size()); 35 | for (Object o : collection) { 36 | output.writeUTF(o.toString()); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/uuid/CachedUUIDEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.util.uuid; 12 | 13 | import java.util.Calendar; 14 | import java.util.UUID; 15 | 16 | public class CachedUUIDEntry { 17 | private final String name; 18 | private final UUID uuid; 19 | private final Calendar expiry; 20 | 21 | public CachedUUIDEntry(String name, UUID uuid, Calendar expiry) { 22 | this.name = name; 23 | this.uuid = uuid; 24 | this.expiry = expiry; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public UUID getUuid() { 32 | return uuid; 33 | } 34 | 35 | public Calendar getExpiry() { 36 | return expiry; 37 | } 38 | 39 | public boolean expired() { 40 | return Calendar.getInstance().after(expiry); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/uuid/NameFetcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.util.uuid; 12 | 13 | import com.google.gson.Gson; 14 | import com.google.gson.JsonObject; 15 | import com.squareup.okhttp.OkHttpClient; 16 | import com.squareup.okhttp.Request; 17 | import com.squareup.okhttp.ResponseBody; 18 | 19 | import java.io.IOException; 20 | import java.util.Collections; 21 | import java.util.List; 22 | import java.util.UUID; 23 | 24 | public class NameFetcher { 25 | private static OkHttpClient httpClient; 26 | private static final Gson gson = new Gson(); 27 | 28 | public static void setHttpClient(OkHttpClient httpClient) { 29 | NameFetcher.httpClient = httpClient; 30 | } 31 | 32 | public static List nameHistoryFromUuid(UUID uuid) throws IOException { 33 | String name = getName(uuid); 34 | if (name == null) return Collections.emptyList(); 35 | return Collections.singletonList(name); 36 | } 37 | 38 | public static String getName(UUID uuid) throws IOException { 39 | String url = "https://playerdb.co/api/player/minecraft/" + uuid.toString(); 40 | Request request = new Request.Builder() 41 | .addHeader("User-Agent", "RedisBungee-ProxioDev") 42 | .url(url) 43 | .get() 44 | .build(); 45 | ResponseBody body = httpClient.newCall(request).execute().body(); 46 | String response = body.string(); 47 | body.close(); 48 | 49 | JsonObject json = gson.fromJson(response, JsonObject.class); 50 | if (!json.has("success") || !json.get("success").getAsBoolean()) return null; 51 | if (!json.has("data")) return null; 52 | JsonObject data = json.getAsJsonObject("data"); 53 | if (!data.has("player")) return null; 54 | JsonObject player = data.getAsJsonObject("player"); 55 | if (!player.has("username")) return null; 56 | 57 | return player.get("username").getAsString(); 58 | } 59 | } -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/uuid/UUIDFetcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.util.uuid; 12 | 13 | import com.google.common.collect.ImmutableList; 14 | import com.google.gson.Gson; 15 | import com.squareup.okhttp.*; 16 | 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.UUID; 21 | import java.util.concurrent.Callable; 22 | 23 | /* Credits to evilmidget38 for this class. I modified it to use Gson. */ 24 | public class UUIDFetcher implements Callable> { 25 | private static final double PROFILES_PER_REQUEST = 100; 26 | private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; 27 | private static final MediaType JSON = MediaType.parse("application/json"); 28 | private final List names; 29 | private final boolean rateLimiting; 30 | private static final Gson gson = new Gson(); 31 | 32 | 33 | public static void setHttpClient(OkHttpClient httpClient) { 34 | UUIDFetcher.httpClient = httpClient; 35 | } 36 | 37 | private static OkHttpClient httpClient; 38 | 39 | private UUIDFetcher(List names, boolean rateLimiting) { 40 | this.names = ImmutableList.copyOf(names); 41 | this.rateLimiting = rateLimiting; 42 | } 43 | 44 | public UUIDFetcher(List names) { 45 | this(names, true); 46 | } 47 | 48 | public static UUID getUUID(String id) { 49 | return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32)); 50 | } 51 | 52 | public Map call() throws Exception { 53 | Map uuidMap = new HashMap<>(); 54 | int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST); 55 | for (int i = 0; i < requests; i++) { 56 | String body = gson.toJson(names.subList(i * 100, Math.min((i + 1) * 100, names.size()))); 57 | Request request = new Request.Builder().url(PROFILE_URL).post(RequestBody.create(JSON, body)).build(); 58 | ResponseBody responseBody = httpClient.newCall(request).execute().body(); 59 | String response = responseBody.string(); 60 | responseBody.close(); 61 | Profile[] array = gson.fromJson(response, Profile[].class); 62 | for (Profile profile : array) { 63 | UUID uuid = UUIDFetcher.getUUID(profile.id); 64 | uuidMap.put(profile.name, uuid); 65 | } 66 | if (rateLimiting && i != requests - 1) { 67 | Thread.sleep(100L); 68 | } 69 | } 70 | return uuidMap; 71 | } 72 | 73 | private static class Profile { 74 | String id; 75 | String name; 76 | } 77 | } -------------------------------------------------------------------------------- /api/src/main/java/com/imaginarycode/minecraft/redisbungee/api/util/uuid/UUIDTranslator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.api.util.uuid; 12 | 13 | import com.google.common.base.Charsets; 14 | import com.google.common.collect.ImmutableMap; 15 | import com.google.gson.Gson; 16 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 17 | import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask; 18 | import org.checkerframework.checker.nullness.qual.NonNull; 19 | import redis.clients.jedis.UnifiedJedis; 20 | import redis.clients.jedis.exceptions.JedisException; 21 | 22 | import java.util.Calendar; 23 | import java.util.Collections; 24 | import java.util.Map; 25 | import java.util.UUID; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | import java.util.regex.Pattern; 28 | 29 | public final class UUIDTranslator { 30 | private static final Pattern UUID_PATTERN = Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); 31 | private static final Pattern MOJANGIAN_UUID_PATTERN = Pattern.compile("[a-fA-F0-9]{32}"); 32 | private final RedisBungeePlugin plugin; 33 | private final Map nameToUuidMap = new ConcurrentHashMap<>(128, 0.5f, 4); 34 | private final Map uuidToNameMap = new ConcurrentHashMap<>(128, 0.5f, 4); 35 | private static final Gson gson = new Gson(); 36 | 37 | public UUIDTranslator(RedisBungeePlugin plugin) { 38 | this.plugin = plugin; 39 | } 40 | 41 | private void addToMaps(String name, UUID uuid) { 42 | // This is why I like LocalDate... 43 | 44 | // Cache the entry for three days. 45 | Calendar calendar = Calendar.getInstance(); 46 | calendar.add(Calendar.DAY_OF_MONTH, 3); 47 | 48 | // Create the entry and populate the local maps 49 | CachedUUIDEntry entry = new CachedUUIDEntry(name, uuid, calendar); 50 | nameToUuidMap.put(name.toLowerCase(), entry); 51 | uuidToNameMap.put(uuid, entry); 52 | } 53 | 54 | public UUID getTranslatedUuid(@NonNull String player, boolean expensiveLookups) { 55 | // If the player is online, give them their UUID. 56 | // Remember, local data > remote data. 57 | if (plugin.getPlayer(player) != null) 58 | return plugin.getPlayerUUID(player); 59 | 60 | // Check if it exists in the map 61 | CachedUUIDEntry cachedUUIDEntry = nameToUuidMap.get(player.toLowerCase()); 62 | if (cachedUUIDEntry != null) { 63 | if (!cachedUUIDEntry.expired()) 64 | return cachedUUIDEntry.getUuid(); 65 | else 66 | nameToUuidMap.remove(player); 67 | } 68 | 69 | // Check if we can exit early 70 | if (UUID_PATTERN.matcher(player).find()) { 71 | return UUID.fromString(player); 72 | } 73 | 74 | if (MOJANGIAN_UUID_PATTERN.matcher(player).find()) { 75 | // Reconstruct the UUID 76 | return UUIDFetcher.getUUID(player); 77 | } 78 | 79 | // If we are in offline mode, UUID generation is simple. 80 | // We don't even have to cache the UUID, since this is easy to recalculate. 81 | if (!plugin.isOnlineMode()) { 82 | return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player).getBytes(Charsets.UTF_8)); 83 | } 84 | RedisTask redisTask = new RedisTask(plugin) { 85 | @Override 86 | public UUID unifiedJedisTask(UnifiedJedis unifiedJedis) { 87 | String stored = unifiedJedis.hget("uuid-cache", player.toLowerCase()); 88 | if (stored != null) { 89 | // Found an entry value. Deserialize it. 90 | CachedUUIDEntry entry = gson.fromJson(stored, CachedUUIDEntry.class); 91 | 92 | // Check for expiry: 93 | if (entry.expired()) { 94 | unifiedJedis.hdel("uuid-cache", player.toLowerCase()); 95 | // Doesn't hurt to also remove the UUID entry as well. 96 | unifiedJedis.hdel("uuid-cache", entry.getUuid().toString()); 97 | } else { 98 | nameToUuidMap.put(player.toLowerCase(), entry); 99 | uuidToNameMap.put(entry.getUuid(), entry); 100 | return entry.getUuid(); 101 | } 102 | } 103 | 104 | // That didn't work. Let's ask Mojang. 105 | if (!expensiveLookups || !plugin.isOnlineMode()) 106 | return null; 107 | 108 | Map uuidMap1; 109 | try { 110 | uuidMap1 = new UUIDFetcher(Collections.singletonList(player)).call(); 111 | } catch (Exception e) { 112 | plugin.logFatal("Unable to fetch UUID from Mojang for " + player); 113 | return null; 114 | } 115 | for (Map.Entry entry : uuidMap1.entrySet()) { 116 | if (entry.getKey().equalsIgnoreCase(player)) { 117 | persistInfo(entry.getKey(), entry.getValue(), unifiedJedis); 118 | return entry.getValue(); 119 | } 120 | } 121 | return null; 122 | } 123 | }; 124 | // Let's try Redis. 125 | try { 126 | return redisTask.execute(); 127 | } catch (JedisException e) { 128 | plugin.logFatal("Unable to fetch UUID for " + player); 129 | } 130 | 131 | return null; // Nope, game over! 132 | } 133 | 134 | public String getNameFromUuid(@NonNull UUID player, boolean expensiveLookups) { 135 | // If the player is online, give them their UUID. 136 | // Remember, local data > remote data. 137 | if (plugin.getPlayer(player) != null) 138 | return plugin.getPlayerName(player); 139 | 140 | // Check if it exists in the map 141 | CachedUUIDEntry cachedUUIDEntry = uuidToNameMap.get(player); 142 | if (cachedUUIDEntry != null) { 143 | if (!cachedUUIDEntry.expired()) 144 | return cachedUUIDEntry.getName(); 145 | else 146 | uuidToNameMap.remove(player); 147 | } 148 | 149 | RedisTask redisTask = new RedisTask(plugin) { 150 | @Override 151 | public String unifiedJedisTask(UnifiedJedis unifiedJedis) { 152 | String stored = unifiedJedis.hget("uuid-cache", player.toString()); 153 | if (stored != null) { 154 | // Found an entry value. Deserialize it. 155 | CachedUUIDEntry entry = gson.fromJson(stored, CachedUUIDEntry.class); 156 | 157 | // Check for expiry: 158 | if (entry.expired()) { 159 | unifiedJedis.hdel("uuid-cache", player.toString()); 160 | // Doesn't hurt to also remove the named entry as well. 161 | // TODO: Since UUIDs are fixed, we could look up the name and see if the UUID matches. 162 | unifiedJedis.hdel("uuid-cache", entry.getName()); 163 | } else { 164 | nameToUuidMap.put(entry.getName().toLowerCase(), entry); 165 | uuidToNameMap.put(player, entry); 166 | return entry.getName(); 167 | } 168 | } 169 | 170 | if (!expensiveLookups || !plugin.isOnlineMode()) 171 | return null; 172 | 173 | // That didn't work. Let's ask PlayerDB. 174 | String name; 175 | try { 176 | name = NameFetcher.getName(player); 177 | } catch (Exception e) { 178 | plugin.logFatal("Unable to fetch name from PlayerDB for " + player); 179 | return null; 180 | } 181 | 182 | if (name != null) { 183 | persistInfo(name, player, unifiedJedis); 184 | return name; 185 | } 186 | 187 | return null; 188 | } 189 | }; 190 | 191 | 192 | // Okay, it wasn't locally cached. Let's try Redis. 193 | try { 194 | return redisTask.execute(); 195 | } catch (JedisException e) { 196 | plugin.logFatal("Unable to fetch name for " + player); 197 | return null; 198 | } 199 | } 200 | 201 | public void persistInfo(String name, UUID uuid, UnifiedJedis unifiedJedis) { 202 | addToMaps(name, uuid); 203 | String json = gson.toJson(uuidToNameMap.get(uuid)); 204 | unifiedJedis.hset("uuid-cache", ImmutableMap.of(name.toLowerCase(), json, uuid.toString(), json)); 205 | } 206 | 207 | 208 | } 209 | -------------------------------------------------------------------------------- /api/src/main/resources/REDISBUNGEE_LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 1.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 4 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 5 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial code and documentation 12 | distributed under this Agreement, and 13 | b) in the case of each subsequent Contributor: 14 | i) changes to the Program, and 15 | ii) additions to the Program; 16 | 17 | where such changes and/or additions to the Program originate from and are 18 | distributed by that particular Contributor. A Contribution 'originates' 19 | from a Contributor if it was added to the Program by such Contributor 20 | itself or anyone acting on such Contributor's behalf. Contributions do not 21 | include additions to the Program which: (i) are separate modules of 22 | software distributed in conjunction with the Program under their own 23 | license agreement, and (ii) are not derivative works of the Program. 24 | 25 | "Contributor" means any person or entity that distributes the Program. 26 | 27 | "Licensed Patents" mean patent claims licensable by a Contributor which are 28 | necessarily infringed by the use or sale of its Contribution alone or when 29 | combined with the Program. 30 | 31 | "Program" means the Contributions distributed in accordance with this 32 | Agreement. 33 | 34 | "Recipient" means anyone who receives the Program under this Agreement, 35 | including all Contributors. 36 | 37 | 2. GRANT OF RIGHTS 38 | a) Subject to the terms of this Agreement, each Contributor hereby grants 39 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 40 | reproduce, prepare derivative works of, publicly display, publicly 41 | perform, distribute and sublicense the Contribution of such Contributor, 42 | if any, and such derivative works, in source code and object code form. 43 | b) Subject to the terms of this Agreement, each Contributor hereby grants 44 | Recipient a non-exclusive, worldwide, royalty-free patent license under 45 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 46 | transfer the Contribution of such Contributor, if any, in source code and 47 | object code form. This patent license shall apply to the combination of 48 | the Contribution and the Program if, at the time the Contribution is 49 | added by the Contributor, such addition of the Contribution causes such 50 | combination to be covered by the Licensed Patents. The patent license 51 | shall not apply to any other combinations which include the Contribution. 52 | No hardware per se is licensed hereunder. 53 | c) Recipient understands that although each Contributor grants the licenses 54 | to its Contributions set forth herein, no assurances are provided by any 55 | Contributor that the Program does not infringe the patent or other 56 | intellectual property rights of any other entity. Each Contributor 57 | disclaims any liability to Recipient for claims brought by any other 58 | entity based on infringement of intellectual property rights or 59 | otherwise. As a condition to exercising the rights and licenses granted 60 | hereunder, each Recipient hereby assumes sole responsibility to secure 61 | any other intellectual property rights needed, if any. For example, if a 62 | third party patent license is required to allow Recipient to distribute 63 | the Program, it is Recipient's responsibility to acquire that license 64 | before distributing the Program. 65 | d) Each Contributor represents that to its knowledge it has sufficient 66 | copyright rights in its Contribution, if any, to grant the copyright 67 | license set forth in this Agreement. 68 | 69 | 3. REQUIREMENTS 70 | 71 | A Contributor may choose to distribute the Program in object code form under 72 | its own license agreement, provided that: 73 | 74 | a) it complies with the terms and conditions of this Agreement; and 75 | b) its license agreement: 76 | i) effectively disclaims on behalf of all Contributors all warranties 77 | and conditions, express and implied, including warranties or 78 | conditions of title and non-infringement, and implied warranties or 79 | conditions of merchantability and fitness for a particular purpose; 80 | ii) effectively excludes on behalf of all Contributors all liability for 81 | damages, including direct, indirect, special, incidental and 82 | consequential damages, such as lost profits; 83 | iii) states that any provisions which differ from this Agreement are 84 | offered by that Contributor alone and not by any other party; and 85 | iv) states that source code for the Program is available from such 86 | Contributor, and informs licensees how to obtain it in a reasonable 87 | manner on or through a medium customarily used for software exchange. 88 | 89 | When the Program is made available in source code form: 90 | 91 | a) it must be made available under this Agreement; and 92 | b) a copy of this Agreement must be included with each copy of the Program. 93 | Contributors may not remove or alter any copyright notices contained 94 | within the Program. 95 | 96 | Each Contributor must identify itself as the originator of its Contribution, 97 | if 98 | any, in a manner that reasonably allows subsequent Recipients to identify the 99 | originator of the Contribution. 100 | 101 | 4. COMMERCIAL DISTRIBUTION 102 | 103 | Commercial distributors of software may accept certain responsibilities with 104 | respect to end users, business partners and the like. While this license is 105 | intended to facilitate the commercial use of the Program, the Contributor who 106 | includes the Program in a commercial product offering should do so in a manner 107 | which does not create potential liability for other Contributors. Therefore, 108 | if a Contributor includes the Program in a commercial product offering, such 109 | Contributor ("Commercial Contributor") hereby agrees to defend and indemnify 110 | every other Contributor ("Indemnified Contributor") against any losses, 111 | damages and costs (collectively "Losses") arising from claims, lawsuits and 112 | other legal actions brought by a third party against the Indemnified 113 | Contributor to the extent caused by the acts or omissions of such Commercial 114 | Contributor in connection with its distribution of the Program in a commercial 115 | product offering. The obligations in this section do not apply to any claims 116 | or Losses relating to any actual or alleged intellectual property 117 | infringement. In order to qualify, an Indemnified Contributor must: 118 | a) promptly notify the Commercial Contributor in writing of such claim, and 119 | b) allow the Commercial Contributor to control, and cooperate with the 120 | Commercial Contributor in, the defense and any related settlement 121 | negotiations. The Indemnified Contributor may participate in any such claim at 122 | its own expense. 123 | 124 | For example, a Contributor might include the Program in a commercial product 125 | offering, Product X. That Contributor is then a Commercial Contributor. If 126 | that Commercial Contributor then makes performance claims, or offers 127 | warranties related to Product X, those performance claims and warranties are 128 | such Commercial Contributor's responsibility alone. Under this section, the 129 | Commercial Contributor would have to defend claims against the other 130 | Contributors related to those performance claims and warranties, and if a 131 | court requires any other Contributor to pay any damages as a result, the 132 | Commercial Contributor must pay those damages. 133 | 134 | 5. NO WARRANTY 135 | 136 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN 137 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 138 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each 140 | Recipient is solely responsible for determining the appropriateness of using 141 | and distributing the Program and assumes all risks associated with its 142 | exercise of rights under this Agreement , including but not limited to the 143 | risks and costs of program errors, compliance with applicable laws, damage to 144 | or loss of data, programs or equipment, and unavailability or interruption of 145 | operations. 146 | 147 | 6. DISCLAIMER OF LIABILITY 148 | 149 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 150 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 151 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 152 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 153 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 154 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 155 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 156 | OF SUCH DAMAGES. 157 | 158 | 7. GENERAL 159 | 160 | If any provision of this Agreement is invalid or unenforceable under 161 | applicable law, it shall not affect the validity or enforceability of the 162 | remainder of the terms of this Agreement, and without further action by the 163 | parties hereto, such provision shall be reformed to the minimum extent 164 | necessary to make such provision valid and enforceable. 165 | 166 | If Recipient institutes patent litigation against any entity (including a 167 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 168 | (excluding combinations of the Program with other software or hardware) 169 | infringes such Recipient's patent(s), then such Recipient's rights granted 170 | under Section 2(b) shall terminate as of the date such litigation is filed. 171 | 172 | All Recipient's rights under this Agreement shall terminate if it fails to 173 | comply with any of the material terms or conditions of this Agreement and does 174 | not cure such failure in a reasonable period of time after becoming aware of 175 | such noncompliance. If all Recipient's rights under this Agreement terminate, 176 | Recipient agrees to cease use and distribution of the Program as soon as 177 | reasonably practicable. However, Recipient's obligations under this Agreement 178 | and any licenses granted by Recipient relating to the Program shall continue 179 | and survive. 180 | 181 | Everyone is permitted to copy and distribute copies of this Agreement, but in 182 | order to avoid inconsistency the Agreement is copyrighted and may only be 183 | modified in the following manner. The Agreement Steward reserves the right to 184 | publish new versions (including revisions) of this Agreement from time to 185 | time. No one other than the Agreement Steward has the right to modify this 186 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 187 | Eclipse Foundation may assign the responsibility to serve as the Agreement 188 | Steward to a suitable separate entity. Each new version of the Agreement will 189 | be given a distinguishing version number. The Program (including 190 | Contributions) may always be distributed subject to the version of the 191 | Agreement under which it was received. In addition, after a new version of the 192 | Agreement is published, Contributor may elect to distribute the Program 193 | (including its Contributions) under the new version. Except as expressly 194 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 195 | licenses to the intellectual property of any Contributor under this Agreement, 196 | whether expressly, by implication, estoppel or otherwise. All rights in the 197 | Program not expressly granted under this Agreement are reserved. 198 | 199 | This Agreement is governed by the laws of the State of New York and the 200 | intellectual property laws of the United States of America. No party to this 201 | Agreement will bring a legal action under this Agreement more than one year 202 | after the cause of action arose. Each party waives its rights to a jury trial in 203 | any resulting litigation. -------------------------------------------------------------------------------- /api/src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # RedisBungee configuration file. 2 | # Notice: 3 | # Redis 7.2.4 is last free and open source Redis version after license change 4 | # https://download.redis.io/releases/redis-7.2.4.tar.gz which you have to compile yourself, 5 | # unless your package manager still provide it. 6 | # Here is The alternatives 7 | # - 'ValKey' By linux foundation https://valkey.io/download/ 8 | # - 'KeyDB' by Snapchat inc https://docs.keydb.dev/docs/download/ 9 | 10 | 11 | # The 'Redis', 'ValKey', 'KeyDB' server you will use. 12 | # these settings are ignored when cluster mode is enabled. 13 | redis-server: 127.0.0.1 14 | redis-port: 6379 15 | 16 | # Cluster Mode 17 | # enabling this option will enable cluster mode. 18 | cluster-mode-enabled: false 19 | 20 | # FORMAT: 21 | # redis-cluster-servers: 22 | # - host: 127.0.0.1` 23 | # port: 2020 24 | # - host: 127.0.0.1 25 | # port: 2021 26 | # - host: 127.0.0.1 27 | # port: 2021 28 | 29 | # you can set single server and Jedis will automatically discover cluster nodes, 30 | # but might fail if this single redis node is down when Proxy startup, its recommended put the all the nodes 31 | redis-cluster-servers: 32 | - host: 127.0.0.1 33 | port: 6379 34 | 35 | # OPTIONAL: if your redis uses acl usernames set the username here. leave empty for no username. 36 | redis-username: "" 37 | 38 | # OPTIONAL but recommended: If your Redis server uses AUTH, set the required password. 39 | redis-password: "" 40 | 41 | # Maximum connections that will be maintained to the Redis server. 42 | # The default is 10. This setting should be left as-is unless you have some wildly 43 | # inefficient plugins or a lot of players. 44 | max-redis-connections: 10 45 | 46 | # since redis can support ssl by version 6 you can use SSL/TLS in redis bungee too! 47 | # but there is more configuration needed to work see https://github.com/ProxioDev/RedisBungee/issues/18 48 | # Keep note that SSL/TLS connections will decrease redis performance so use it when needed. 49 | useSSL: false 50 | 51 | # An identifier for this network, which helps to separate redisbungee instances on same redis instance. 52 | # You can use environment variable 'REDISBUNGEE_NETWORK_ID' to override 53 | network-id: "main" 54 | 55 | # An identifier for this BungeeCord / Velocity instance. Will randomly generate if leaving it blank. 56 | # You can set Environment variable 'REDISBUNGEE_PROXY_ID' to override 57 | proxy-id: "proxy-1" 58 | 59 | # since RedisBungee Internally now uses UnifiedJedis instead of Jedis, JedisPool. 60 | # which will break compatibility with old plugins that uses RedisBungee JedisPool 61 | # so to mitigate this issue, RedisBungee will create an JedisPool for compatibility reasons. 62 | # disabled by default 63 | # Automatically disabled when cluster mode is enabled 64 | enable-jedis-pool-compatibility: false 65 | 66 | # max connections for the compatibility pool 67 | compatibility-max-connections: 3 68 | 69 | # restore old login behavior before 0.9.0 update 70 | # enabled by default 71 | # when true: when player login and there is old player with same uuid it will get disconnected as result and new player will log in 72 | # when false: when a player login but login will fail because old player is still connected. 73 | kick-when-online: true 74 | 75 | # enabled by default 76 | # this option tells RedisBungee handle motd and set online count, when motd is requested 77 | # you can disable this when you want to handle motd yourself, use RedisBungee api to get total players when needed :) 78 | handle-motd: true 79 | 80 | # A list of IP addresses for which RedisBungee will not modify the response for, useful for automatic 81 | # restart scripts. 82 | # Automatically disabled if handle-motd is disabled. 83 | exempt-ip-addresses: [] 84 | 85 | # disabled by default 86 | # RedisBungee will attempt to connect player to last server that was stored. 87 | reconnect-to-last-server: false 88 | 89 | # For redis bungee legacy commands 90 | # either can be run using '/rbl glist' for example 91 | # or if 'install' is set to true '/glist' can be used. 92 | # 'install' also overrides the proxy installed commands 93 | # 94 | # In legacy commands each command got it own permissions since they had it own permission pre new command system, 95 | # so it's also applied to subcommands in '/rbl'. 96 | commands: 97 | # Permission redisbungee.legacy.use 98 | redisbungee-legacy: 99 | enabled: false 100 | subcommands: 101 | # Permission redisbungee.command.glist 102 | glist: 103 | enabled: false 104 | install: false 105 | # Permission redisbungee.command.find 106 | find: 107 | enabled: false 108 | install: false 109 | # Permission redisbungee.command.lastseen 110 | lastseen: 111 | enabled: false 112 | install: false 113 | # Permission redisbungee.command.ip 114 | ip: 115 | enabled: false 116 | install: false 117 | # Permission redisbungee.command.pproxy 118 | pproxy: 119 | enabled: false 120 | install: false 121 | # Permission redisbungee.command.sendtoall 122 | sendtoall: 123 | enabled: false 124 | install: false 125 | # Permission redisbungee.command.serverid 126 | serverid: 127 | enabled: false 128 | install: false 129 | # Permission redisbungee.command.serverids 130 | serverids: 131 | enabled: false 132 | install: false 133 | # Permission redisbungee.command.plist 134 | plist: 135 | enabled: false 136 | install: false 137 | # Permission redisbungee.command.use 138 | redisbungee: 139 | enabled: true 140 | 141 | # Config version DO NOT CHANGE!!!! 142 | config-version: 2 143 | -------------------------------------------------------------------------------- /api/src/main/resources/lang.yml: -------------------------------------------------------------------------------- 1 | # this config file is for messages / Languages 2 | # use MiniMessage format https://docs.advntr.dev/minimessage/format.html 3 | # for colors etc... Legacy chat color is not supported. 4 | 5 | # Language codes used in minecraft from the minecraft wiki 6 | # example: en-us for american english and ar-sa for arabic 7 | 8 | # all codes can be obtained from link below 9 | # from the colum Locale Code -> In-game 10 | # NOTE: minecraft wiki shows languages like this `en_us` in config it should be `en-us` 11 | # https://minecraft.wiki/w/Language 12 | 13 | # example: 14 | # lets assume we want to add arabic language. 15 | # messages: 16 | # logged-in-other-location: 17 | # en-us: "You logged in from another location!" 18 | # ar-sa: "لقد اتصلت من مكان اخر" 19 | 20 | 21 | # RedisBungee Prefix if ever used. 22 | prefix: "[RedisBungee]" 23 | 24 | # en-us is american English, Which is the default language used when a language for a message isn't defined. 25 | # Warning: IF THE set default locale wasn't defined in the config for all messages, plugin will not load. 26 | # set the Default locale 27 | default-locale: en-us 28 | 29 | # send language based on client sent settings 30 | # if you don't have languages configured For client Language 31 | # it will default to language that has been set above 32 | # NOTE: due minecraft protocol not sending player settings during login, 33 | # some of the messages like logged-in-other-location will 34 | # skip translation and use default locale that has been set in default-locale. 35 | use-client-locale: true 36 | 37 | # messages that are used during login, and connecting to Last server 38 | messages: 39 | logged-in-other-location: 40 | en-us: "You logged in from another location!" 41 | pt-br: "Você está logado em outra localização!" 42 | already-logged-in: 43 | en-us: "You are already logged in!" 44 | pt-br: "Você já está logado!" 45 | server-not-found: 46 | # placeholder displays server name in the message. 47 | en-us: "unable to connect you to the last server, because server was not found." 48 | pt-br: "falha ao conectar você ao último servidor, porque o servidor não foi encontrado." 49 | server-connecting: 50 | # placeholder displays server name in the message. 51 | en-us: "Connecting you to ..." 52 | pt-br: "Conectando você a ..." 53 | 54 | # DO NOT CHANGE!!!!! 55 | config-version: 1 56 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxioDev/ValioBungee/f27d54beb8b0bcd10a71eb17dff6179ca0cabb84/build.gradle.kts -------------------------------------------------------------------------------- /commands/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | } 4 | 5 | dependencies { 6 | implementation(project(":RedisBungee-API")) 7 | implementation(libs.acf.core) 8 | } 9 | 10 | description = "RedisBungee common commands" 11 | 12 | 13 | tasks { 14 | compileJava { 15 | options.encoding = Charsets.UTF_8.name() 16 | options.release.set(17) 17 | } 18 | javadoc { 19 | options.encoding = Charsets.UTF_8.name() 20 | } 21 | processResources { 22 | filteringCharset = Charsets.UTF_8.name() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/CommandLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands; 12 | 13 | import co.aikar.commands.CommandManager; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 15 | 16 | import com.imaginarycode.minecraft.redisbungee.commands.legacy.LegacyRedisBungeeCommands; 17 | 18 | public class CommandLoader { 19 | 20 | public static void initCommands(CommandManager commandManager, RedisBungeePlugin plugin) { 21 | var commandsConfiguration = plugin.configuration().commandsConfiguration(); 22 | if (commandsConfiguration.redisbungeeEnabled()) { 23 | commandManager.registerCommand(new CommandRedisBungee(plugin)); 24 | } 25 | if (commandsConfiguration.redisbungeeLegacyEnabled()) { 26 | commandManager.registerCommand(new LegacyRedisBungeeCommands(commandManager,plugin)); 27 | } 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/CommandRedisBungee.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.RegisteredCommand; 15 | import co.aikar.commands.annotation.*; 16 | import com.google.common.primitives.Ints; 17 | import com.imaginarycode.minecraft.redisbungee.Constants; 18 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 19 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 20 | import com.imaginarycode.minecraft.redisbungee.commands.utils.StopperUUIDCleanupTask; 21 | import net.kyori.adventure.text.Component; 22 | import net.kyori.adventure.text.TextComponent; 23 | import net.kyori.adventure.text.event.ClickEvent; 24 | import net.kyori.adventure.text.event.HoverEvent; 25 | import net.kyori.adventure.text.format.NamedTextColor; 26 | import net.kyori.adventure.text.minimessage.MiniMessage; 27 | import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | import java.util.Map; 32 | 33 | @CommandAlias("rb|redisbungee") 34 | @CommandPermission("redisbungee.command.use") 35 | @Description("Main command") 36 | public class CommandRedisBungee extends AdventureBaseCommand { 37 | 38 | private final RedisBungeePlugin plugin; 39 | 40 | public CommandRedisBungee(RedisBungeePlugin plugin) { 41 | this.plugin = plugin; 42 | } 43 | 44 | @Default 45 | @Subcommand("info|version|git") 46 | @Description("information about current redisbungee build") 47 | public void info(CommandIssuer issuer) { 48 | final String message = """ 49 | This proxy is running RedisBungee Limework's fork 50 | ======================================== 51 | RedisBungee version: 52 | Commit: 53 | ======================================== 54 | run /rb help for more commands"""; 55 | sendMessage( 56 | issuer, 57 | MiniMessage.miniMessage() 58 | .deserialize( 59 | message, 60 | Placeholder.component("version", Component.text(Constants.VERSION)), 61 | Placeholder.component( 62 | "commit", 63 | Component.text(Constants.GIT_COMMIT.substring(0, 8)) 64 | .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, Constants.getGithubCommitLink())) 65 | .hoverEvent(HoverEvent.showText(Component.text("Click me to open: " + Constants.getGithubCommitLink()))) 66 | ))); 67 | } 68 | // ......: ...... 69 | @HelpCommand 70 | @Description("shows the help page") 71 | public void help(CommandIssuer issuer) { 72 | final String barFormat = "========================================"; 73 | final String commandFormat = "/rb : "; 74 | 75 | TextComponent.Builder message = Component.text(); 76 | message.append(MiniMessage.miniMessage().deserialize(barFormat)); 77 | 78 | getSubCommands().forEach((subCommand, registeredCommand) -> { 79 | String[] split = registeredCommand.getCommand().split(" "); 80 | if (split.length > 1 && subCommand.equalsIgnoreCase(split[1])) { 81 | message.appendNewline().append(MiniMessage.miniMessage().deserialize(commandFormat, Placeholder.component("sub-command", Component.text(subCommand)), 82 | Placeholder.component("description", MiniMessage.miniMessage().deserialize(registeredCommand.getHelpText())) 83 | )); 84 | } 85 | }); 86 | 87 | message.appendNewline().append(MiniMessage.miniMessage().deserialize(barFormat)); 88 | 89 | sendMessage(issuer, message.build()); 90 | } 91 | @Subcommand("clean") 92 | @Description("cleans up the uuid cache WARNING... command above could cause performance issues") 93 | @Private 94 | public void cleanUp(CommandIssuer issuer) { 95 | if (StopperUUIDCleanupTask.isRunning) { 96 | sendMessage(issuer, 97 | Component.text("cleanup is currently running!").color(NamedTextColor.RED)); 98 | return; 99 | } 100 | sendMessage(issuer, 101 | Component.text("cleanup is Starting, you should see the output status in the proxy console").color(NamedTextColor.GOLD)); 102 | plugin.executeAsync(new StopperUUIDCleanupTask(plugin)); 103 | } 104 | 105 | 106 | 107 | private List> subListProxies(List> data, final int currentPage, final int pageSize) { 108 | return data.subList(((currentPage * pageSize) - pageSize), Ints.constrainToRange(currentPage * pageSize, 0, data.size())); 109 | 110 | } 111 | @Subcommand("show") 112 | @Description("Shows proxies in this network") 113 | public void showProxies(CommandIssuer issuer, String[] args) { 114 | final String closer = "========================================"; 115 | final String pageTop = "Page: / Network ID: Proxies online: "; 116 | final String proxy = " : online"; 117 | final String proxyHere = " (#) "; 118 | final String nextPage = ">>>>>"; 119 | final String previousPage = "<<<<< "; 120 | final String pageInvalid = "invalid page"; 121 | final String noProxies = "No proxies were found :("; 122 | 123 | final int pageSize = 16; 124 | 125 | int currentPage; 126 | if (args.length > 0) { 127 | try { 128 | currentPage = Integer.parseInt(args[0]); 129 | if (currentPage < 1) currentPage = 1; 130 | } catch (NumberFormatException e) { 131 | sendMessage(issuer, MiniMessage.miniMessage().deserialize(pageInvalid)); 132 | return; 133 | } 134 | } else currentPage = 1; 135 | 136 | var data = new ArrayList<>(plugin.proxyDataManager().eachProxyCount().entrySet()); 137 | // there is no way this runs because there is always an heartbeat. 138 | // if not could be some shenanigans done by devs :P 139 | if (data.isEmpty()) { 140 | sendMessage(issuer, MiniMessage.miniMessage().deserialize(noProxies)); 141 | return; 142 | } 143 | // compute the total pages 144 | int maxPages = (int) Math.ceil(data.size() / (double) pageSize); 145 | if (currentPage > maxPages) currentPage = maxPages; 146 | var subList = subListProxies(data, currentPage, pageSize); 147 | TextComponent.Builder builder = Component.text(); 148 | builder.append(MiniMessage.miniMessage().deserialize(closer)).appendNewline(); 149 | builder.append(MiniMessage.miniMessage().deserialize(pageTop, 150 | Placeholder.component("current", Component.text(currentPage)), 151 | Placeholder.component("max", Component.text(maxPages)), 152 | Placeholder.component("network", Component.text(plugin.proxyDataManager().networkId())), 153 | Placeholder.component("proxies", Component.text(data.size())) 154 | 155 | 156 | )).appendNewline(); 157 | int left = pageSize; 158 | for (Map.Entry entrySet : subList) { 159 | builder.append(MiniMessage.miniMessage().deserialize(proxy, 160 | 161 | Placeholder.component("proxy", Component.text(entrySet.getKey())), 162 | Placeholder.component("here", Component.text(plugin.proxyDataManager().proxyId().equals(entrySet.getKey()) ? proxyHere : "")), 163 | Placeholder.component("players", Component.text(entrySet.getValue())) 164 | 165 | )).appendNewline(); 166 | left--; 167 | } 168 | while(left > 0) { 169 | builder.appendNewline(); 170 | left--; 171 | } 172 | if (currentPage > 1) { 173 | builder.append(MiniMessage.miniMessage().deserialize(previousPage) 174 | .color(NamedTextColor.WHITE).clickEvent(ClickEvent.runCommand("/rb show " + (currentPage - 1)))); 175 | } else { 176 | builder.append(MiniMessage.miniMessage().deserialize(previousPage).color(NamedTextColor.GRAY)); 177 | } 178 | if (subList.size() == pageSize && !subListProxies(data, currentPage + 1, pageSize).isEmpty()) { 179 | builder.append(MiniMessage.miniMessage().deserialize(nextPage) 180 | .color(NamedTextColor.WHITE).clickEvent(ClickEvent.runCommand("/rb show " + (currentPage + 1)))); 181 | } else { 182 | builder.append(MiniMessage.miniMessage().deserialize(nextPage).color(NamedTextColor.GRAY)); 183 | } 184 | builder.appendNewline(); 185 | builder.append(MiniMessage.miniMessage().deserialize(closer)); 186 | sendMessage(issuer, builder.build()); 187 | 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandFind.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("find|rfind") 20 | @CommandPermission("redisbungee.command.find") 21 | public class CommandFind extends AdventureBaseCommand { 22 | 23 | private final LegacyRedisBungeeCommands rootCommand; 24 | 25 | public CommandFind(LegacyRedisBungeeCommands rootCommand) { 26 | this.rootCommand = rootCommand; 27 | } 28 | 29 | @Default 30 | public void find(CommandIssuer issuer, String[] args) { 31 | rootCommand.find(issuer, args); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandGList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("glist|rglist") 20 | @CommandPermission("redisbungee.command.glist") 21 | public class CommandGList extends AdventureBaseCommand { 22 | 23 | private final LegacyRedisBungeeCommands rootCommand; 24 | 25 | public CommandGList(LegacyRedisBungeeCommands rootCommand) { 26 | this.rootCommand = rootCommand; 27 | } 28 | 29 | @Default 30 | public void gList(CommandIssuer issuer, String[] args) { 31 | rootCommand.gList(issuer, args); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandIp.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("ip|playerip|rip|rplayerip") 20 | @CommandPermission("redisbungee.command.ip") 21 | public class CommandIp extends AdventureBaseCommand { 22 | 23 | private final LegacyRedisBungeeCommands rootCommand; 24 | 25 | public CommandIp(LegacyRedisBungeeCommands rootCommand) { 26 | this.rootCommand = rootCommand; 27 | } 28 | 29 | 30 | @Default 31 | public void ip(CommandIssuer issuer, String[] args) { 32 | this.rootCommand.ip(issuer, args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandLastSeen.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("lastseen|rlastseend") 20 | @CommandPermission("redisbungee.command.lastseen") 21 | public class CommandLastSeen extends AdventureBaseCommand { 22 | 23 | 24 | private final LegacyRedisBungeeCommands rootCommand; 25 | 26 | public CommandLastSeen(LegacyRedisBungeeCommands rootCommand) { 27 | this.rootCommand = rootCommand; 28 | } 29 | 30 | @Default 31 | public void lastSeen(CommandIssuer issuer, String[] args) { 32 | this.rootCommand.lastSeen(issuer,args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandPProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("pproxy") 20 | @CommandPermission("redisbungee.command.pproxy") 21 | public class CommandPProxy extends AdventureBaseCommand { 22 | private final LegacyRedisBungeeCommands rootCommand; 23 | 24 | public CommandPProxy(LegacyRedisBungeeCommands rootCommand) { 25 | this.rootCommand = rootCommand; 26 | } 27 | 28 | @Default 29 | public void playerProxy(CommandIssuer issuer, String[] args) { 30 | this.rootCommand.playerProxy(issuer,args); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandPlist.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("plist|rplist") 20 | @CommandPermission("redisbungee.command.plist") 21 | public class CommandPlist extends AdventureBaseCommand { 22 | 23 | 24 | private final LegacyRedisBungeeCommands rootCommand; 25 | 26 | public CommandPlist(LegacyRedisBungeeCommands rootCommand) { 27 | this.rootCommand = rootCommand; 28 | } 29 | 30 | @Default 31 | public void playerList(CommandIssuer issuer, String[] args) { 32 | this.rootCommand.playerList(issuer, args); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandSendToAll.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("sendtoall|rsendtoall") 20 | @CommandPermission("redisbungee.command.sendtoall") 21 | public class CommandSendToAll extends AdventureBaseCommand { 22 | 23 | 24 | private final LegacyRedisBungeeCommands rootCommand; 25 | 26 | public CommandSendToAll(LegacyRedisBungeeCommands rootCommand) { 27 | this.rootCommand = rootCommand; 28 | } 29 | @Default 30 | public void sendToAll(CommandIssuer issuer, String[] args) { 31 | this.rootCommand.sendToAll(issuer, args); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandServerId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("serverid|rserverid") 20 | @CommandPermission("redisbungee.command.serverid") 21 | public class CommandServerId extends AdventureBaseCommand { 22 | 23 | 24 | private final LegacyRedisBungeeCommands rootCommand; 25 | 26 | public CommandServerId(LegacyRedisBungeeCommands rootCommand) { 27 | this.rootCommand = rootCommand; 28 | } 29 | @Default 30 | public void serverId(CommandIssuer issuer) { 31 | this.rootCommand.serverId(issuer); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/legacy/CommandServerIds.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.legacy; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.annotation.CommandAlias; 15 | import co.aikar.commands.annotation.CommandPermission; 16 | import co.aikar.commands.annotation.Default; 17 | import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand; 18 | 19 | @CommandAlias("serverids|rserverids") 20 | @CommandPermission("redisbungee.command.serverids") 21 | public class CommandServerIds extends AdventureBaseCommand { 22 | 23 | 24 | private final LegacyRedisBungeeCommands rootCommand; 25 | 26 | public CommandServerIds(LegacyRedisBungeeCommands rootCommand) { 27 | this.rootCommand = rootCommand; 28 | } 29 | 30 | @Default 31 | public void serverIds(CommandIssuer issuer) { 32 | this.rootCommand.serverIds(issuer); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/utils/AdventureBaseCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.utils; 12 | 13 | import co.aikar.commands.BaseCommand; 14 | import co.aikar.commands.CommandIssuer; 15 | import net.kyori.adventure.text.Component; 16 | 17 | /** 18 | * this just dumb class that wraps the adventure stuff into base command 19 | */ 20 | public abstract class AdventureBaseCommand extends BaseCommand { 21 | 22 | public static void sendMessage(CommandIssuer issuer, Component component) { 23 | CommandPlatformHelper.getPlatformHelper().sendMessage(issuer, component); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/utils/CommandPlatformHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.commands.utils; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 15 | import net.kyori.adventure.text.Component; 16 | 17 | 18 | public abstract class CommandPlatformHelper { 19 | 20 | private static CommandPlatformHelper SINGLETON; 21 | 22 | public abstract void sendMessage(CommandIssuer issuer, Component component); 23 | 24 | public static void init(CommandPlatformHelper platformHelper) { 25 | if (SINGLETON != null) { 26 | throw new IllegalStateException("tried to re init Platform Helper"); 27 | } 28 | SINGLETON = platformHelper; 29 | } 30 | 31 | 32 | public static CommandPlatformHelper getPlatformHelper() { 33 | return SINGLETON; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /commands/src/main/java/com/imaginarycode/minecraft/redisbungee/commands/utils/StopperUUIDCleanupTask.java: -------------------------------------------------------------------------------- 1 | package com.imaginarycode.minecraft.redisbungee.commands.utils; 2 | 3 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 4 | import com.imaginarycode.minecraft.redisbungee.api.tasks.UUIDCleanupTask; 5 | import redis.clients.jedis.UnifiedJedis; 6 | 7 | public class StopperUUIDCleanupTask extends UUIDCleanupTask { 8 | 9 | public static boolean isRunning = false; 10 | 11 | public StopperUUIDCleanupTask(RedisBungeePlugin plugin) { 12 | super(plugin); 13 | } 14 | 15 | 16 | @Override 17 | public Void unifiedJedisTask(UnifiedJedis unifiedJedis) { 18 | isRunning = true; 19 | try { 20 | super.unifiedJedisTask(unifiedJedis); 21 | } catch (Exception ignored) {} 22 | isRunning = false; 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /copyright_print.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-present RedisBungee contributors 2 | 3 | All rights reserved. This program and the accompanying materials 4 | are made available under the terms of the Eclipse Public License v1.0 5 | which accompanies this distribution, and is available at 6 | 7 | http://www.eclipse.org/legal/epl-v10.html -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=com.imaginarycode.minecraft 2 | version=0.12.6 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProxioDev/ValioBungee/f27d54beb8b0bcd10a71eb17dff6179ca0cabb84/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-8.10.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original 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 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /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 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 3 | -------------------------------------------------------------------------------- /proxies/bungeecord/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.github.johnrengelman.shadow") version "8.1.1" 4 | id("xyz.jpenilla.run-waterfall") version "2.0.0" 5 | } 6 | 7 | dependencies { 8 | implementation(project(":RedisBungee-Bungee")) 9 | compileOnly(libs.platform.bungeecord) { 10 | exclude("com.google.guava", "guava") 11 | exclude("com.google.code.gson", "gson") 12 | exclude("net.kyori","adventure-api") 13 | } 14 | implementation(libs.adventure.platforms.bungeecord) 15 | implementation(libs.adventure.gson) 16 | implementation(libs.acf.bungeecord) 17 | implementation(project(":RedisBungee-Commands")) 18 | } 19 | 20 | description = "RedisBungee Bungeecord implementation" 21 | 22 | java { 23 | withSourcesJar() 24 | } 25 | 26 | tasks { 27 | runWaterfall { 28 | waterfallVersion("1.20") 29 | environment["REDISBUNGEE_PROXY_ID"] = "bungeecord-1" 30 | environment["REDISBUNGEE_NETWORK_ID"] = "dev" 31 | } 32 | compileJava { 33 | options.encoding = Charsets.UTF_8.name() 34 | options.release.set(17) 35 | } 36 | processResources { 37 | filteringCharset = Charsets.UTF_8.name() 38 | filesMatching("plugin.yml") { 39 | filter { 40 | it.replace("*{redisbungee.version}*", "$version", false) 41 | } 42 | } 43 | 44 | } 45 | shadowJar { 46 | relocate("redis.clients.jedis", "com.imaginarycode.minecraft.redisbungee.internal.jedis") 47 | relocate("redis.clients.util", "com.imaginarycode.minecraft.redisbungee.internal.jedisutil") 48 | relocate("org.apache.commons.pool", "com.imaginarycode.minecraft.redisbungee.internal.commonspool") 49 | relocate("com.squareup.okhttp", "com.imaginarycode.minecraft.redisbungee.internal.okhttp") 50 | relocate("okio", "com.imaginarycode.minecraft.redisbungee.internal.okio") 51 | relocate("org.json", "com.imaginarycode.minecraft.redisbungee.internal.json") 52 | // configurate shade 53 | relocate("ninja.leaping.configurate", "com.imaginarycode.minecraft.redisbungee.internal.configurate") 54 | relocate("org.yaml", "com.imaginarycode.minecraft.redisbungee.internal.yml") 55 | relocate("com.google.common", "com.imaginarycode.minecraft.redisbungee.internal.com.google.common") 56 | relocate("com.google.errorprone", "com.imaginarycode.minecraft.redisbungee.internal.com.google.errorprone") 57 | relocate("com.google.gson", "com.imaginarycode.minecraft.redisbungee.internal.com.google.gson") 58 | relocate("com.google.j2objc", "com.imaginarycode.minecraft.redisbungee.internal.com.google.j2objc") 59 | relocate("com.google.thirdparty", "com.imaginarycode.minecraft.redisbungee.internal.com.google.thirdparty") 60 | relocate("com.github.benmanes.caffeine", "com.imaginarycode.minecraft.redisbungee.internal.caffeine") 61 | // acf shade 62 | relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands") 63 | // adventure :/ 64 | relocate("net.kyori", "com.imaginarycode.minecraft.redisbungee.internal.net.kyori") 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /proxies/bungeecord/bungeecord-api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | `maven-publish` 4 | } 5 | 6 | dependencies { 7 | api(project(":RedisBungee-API")) 8 | compileOnly(libs.platform.bungeecord) { 9 | exclude("com.google.guava", "guava") 10 | exclude("com.google.code.gson", "gson") 11 | exclude("net.kyori","adventure-api") 12 | } 13 | } 14 | 15 | description = "RedisBungee Bungeecord API" 16 | 17 | java { 18 | withJavadocJar() 19 | withSourcesJar() 20 | } 21 | 22 | 23 | tasks { 24 | withType { 25 | dependsOn(project(":RedisBungee-API").getTasksByName("javadoc", false)) 26 | val options = options as StandardJavadocDocletOptions 27 | options.use() 28 | options.isDocFilesSubDirs = true 29 | options.links( 30 | "https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/", // bungeecord api 31 | ) 32 | val apiDocs = File(rootProject.projectDir, "api/build/docs/javadoc") 33 | options.linksOffline("https://ci.limework.net/ValioBungee/api/build/docs/javadoc", apiDocs.path) 34 | } 35 | compileJava { 36 | options.encoding = Charsets.UTF_8.name() 37 | options.release.set(17) 38 | } 39 | javadoc { 40 | options.encoding = Charsets.UTF_8.name() 41 | } 42 | } 43 | 44 | publishing { 45 | publications { 46 | create("maven") { 47 | from(components["java"]) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /proxies/bungeecord/bungeecord-api/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeAPI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 14 | import net.md_5.bungee.api.config.ServerInfo; 15 | import net.md_5.bungee.api.plugin.Plugin; 16 | import org.checkerframework.checker.nullness.qual.NonNull; 17 | import org.checkerframework.checker.nullness.qual.Nullable; 18 | 19 | import java.util.UUID; 20 | 21 | /** 22 | * This platform class exposes some internal RedisBungee functions. You obtain an instance of this object by invoking {@link RedisBungeeAPI#getRedisBungeeApi()} 23 | * or somehow you got the Plugin instance by you can call the api using {@link RedisBungeePlugin#getAbstractRedisBungeeApi()}. 24 | * 25 | * @author tuxed 26 | * @since 0.2.3 | updated 0.8.0 27 | */ 28 | public class RedisBungeeAPI extends AbstractRedisBungeeAPI { 29 | 30 | private static RedisBungeeAPI redisBungeeApi; 31 | 32 | public RedisBungeeAPI(RedisBungeePlugin plugin) { 33 | super(plugin); 34 | if (redisBungeeApi == null) { 35 | redisBungeeApi = this; 36 | } 37 | } 38 | 39 | /** 40 | * Get the server where the specified player is playing. This function also deals with the case of local players 41 | * as well, and will return local information on them. 42 | * 43 | * @param player a player uuid 44 | * @return {@link ServerInfo} Can be null if proxy can't find it. 45 | * @see #getServerNameFor(UUID) 46 | */ 47 | @Nullable 48 | public final ServerInfo getServerFor(@NonNull UUID player) { 49 | String serverName = this.getServerNameFor(player); 50 | if (serverName == null) return null; 51 | return ((Plugin) this.plugin).getProxy().getServerInfo(serverName); 52 | } 53 | 54 | /** 55 | * Api instance 56 | * 57 | * @return the API instance. 58 | * @since 0.6.5 59 | */ 60 | public static RedisBungeeAPI getRedisBungeeApi() { 61 | return redisBungeeApi; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /proxies/bungeecord/bungeecord-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PlayerChangedServerNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerChangedServerNetworkEvent; 14 | import net.md_5.bungee.api.plugin.Event; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * This event is sent when a player connects to a new server. RedisBungee sends the event only when 20 | * the proxy the player has been connected to is different than the local proxy. 21 | *

22 | * This event corresponds to {@link net.md_5.bungee.api.event.ServerConnectedEvent}, and is fired 23 | * asynchronously. 24 | * 25 | * @since 0.3.4 26 | */ 27 | public class PlayerChangedServerNetworkEvent extends Event implements IPlayerChangedServerNetworkEvent { 28 | private final UUID uuid; 29 | private final String previousServer; 30 | private final String server; 31 | 32 | public PlayerChangedServerNetworkEvent(UUID uuid, String previousServer, String server) { 33 | this.uuid = uuid; 34 | this.previousServer = previousServer; 35 | this.server = server; 36 | } 37 | 38 | @Override 39 | public UUID getUuid() { 40 | return uuid; 41 | } 42 | 43 | @Override 44 | public String getServer() { 45 | return server; 46 | } 47 | 48 | @Override 49 | public String getPreviousServer() { 50 | return previousServer; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /proxies/bungeecord/bungeecord-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PlayerJoinedNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent; 14 | import net.md_5.bungee.api.plugin.Event; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * This event is sent when a player joins the network. RedisBungee sends the event only when 20 | * the proxy the player has been connected to is different than the local proxy. 21 | *

22 | * This event corresponds to {@link net.md_5.bungee.api.event.PostLoginEvent}, and is fired 23 | * asynchronously. 24 | * 25 | * @since 0.3.4 26 | */ 27 | public class PlayerJoinedNetworkEvent extends Event implements IPlayerJoinedNetworkEvent { 28 | private final UUID uuid; 29 | 30 | public PlayerJoinedNetworkEvent(UUID uuid) { 31 | this.uuid = uuid; 32 | } 33 | 34 | @Override 35 | public UUID getUuid() { 36 | return uuid; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /proxies/bungeecord/bungeecord-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PlayerLeftNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent; 14 | import net.md_5.bungee.api.plugin.Event; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * This event is sent when a player disconnects. RedisBungee sends the event only when 20 | * the proxy the player has been connected to is different than the local proxy. 21 | *

22 | * This event corresponds to {@link net.md_5.bungee.api.event.PlayerDisconnectEvent}, and is fired 23 | * asynchronously. 24 | * 25 | * @since 0.3.4 26 | */ 27 | public class PlayerLeftNetworkEvent extends Event implements IPlayerLeftNetworkEvent { 28 | private final UUID uuid; 29 | 30 | public PlayerLeftNetworkEvent(UUID uuid) { 31 | this.uuid = uuid; 32 | } 33 | 34 | @Override 35 | public UUID getUuid() { 36 | return uuid; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /proxies/bungeecord/bungeecord-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PubSubMessageEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent; 14 | import net.md_5.bungee.api.plugin.Event; 15 | 16 | /** 17 | * This event is posted when a PubSub message is received. 18 | *

19 | * Warning: This event is fired in a separate thread! 20 | * 21 | * @since 0.2.6 22 | */ 23 | 24 | public class PubSubMessageEvent extends Event implements IPubSubMessageEvent { 25 | private final String channel; 26 | private final String message; 27 | 28 | public PubSubMessageEvent(String channel, String message) { 29 | this.channel = channel; 30 | this.message = message; 31 | } 32 | 33 | @Override 34 | public String getChannel() { 35 | return channel; 36 | } 37 | 38 | @Override 39 | public String getMessage() { 40 | return message; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /proxies/bungeecord/src/main/java/com/imaginarycode/minecraft/redisbungee/BungeeCommandPlatformHelper.java: -------------------------------------------------------------------------------- 1 | package com.imaginarycode.minecraft.redisbungee; 2 | 3 | import co.aikar.commands.BungeeCommandIssuer; 4 | import co.aikar.commands.CommandIssuer; 5 | import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper; 6 | import net.kyori.adventure.text.Component; 7 | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; 8 | 9 | public class BungeeCommandPlatformHelper extends CommandPlatformHelper { 10 | 11 | @Override 12 | public void sendMessage(CommandIssuer issuer, Component component) { 13 | BungeeCommandIssuer bIssuer = (BungeeCommandIssuer) issuer; 14 | bIssuer.getIssuer().sendMessage(BungeeComponentSerializer.get().serialize(component)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /proxies/bungeecord/src/main/java/com/imaginarycode/minecraft/redisbungee/BungeePlayerDataManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 15 | import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent; 16 | import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent; 17 | import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; 18 | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; 19 | import net.md_5.bungee.api.connection.ProxiedPlayer; 20 | import net.md_5.bungee.api.event.LoginEvent; 21 | import net.md_5.bungee.api.event.PlayerDisconnectEvent; 22 | import net.md_5.bungee.api.event.PostLoginEvent; 23 | import net.md_5.bungee.api.event.ServerConnectedEvent; 24 | import net.md_5.bungee.api.plugin.Listener; 25 | import net.md_5.bungee.api.plugin.Plugin; 26 | import net.md_5.bungee.event.EventHandler; 27 | 28 | import java.util.concurrent.TimeUnit; 29 | 30 | 31 | public class BungeePlayerDataManager extends PlayerDataManager implements Listener { 32 | 33 | public BungeePlayerDataManager(RedisBungeePlugin plugin) { 34 | super(plugin); 35 | } 36 | 37 | @EventHandler 38 | public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) { 39 | super.handleNetworkPlayerServerChange(event); 40 | } 41 | 42 | @EventHandler 43 | public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) { 44 | super.handleNetworkPlayerQuit(event); 45 | } 46 | 47 | @EventHandler 48 | public void onPubSubMessageEvent(PubSubMessageEvent event) { 49 | super.handlePubSubMessageEvent(event); 50 | } 51 | 52 | @EventHandler 53 | public void onServerConnectedEvent(ServerConnectedEvent event) { 54 | final String currentServer = event.getServer().getInfo().getName(); 55 | final String oldServer = event.getPlayer().getServer() == null ? null : event.getPlayer().getServer().getInfo().getName(); 56 | super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer); 57 | } 58 | 59 | @EventHandler 60 | public void onLoginEvent(LoginEvent event) { 61 | event.registerIntent((Plugin) plugin); 62 | // check if online 63 | if (getLastOnline(event.getConnection().getUniqueId()) == 0) { 64 | // because something can go wrong and proxy somehow does not update player data correctly on shutdown 65 | // we have to check proxy if it has the player 66 | String proxyId = getProxyFor(event.getConnection().getUniqueId()); 67 | if (proxyId == null || !plugin.proxyDataManager().isPlayerTrulyOnProxy(proxyId, event.getConnection().getUniqueId())) { 68 | event.completeIntent((Plugin) plugin); 69 | } else { 70 | if (plugin.configuration().kickWhenOnline()) { 71 | kickPlayer(event.getConnection().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation()); 72 | // wait 3 seconds before releasing the event 73 | plugin.executeAsyncAfter(() -> event.completeIntent((Plugin) plugin), TimeUnit.SECONDS, 3); 74 | } else { 75 | event.setCancelled(true); 76 | event.setCancelReason(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().alreadyLoggedIn())); 77 | event.completeIntent((Plugin) plugin); 78 | } 79 | } 80 | } else { 81 | event.completeIntent((Plugin) plugin); 82 | } 83 | 84 | } 85 | 86 | @EventHandler 87 | public void onLoginEvent(PostLoginEvent event) { 88 | super.addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getName(), event.getPlayer().getAddress().getAddress()); 89 | } 90 | 91 | @EventHandler 92 | public void onDisconnectEvent(PlayerDisconnectEvent event) { 93 | super.removePlayer(event.getPlayer().getUniqueId()); 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /proxies/bungeecord/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeCommandSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import net.md_5.bungee.api.CommandSender; 14 | import net.md_5.bungee.api.chat.BaseComponent; 15 | 16 | import java.util.Collection; 17 | import java.util.Collections; 18 | 19 | public class RedisBungeeCommandSender implements CommandSender { 20 | private static final RedisBungeeCommandSender singleton; 21 | 22 | static { 23 | singleton = new RedisBungeeCommandSender(); 24 | } 25 | 26 | public static RedisBungeeCommandSender getSingleton() { 27 | return singleton; 28 | } 29 | 30 | @Override 31 | public String getName() { 32 | return "RedisBungee"; 33 | } 34 | 35 | @Override 36 | public void sendMessage(String s) { 37 | 38 | } 39 | 40 | @Override 41 | public void sendMessages(String... strings) { 42 | 43 | } 44 | 45 | @Override 46 | public void sendMessage(BaseComponent... baseComponents) { 47 | 48 | } 49 | 50 | @Override 51 | public void sendMessage(BaseComponent baseComponent) { 52 | 53 | } 54 | 55 | @Override 56 | public Collection getGroups() { 57 | return null; 58 | } 59 | 60 | @Override 61 | public void addGroups(String... strings) { 62 | 63 | } 64 | 65 | @Override 66 | public void removeGroups(String... strings) { 67 | 68 | } 69 | 70 | @Override 71 | public boolean hasPermission(String s) { 72 | return true; 73 | } 74 | 75 | @Override 76 | public void setPermission(String s, boolean b) { 77 | 78 | } 79 | 80 | @Override 81 | public Collection getPermissions() { 82 | return Collections.emptySet(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /proxies/bungeecord/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import com.google.common.base.Joiner; 14 | import com.google.common.collect.HashMultimap; 15 | import com.google.common.collect.Multimap; 16 | import com.google.common.io.ByteArrayDataInput; 17 | import com.google.common.io.ByteArrayDataOutput; 18 | import com.google.common.io.ByteStreams; 19 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 20 | import net.kyori.adventure.text.Component; 21 | import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; 22 | import net.md_5.bungee.api.AbstractReconnectHandler; 23 | import net.md_5.bungee.api.ProxyServer; 24 | import net.md_5.bungee.api.config.ServerInfo; 25 | import net.md_5.bungee.api.connection.ProxiedPlayer; 26 | import net.md_5.bungee.api.connection.Server; 27 | import net.md_5.bungee.api.event.PluginMessageEvent; 28 | import net.md_5.bungee.api.event.ProxyPingEvent; 29 | import net.md_5.bungee.api.event.ServerConnectEvent; 30 | import net.md_5.bungee.api.plugin.Listener; 31 | import net.md_5.bungee.event.EventHandler; 32 | 33 | import java.util.*; 34 | 35 | import static com.imaginarycode.minecraft.redisbungee.api.util.serialize.MultiMapSerialization.*; 36 | 37 | public class RedisBungeeListener implements Listener { 38 | 39 | private final RedisBungeePlugin plugin; 40 | 41 | public RedisBungeeListener(RedisBungeePlugin plugin) { 42 | this.plugin = plugin; 43 | } 44 | 45 | @EventHandler 46 | public void onPing(ProxyPingEvent event) { 47 | if (!plugin.configuration().handleMotd()) return; 48 | if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getAddress().getAddress())) return; 49 | ServerInfo forced = AbstractReconnectHandler.getForcedHost(event.getConnection()); 50 | 51 | if (forced != null && event.getConnection().getListener().isPingPassthrough()) return; 52 | event.getResponse().getPlayers().setOnline(plugin.proxyDataManager().totalNetworkPlayers()); 53 | } 54 | 55 | @SuppressWarnings("UnstableApiUsage") 56 | @EventHandler 57 | public void onPluginMessage(PluginMessageEvent event) { 58 | if ((event.getTag().equals("legacy:redisbungee") || event.getTag().equals("RedisBungee")) && event.getSender() instanceof Server) { 59 | final String currentChannel = event.getTag(); 60 | final byte[] data = Arrays.copyOf(event.getData(), event.getData().length); 61 | plugin.executeAsync(() -> { 62 | ByteArrayDataInput in = ByteStreams.newDataInput(data); 63 | 64 | String subchannel = in.readUTF(); 65 | ByteArrayDataOutput out = ByteStreams.newDataOutput(); 66 | String type; 67 | 68 | switch (subchannel) { 69 | case "PlayerList" -> { 70 | out.writeUTF("PlayerList"); 71 | Set original = Collections.emptySet(); 72 | type = in.readUTF(); 73 | if (type.equals("ALL")) { 74 | out.writeUTF("ALL"); 75 | original = plugin.proxyDataManager().networkPlayers(); 76 | } else { 77 | out.writeUTF(type); 78 | try { 79 | original = plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type); 80 | } catch (IllegalArgumentException ignored) { 81 | } 82 | } 83 | Set players = new HashSet<>(); 84 | for (UUID uuid : original) 85 | players.add(plugin.getUuidTranslator().getNameFromUuid(uuid, false)); 86 | out.writeUTF(Joiner.on(',').join(players)); 87 | } 88 | case "PlayerCount" -> { 89 | out.writeUTF("PlayerCount"); 90 | type = in.readUTF(); 91 | if (type.equals("ALL")) { 92 | out.writeUTF("ALL"); 93 | out.writeInt(plugin.proxyDataManager().totalNetworkPlayers()); 94 | } else { 95 | out.writeUTF(type); 96 | try { 97 | out.writeInt(plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type).size()); 98 | } catch (IllegalArgumentException e) { 99 | out.writeInt(0); 100 | } 101 | } 102 | } 103 | case "LastOnline" -> { 104 | String user = in.readUTF(); 105 | out.writeUTF("LastOnline"); 106 | out.writeUTF(user); 107 | out.writeLong(plugin.getAbstractRedisBungeeApi().getLastOnline(Objects.requireNonNull(plugin.getUuidTranslator().getTranslatedUuid(user, true)))); 108 | } 109 | case "ServerPlayers" -> { 110 | String type1 = in.readUTF(); 111 | out.writeUTF("ServerPlayers"); 112 | Multimap multimap = plugin.getAbstractRedisBungeeApi().getServerToPlayers(); 113 | boolean includesUsers; 114 | switch (type1) { 115 | case "COUNT" -> includesUsers = false; 116 | case "PLAYERS" -> includesUsers = true; 117 | default -> { 118 | // TODO: Should I raise an error? 119 | return; 120 | } 121 | } 122 | out.writeUTF(type1); 123 | if (includesUsers) { 124 | Multimap human = HashMultimap.create(); 125 | for (Map.Entry entry : multimap.entries()) { 126 | human.put(entry.getKey(), plugin.getUuidTranslator().getNameFromUuid(entry.getValue(), false)); 127 | } 128 | serializeMultimap(human, true, out); 129 | } else { 130 | serializeMultiset(multimap.keys(), out); 131 | } 132 | } 133 | case "Proxy" -> { 134 | out.writeUTF("Proxy"); 135 | out.writeUTF(plugin.configuration().getProxyId()); 136 | } 137 | case "PlayerProxy" -> { 138 | String username = in.readUTF(); 139 | out.writeUTF("PlayerProxy"); 140 | out.writeUTF(username); 141 | out.writeUTF(plugin.getAbstractRedisBungeeApi().getProxy(Objects.requireNonNull(plugin.getUuidTranslator().getTranslatedUuid(username, true)))); 142 | } 143 | default -> { 144 | return; 145 | } 146 | } 147 | 148 | ((Server) event.getSender()).sendData(currentChannel, out.toByteArray()); 149 | }); 150 | } 151 | } 152 | 153 | @EventHandler 154 | public void onServerConnectEvent(ServerConnectEvent event) { 155 | if (event.getReason() == ServerConnectEvent.Reason.JOIN_PROXY && plugin.configuration().handleReconnectToLastServer()) { 156 | ProxiedPlayer player = event.getPlayer(); 157 | String lastServer = plugin.playerDataManager().getLastServerFor(event.getPlayer().getUniqueId()); 158 | if (lastServer == null) return; 159 | player.sendMessage(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().serverConnecting(player.getLocale(), lastServer))); 160 | ServerInfo serverInfo = ProxyServer.getInstance().getServerInfo(lastServer); 161 | if (serverInfo == null) { 162 | player.sendMessage(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().serverNotFound(player.getLocale(), lastServer))); 163 | return; 164 | } 165 | event.setTarget(serverInfo); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /proxies/bungeecord/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: RedisBungee 2 | main: com.imaginarycode.minecraft.redisbungee.RedisBungee 3 | version: *{redisbungee.version}* 4 | author: "astei, ProxioDev" 5 | # This is used so that we can automatically override default BungeeCord behavior. 6 | softDepends: ["cmd_find", "cmd_list"] -------------------------------------------------------------------------------- /proxies/velocity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | id("com.github.johnrengelman.shadow") version "8.1.1" 4 | id("xyz.jpenilla.run-velocity") version "2.0.0" 5 | } 6 | 7 | dependencies { 8 | implementation(project(":RedisBungee-Velocity")) 9 | compileOnly(libs.platform.velocity) 10 | annotationProcessor(libs.platform.velocity) 11 | implementation(project(":RedisBungee-Commands")) 12 | implementation(libs.acf.velocity) 13 | 14 | } 15 | 16 | description = "RedisBungee Velocity implementation" 17 | 18 | java { 19 | withSourcesJar() 20 | } 21 | 22 | tasks { 23 | runVelocity { 24 | velocityVersion("3.3.0-SNAPSHOT") 25 | environment["REDISBUNGEE_PROXY_ID"] = "velocity-1" 26 | environment["REDISBUNGEE_NETWORK_ID"] = "dev" 27 | } 28 | compileJava { 29 | options.encoding = Charsets.UTF_8.name() 30 | options.release.set(17) 31 | } 32 | processResources { 33 | filteringCharset = Charsets.UTF_8.name() 34 | } 35 | shadowJar { 36 | relocate("redis.clients.jedis", "com.imaginarycode.minecraft.redisbungee.internal.jedis") 37 | relocate("redis.clients.util", "com.imaginarycode.minecraft.redisbungee.internal.jedisutil") 38 | relocate("org.apache.commons.pool", "com.imaginarycode.minecraft.redisbungee.internal.commonspool") 39 | relocate("com.squareup.okhttp", "com.imaginarycode.minecraft.redisbungee.internal.okhttp") 40 | relocate("okio", "com.imaginarycode.minecraft.redisbungee.internal.okio") 41 | relocate("org.json", "com.imaginarycode.minecraft.redisbungee.internal.json") 42 | relocate("com.github.benmanes.caffeine", "com.imaginarycode.minecraft.redisbungee.internal.caffeine") 43 | // acf shade 44 | relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands") 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /proxies/velocity/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeCommandSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | 14 | import com.velocitypowered.api.command.CommandSource; 15 | import com.velocitypowered.api.permission.Tristate; 16 | import net.kyori.adventure.permission.PermissionChecker; 17 | 18 | public class RedisBungeeCommandSource implements CommandSource { 19 | private static final RedisBungeeCommandSource singleton; 20 | private final PermissionChecker permissionChecker = PermissionChecker.always(net.kyori.adventure.util.TriState.TRUE); 21 | 22 | static { 23 | singleton = new RedisBungeeCommandSource(); 24 | } 25 | 26 | public static RedisBungeeCommandSource getSingleton() { 27 | return singleton; 28 | } 29 | 30 | 31 | @Override 32 | public boolean hasPermission(String permission) { 33 | return this.permissionChecker.test(permission); 34 | } 35 | 36 | @Override 37 | public Tristate getPermissionValue(String s) { 38 | return Tristate.TRUE; 39 | } 40 | 41 | @Override 42 | public PermissionChecker getPermissionChecker() { 43 | return this.permissionChecker; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /proxies/velocity/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import com.google.common.base.Joiner; 14 | import com.google.common.collect.HashMultimap; 15 | import com.google.common.collect.Multimap; 16 | import com.google.common.io.ByteArrayDataInput; 17 | import com.google.common.io.ByteArrayDataOutput; 18 | import com.google.common.io.ByteStreams; 19 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 20 | import com.velocitypowered.api.event.PostOrder; 21 | import com.velocitypowered.api.event.Subscribe; 22 | import com.velocitypowered.api.event.connection.PluginMessageEvent; 23 | import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent; 24 | import com.velocitypowered.api.event.proxy.ProxyPingEvent; 25 | import com.velocitypowered.api.proxy.Player; 26 | import com.velocitypowered.api.proxy.ServerConnection; 27 | import com.velocitypowered.api.proxy.server.RegisteredServer; 28 | import com.velocitypowered.api.proxy.server.ServerPing; 29 | 30 | import java.util.*; 31 | import java.util.stream.Collectors; 32 | 33 | import static com.imaginarycode.minecraft.redisbungee.api.util.serialize.MultiMapSerialization.serializeMultimap; 34 | import static com.imaginarycode.minecraft.redisbungee.api.util.serialize.MultiMapSerialization.serializeMultiset; 35 | 36 | public class RedisBungeeListener { 37 | 38 | private final RedisBungeePlugin plugin; 39 | 40 | public RedisBungeeListener(RedisBungeePlugin plugin) { 41 | this.plugin = plugin; 42 | } 43 | 44 | @Subscribe(order = PostOrder.LAST) // some plugins changes it online players so we need to be executed as last 45 | public void onPing(ProxyPingEvent event) { 46 | if (!plugin.configuration().handleMotd()) return; 47 | if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getRemoteAddress().getAddress())) return; 48 | 49 | ServerPing.Builder ping = event.getPing().asBuilder(); 50 | ping.onlinePlayers(plugin.proxyDataManager().totalNetworkPlayers()); 51 | event.setPing(ping.build()); 52 | } 53 | 54 | @Subscribe 55 | public void onPluginMessage(PluginMessageEvent event) { 56 | if (!(event.getSource() instanceof ServerConnection) || !RedisBungeeVelocityPlugin.IDENTIFIERS.contains(event.getIdentifier())) { 57 | return; 58 | } 59 | 60 | event.setResult(PluginMessageEvent.ForwardResult.handled()); 61 | 62 | plugin.executeAsync(() -> { 63 | ByteArrayDataInput in = event.dataAsDataStream(); 64 | 65 | String subchannel = in.readUTF(); 66 | ByteArrayDataOutput out = ByteStreams.newDataOutput(); 67 | String type; 68 | 69 | switch (subchannel) { 70 | case "PlayerList" -> { 71 | out.writeUTF("PlayerList"); 72 | Set original = Collections.emptySet(); 73 | type = in.readUTF(); 74 | if (type.equals("ALL")) { 75 | out.writeUTF("ALL"); 76 | original = plugin.proxyDataManager().networkPlayers(); 77 | } else { 78 | out.writeUTF(type); 79 | try { 80 | original = plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type); 81 | } catch (IllegalArgumentException ignored) { 82 | } 83 | } 84 | Set players = original.stream() 85 | .map(uuid -> plugin.getUuidTranslator().getNameFromUuid(uuid, false)) 86 | .collect(Collectors.toSet()); 87 | out.writeUTF(Joiner.on(',').join(players)); 88 | } 89 | case "PlayerCount" -> { 90 | out.writeUTF("PlayerCount"); 91 | type = in.readUTF(); 92 | if (type.equals("ALL")) { 93 | out.writeUTF("ALL"); 94 | out.writeInt(plugin.proxyDataManager().totalNetworkPlayers()); 95 | } else { 96 | out.writeUTF(type); 97 | try { 98 | out.writeInt(plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type).size()); 99 | } catch (IllegalArgumentException e) { 100 | out.writeInt(0); 101 | } 102 | } 103 | } 104 | case "LastOnline" -> { 105 | String user = in.readUTF(); 106 | out.writeUTF("LastOnline"); 107 | out.writeUTF(user); 108 | out.writeLong(plugin.getAbstractRedisBungeeApi().getLastOnline(Objects.requireNonNull(plugin.getUuidTranslator().getTranslatedUuid(user, true)))); 109 | } 110 | case "ServerPlayers" -> { 111 | String type1 = in.readUTF(); 112 | out.writeUTF("ServerPlayers"); 113 | Multimap multimap = plugin.getAbstractRedisBungeeApi().getServerToPlayers(); 114 | boolean includesUsers; 115 | switch (type1) { 116 | case "COUNT" -> includesUsers = false; 117 | case "PLAYERS" -> includesUsers = true; 118 | default -> { 119 | // TODO: Should I raise an error? 120 | return; 121 | } 122 | } 123 | out.writeUTF(type1); 124 | if (includesUsers) { 125 | Multimap human = HashMultimap.create(); 126 | for (Map.Entry entry : multimap.entries()) { 127 | human.put(entry.getKey(), plugin.getUuidTranslator().getNameFromUuid(entry.getValue(), false)); 128 | } 129 | serializeMultimap(human, true, out); 130 | } else { 131 | serializeMultiset(multimap.keys(), out); 132 | } 133 | } 134 | case "Proxy" -> { 135 | out.writeUTF("Proxy"); 136 | out.writeUTF(plugin.configuration().getProxyId()); 137 | } 138 | case "PlayerProxy" -> { 139 | String username = in.readUTF(); 140 | out.writeUTF("PlayerProxy"); 141 | out.writeUTF(username); 142 | out.writeUTF(plugin.getAbstractRedisBungeeApi().getProxy(Objects.requireNonNull(plugin.getUuidTranslator().getTranslatedUuid(username, true)))); 143 | } 144 | default -> { 145 | return; 146 | } 147 | } 148 | try { 149 | // ServerConnection throws IllegalStateException when connection dies somehow so just ignore :/ 150 | ((ServerConnection) event.getSource()).sendPluginMessage(event.getIdentifier(), out.toByteArray()); 151 | } catch (IllegalStateException ignored) { 152 | } 153 | }); 154 | 155 | } 156 | 157 | @Subscribe 158 | public void onPlayerChooseInitialServerEvent(PlayerChooseInitialServerEvent event) { 159 | if (plugin.configuration().handleReconnectToLastServer()) { 160 | Player player = event.getPlayer(); 161 | String lastServer = plugin.playerDataManager().getLastServerFor(player.getUniqueId()); 162 | if (lastServer == null) return; 163 | player.sendMessage(plugin.langConfiguration().messages().serverConnecting(player.getPlayerSettings().getLocale(), lastServer)); 164 | Optional optionalRegisteredServer = ((RedisBungeeVelocityPlugin) plugin).getProxy().getServer(lastServer); 165 | if (optionalRegisteredServer.isEmpty()) { 166 | player.sendMessage(plugin.langConfiguration().messages().serverNotFound(player.getPlayerSettings().getLocale(), lastServer)); 167 | return; 168 | } 169 | RegisteredServer server = optionalRegisteredServer.get(); 170 | event.setInitialServer(server); 171 | } 172 | } 173 | 174 | 175 | } 176 | -------------------------------------------------------------------------------- /proxies/velocity/src/main/java/com/imaginarycode/minecraft/redisbungee/VelocityCommandPlatformHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import co.aikar.commands.CommandIssuer; 14 | import co.aikar.commands.VelocityCommandIssuer; 15 | import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper; 16 | import net.kyori.adventure.text.Component; 17 | 18 | public class VelocityCommandPlatformHelper extends CommandPlatformHelper { 19 | 20 | @Override 21 | public void sendMessage(CommandIssuer issuer, Component component) { 22 | VelocityCommandIssuer vIssuer = (VelocityCommandIssuer) issuer; 23 | vIssuer.getIssuer().sendMessage(component); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /proxies/velocity/src/main/java/com/imaginarycode/minecraft/redisbungee/VelocityPlayerDataManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager; 14 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 15 | import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration; 16 | import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent; 17 | import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent; 18 | import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; 19 | import com.velocitypowered.api.event.Continuation; 20 | import com.velocitypowered.api.event.ResultedEvent; 21 | import com.velocitypowered.api.event.Subscribe; 22 | import com.velocitypowered.api.event.connection.DisconnectEvent; 23 | import com.velocitypowered.api.event.connection.LoginEvent; 24 | import com.velocitypowered.api.event.connection.PostLoginEvent; 25 | import com.velocitypowered.api.event.player.ServerConnectedEvent; 26 | import com.velocitypowered.api.proxy.Player; 27 | import net.kyori.adventure.text.Component; 28 | 29 | import java.util.concurrent.TimeUnit; 30 | 31 | public class VelocityPlayerDataManager extends PlayerDataManager { 32 | public VelocityPlayerDataManager(RedisBungeePlugin plugin) { 33 | super(plugin); 34 | } 35 | 36 | @Subscribe 37 | public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) { 38 | handleNetworkPlayerServerChange(event); 39 | } 40 | 41 | @Subscribe 42 | public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) { 43 | handleNetworkPlayerQuit(event); 44 | } 45 | 46 | @Subscribe 47 | public void onPubSubMessageEvent(PubSubMessageEvent event) { 48 | handlePubSubMessageEvent(event); 49 | } 50 | 51 | @Subscribe 52 | public void onServerConnectedEvent(ServerConnectedEvent event) { 53 | final String currentServer = event.getServer().getServerInfo().getName(); 54 | final String oldServer; 55 | if (event.getPreviousServer().isPresent()) { 56 | oldServer = event.getPreviousServer().get().getServerInfo().getName(); 57 | } else { 58 | oldServer = null; 59 | } 60 | super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer); 61 | } 62 | 63 | @Subscribe 64 | public void onLoginEvent(LoginEvent event, Continuation continuation) { 65 | // check if online 66 | if (getLastOnline(event.getPlayer().getUniqueId()) == 0) { 67 | // because something can go wrong and proxy somehow does not update player data correctly on shutdown 68 | // we have to check proxy if it has the player 69 | String proxyId = getProxyFor(event.getPlayer().getUniqueId()); 70 | if (proxyId == null || !plugin.proxyDataManager().isPlayerTrulyOnProxy(proxyId, event.getPlayer().getUniqueId())) { 71 | continuation.resume(); 72 | } else { 73 | if (plugin.configuration().kickWhenOnline()) { 74 | kickPlayer(event.getPlayer().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation()); 75 | // wait 3 seconds before releasing the event 76 | plugin.executeAsyncAfter(continuation::resume, TimeUnit.SECONDS, 3); 77 | } else { 78 | event.setResult(ResultedEvent.ComponentResult.denied(plugin.langConfiguration().messages().alreadyLoggedIn())); 79 | continuation.resume(); 80 | } 81 | } 82 | } else { 83 | continuation.resume(); 84 | } 85 | } 86 | 87 | @Subscribe 88 | public void onLoginEvent(PostLoginEvent event) { 89 | addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getUsername(), event.getPlayer().getRemoteAddress().getAddress()); 90 | } 91 | 92 | @Subscribe 93 | public void onDisconnectEvent(DisconnectEvent event) { 94 | if (event.getLoginStatus() == DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN || event.getLoginStatus() == DisconnectEvent.LoginStatus.PRE_SERVER_JOIN) { 95 | removePlayer(event.getPlayer().getUniqueId()); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | `maven-publish` 4 | } 5 | 6 | dependencies { 7 | api(project(":RedisBungee-API")) { 8 | // Since velocity already includes guava / configurate exlude them 9 | exclude("com.google.guava", "guava") 10 | exclude("com.google.code.gson", "gson") 11 | exclude("org.spongepowered", "configurate-yaml") 12 | // exclude also adventure api 13 | exclude("net.kyori", "adventure-api") 14 | exclude("net.kyori", "adventure-text-serializer-gson") 15 | exclude("net.kyori", "adventure-text-serializer-legacy") 16 | exclude("net.kyori", "adventure-text-serializer-plain") 17 | exclude("net.kyori", "adventure-text-minimessage") 18 | } 19 | compileOnly(libs.platform.velocity) 20 | 21 | } 22 | 23 | description = "RedisBungee Velocity API" 24 | 25 | java { 26 | withJavadocJar() 27 | withSourcesJar() 28 | } 29 | 30 | tasks { 31 | withType { 32 | dependsOn(project(":RedisBungee-API").getTasksByName("javadoc", false)) 33 | val options = options as StandardJavadocDocletOptions 34 | options.use() 35 | options.isDocFilesSubDirs = true 36 | options.links( 37 | "https://jd.papermc.io/velocity/3.0.0/", // velocity api 38 | ) 39 | val apiDocs = File(rootProject.projectDir, "api/build/docs/javadoc") 40 | options.linksOffline("https://ci.limework.net/ValioBungee/api/build/docs/javadoc", apiDocs.path) 41 | } 42 | compileJava { 43 | options.encoding = Charsets.UTF_8.name() 44 | options.release.set(17) 45 | } 46 | javadoc { 47 | options.encoding = Charsets.UTF_8.name() 48 | } 49 | processResources { 50 | filteringCharset = Charsets.UTF_8.name() 51 | } 52 | 53 | } 54 | 55 | publishing { 56 | publications { 57 | create("maven") { 58 | from(components["java"]) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeAPI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee; 12 | 13 | import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 14 | import com.velocitypowered.api.proxy.server.RegisteredServer; 15 | import com.velocitypowered.api.proxy.server.ServerInfo; 16 | import org.checkerframework.checker.nullness.qual.NonNull; 17 | import org.checkerframework.checker.nullness.qual.Nullable; 18 | 19 | import java.util.UUID; 20 | 21 | /** 22 | * This platform class exposes some internal RedisBungee functions. You obtain an instance of this object by invoking {@link RedisBungeeAPI#getRedisBungeeApi()} 23 | * or somehow you got the Plugin instance by you can call the api using {@link RedisBungeePlugin#getAbstractRedisBungeeApi()}. 24 | * 25 | * @author tuxed 26 | * @since 0.2.3 27 | */ 28 | public class RedisBungeeAPI extends AbstractRedisBungeeAPI { 29 | 30 | private static RedisBungeeAPI redisBungeeApi; 31 | 32 | public RedisBungeeAPI(RedisBungeePlugin plugin) { 33 | super(plugin); 34 | if (redisBungeeApi == null) { 35 | redisBungeeApi = this; 36 | } 37 | 38 | } 39 | 40 | /** 41 | * Get the server where the specified player is playing. This function also deals with the case of local players 42 | * as well, and will return local information on them. 43 | * 44 | * @param player a player uuid 45 | * @return {@link ServerInfo} Can be null if proxy can't find it. 46 | * @see #getServerNameFor(UUID) 47 | */ 48 | @Nullable 49 | public final ServerInfo getServerFor(@NonNull UUID player) { 50 | String serverName = this.getServerNameFor(player); 51 | if (serverName == null) return null; 52 | return ((ServerObjectFetcher) this.plugin).getProxy().getServer(serverName).map((RegisteredServer::getServerInfo)).orElse(null); 53 | } 54 | 55 | /** 56 | * Api instance 57 | * 58 | * @return the API instance. 59 | * @since 0.6.5 60 | */ 61 | public static RedisBungeeAPI getRedisBungeeApi() { 62 | return redisBungeeApi; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/src/main/java/com/imaginarycode/minecraft/redisbungee/ServerObjectFetcher.java: -------------------------------------------------------------------------------- 1 | package com.imaginarycode.minecraft.redisbungee; 2 | 3 | import com.velocitypowered.api.proxy.ProxyServer; 4 | 5 | public interface ServerObjectFetcher { 6 | 7 | ProxyServer getProxy(); 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PlayerChangedServerNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | 14 | import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerChangedServerNetworkEvent; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * This event is sent when a player connects to a new server. RedisBungee sends the event only when 20 | * the proxy the player has been connected to is different than the local proxy. 21 | *

22 | * This event corresponds to {@link com.velocitypowered.api.event.player.ServerConnectedEvent}, and is fired 23 | * asynchronously. 24 | * 25 | * @since 0.3.4 26 | */ 27 | public class PlayerChangedServerNetworkEvent implements IPlayerChangedServerNetworkEvent { 28 | private final UUID uuid; 29 | private final String previousServer; 30 | private final String server; 31 | 32 | public PlayerChangedServerNetworkEvent(UUID uuid, String previousServer, String server) { 33 | this.uuid = uuid; 34 | this.previousServer = previousServer; 35 | this.server = server; 36 | } 37 | 38 | @Override 39 | public UUID getUuid() { 40 | return uuid; 41 | } 42 | 43 | @Override 44 | public String getServer() { 45 | return server; 46 | } 47 | 48 | @Override 49 | public String getPreviousServer() { 50 | return previousServer; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PlayerJoinedNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | 14 | import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * This event is sent when a player joins the network. RedisBungee sends the event only when 20 | * the proxy the player has been connected to is different than the local proxy. 21 | *

22 | * This event corresponds to {@link com.velocitypowered.api.event.connection.PostLoginEvent}, and is fired 23 | * asynchronously. 24 | * 25 | * @since 0.3.4 26 | */ 27 | public class PlayerJoinedNetworkEvent implements IPlayerJoinedNetworkEvent { 28 | private final UUID uuid; 29 | 30 | public PlayerJoinedNetworkEvent(UUID uuid) { 31 | this.uuid = uuid; 32 | } 33 | 34 | @Override 35 | public UUID getUuid() { 36 | return uuid; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PlayerLeftNetworkEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | 14 | import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent; 15 | 16 | import java.util.UUID; 17 | 18 | /** 19 | * This event is sent when a player disconnects. RedisBungee sends the event only when 20 | * the proxy the player has been connected to is different than the local proxy. 21 | *

22 | * This event corresponds to {@link com.velocitypowered.api.event.connection.DisconnectEvent}, and is fired 23 | * asynchronously. 24 | * 25 | * @since 0.3.4 26 | */ 27 | public class PlayerLeftNetworkEvent implements IPlayerLeftNetworkEvent { 28 | private final UUID uuid; 29 | 30 | public PlayerLeftNetworkEvent(UUID uuid) { 31 | this.uuid = uuid; 32 | } 33 | 34 | @Override 35 | public UUID getUuid() { 36 | return uuid; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /proxies/velocity/velocity-api/src/main/java/com/imaginarycode/minecraft/redisbungee/events/PubSubMessageEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present RedisBungee contributors 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * which accompanies this distribution, and is available at 7 | * 8 | * http://www.eclipse.org/legal/epl-v10.html 9 | */ 10 | 11 | package com.imaginarycode.minecraft.redisbungee.events; 12 | 13 | 14 | import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent; 15 | 16 | /** 17 | * This event is posted when a PubSub message is received. 18 | *

19 | * Warning: This event is fired in a separate thread! 20 | * 21 | * @since 0.2.6 22 | */ 23 | 24 | public class PubSubMessageEvent implements IPubSubMessageEvent { 25 | private final String channel; 26 | private final String message; 27 | 28 | public PubSubMessageEvent(String channel, String message) { 29 | this.channel = channel; 30 | this.message = message; 31 | } 32 | 33 | @Override 34 | public String getChannel() { 35 | return channel; 36 | } 37 | 38 | @Override 39 | public String getMessage() { 40 | return message; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | 7 | rootProject.name = "ValioBungee" 8 | 9 | include(":RedisBungee-API") 10 | project(":RedisBungee-API").projectDir = file("api") 11 | 12 | include(":RedisBungee-Commands") 13 | project(":RedisBungee-Commands").projectDir = file("commands") 14 | 15 | include(":RedisBungee-Velocity") 16 | project(":RedisBungee-Velocity").projectDir = file("proxies/velocity") 17 | 18 | include(":RedisBungee-Bungee") 19 | project(":RedisBungee-Bungee").projectDir = file("proxies/bungeecord/bungeecord-api") 20 | 21 | include(":RedisBungee-Proxy-Bungee") 22 | project(":RedisBungee-Proxy-Bungee").projectDir = file("proxies/bungeecord") 23 | 24 | include(":RedisBungee-Velocity") 25 | project(":RedisBungee-Velocity").projectDir = file("proxies/velocity/velocity-api") 26 | 27 | include(":RedisBungee-Proxy-Velocity") 28 | project(":RedisBungee-Proxy-Velocity").projectDir = file("proxies/velocity") 29 | 30 | 31 | 32 | 33 | dependencyResolutionManagement { 34 | repositories { 35 | mavenCentral() 36 | maven { 37 | name = "PaperMC" 38 | url = uri("https://repo.papermc.io/repository/maven-public/") 39 | } 40 | maven { 41 | // hosts the bungeecord apis 42 | name = "sonatype" 43 | url = uri("https://oss.sonatype.org/content/repositories/snapshots") 44 | } 45 | maven { 46 | name = "aikar repo" 47 | url = uri("https://repo.aikar.co/content/groups/aikar/") 48 | } 49 | 50 | } 51 | versionCatalogs { 52 | val jedisVersion = "5.1.2" 53 | val configurateVersion = "3.7.3" 54 | val guavaVersion = "31.1-jre" 55 | val okHttpVersion = "2.7.5" 56 | val caffeineVersion = "3.1.8" 57 | val adventureVersion = "4.16.0" 58 | val acf = "0.5.1-SNAPSHOT" 59 | val bungeecordApiVersion = "1.21-R0.1-SNAPSHOT" 60 | val velocityVersion = "3.3.0-SNAPSHOT"; 61 | 62 | 63 | create("libs") { 64 | 65 | library("guava", "com.google.guava:guava:$guavaVersion") 66 | library("jedis", "redis.clients:jedis:$jedisVersion") 67 | library("okhttp", "com.squareup.okhttp:okhttp:$okHttpVersion") 68 | library("configurate", "org.spongepowered:configurate-yaml:$configurateVersion") 69 | library("caffeine", "com.github.ben-manes.caffeine:caffeine:$caffeineVersion") 70 | 71 | library("adventure-api", "net.kyori:adventure-api:$adventureVersion") 72 | library("adventure-gson", "net.kyori:adventure-text-serializer-gson:$adventureVersion") 73 | library("adventure-legacy", "net.kyori:adventure-text-serializer-legacy:$adventureVersion") 74 | library("adventure-plain", "net.kyori:adventure-text-serializer-plain:$adventureVersion") 75 | library("adventure-miniMessage", "net.kyori:adventure-text-minimessage:$adventureVersion") 76 | 77 | library("acf-core", "co.aikar:acf-core:$acf") 78 | library("acf-bungeecord", "co.aikar:acf-bungee:$acf") 79 | library("acf-velocity", "co.aikar:acf-velocity:$acf") 80 | 81 | library("platform-bungeecord","net.md-5:bungeecord-api:$bungeecordApiVersion") 82 | library("adventure-platforms-bungeecord", "net.kyori:adventure-platform-bungeecord:4.3.2") 83 | 84 | library("platform-velocity", "com.velocitypowered:velocity-api:$velocityVersion") 85 | 86 | 87 | 88 | 89 | } 90 | 91 | 92 | } 93 | 94 | 95 | } 96 | --------------------------------------------------------------------------------