├── .editorconfig ├── .gitattributes ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── README.md ├── SECURITY.md ├── dependabot.yml └── workflows │ └── gradle.yml ├── .gitignore ├── HEADER ├── LICENSE ├── api ├── build.gradle.kts └── src │ └── main │ └── java │ └── xyz │ └── jonesdev │ └── sonar │ └── api │ ├── Sonar.java │ ├── SonarPlatform.java │ ├── SonarSupplier.java │ ├── SonarVersion.java │ ├── command │ ├── InvocationSource.java │ ├── SonarCommand.java │ └── subcommand │ │ ├── Subcommand.java │ │ ├── SubcommandInfo.java │ │ └── SubcommandRegistry.java │ ├── config │ ├── Language.java │ ├── SimpleYamlConfig.java │ └── SonarConfiguration.java │ ├── database │ ├── controller │ │ └── VerifiedPlayerController.java │ ├── model │ │ └── VerifiedPlayer.java │ └── ormlite │ │ ├── H2DatabaseTypeAdapter.java │ │ ├── MariaDbDatabaseTypeAdapter.java │ │ └── MysqlDatabaseTypeAdapter.java │ ├── event │ ├── SonarEvent.java │ ├── SonarEventListener.java │ ├── SonarEventManager.java │ └── impl │ │ ├── AttackDetectedEvent.java │ │ ├── AttackMitigatedEvent.java │ │ ├── CaptchaGenerationEndEvent.java │ │ ├── CaptchaGenerationStartEvent.java │ │ ├── UserBlacklistedEvent.java │ │ ├── UserVerifyFailedEvent.java │ │ ├── UserVerifyJoinEvent.java │ │ └── UserVerifySuccessEvent.java │ ├── fallback │ ├── Fallback.java │ ├── FallbackLoginQueue.java │ ├── FallbackPipelines.java │ ├── FallbackUser.java │ ├── captcha │ │ └── CaptchaGenerator.java │ ├── protocol │ │ └── ProtocolVersion.java │ └── ratelimit │ │ └── Ratelimiter.java │ ├── fingerprint │ └── FingerprintingUtil.java │ ├── logger │ └── LoggerWrapper.java │ ├── notification │ ├── ActionBarNotificationHandler.java │ ├── ChatNotificationHandler.java │ └── NotificationHandler.java │ ├── profiler │ └── SimpleProcessProfiler.java │ ├── statistics │ └── SonarStatistics.java │ ├── timer │ └── SystemTimer.java │ ├── tracker │ └── AttackTracker.java │ ├── update │ └── UpdateChecker.java │ └── webhook │ └── DiscordWebhook.java ├── build.gradle.kts ├── bukkit ├── build.gradle.kts └── src │ └── main │ └── java │ └── xyz │ └── jonesdev │ └── sonar │ └── bukkit │ ├── SonarBukkit.java │ ├── SonarBukkitPlugin.java │ ├── command │ └── BukkitSonarCommand.java │ ├── fallback │ ├── BukkitServerVersion.java │ ├── ChannelInactiveListener.java │ ├── FallbackBukkitInboundHandler.java │ └── FallbackBukkitInjector.java │ └── listener │ └── BukkitJoinListener.java ├── bungeecord ├── build.gradle.kts └── src │ └── main │ └── java │ └── xyz │ └── jonesdev │ └── sonar │ └── bungee │ ├── SonarBungee.java │ ├── SonarBungeePlugin.java │ ├── command │ └── BungeeSonarCommand.java │ └── fallback │ ├── FallbackBungeeInboundHandler.java │ └── FallbackBungeeInjector.java ├── captcha ├── build.gradle.kts └── src │ ├── main │ ├── java │ │ └── xyz │ │ │ └── jonesdev │ │ │ └── sonar │ │ │ └── captcha │ │ │ ├── StandardCaptchaGenerator.java │ │ │ ├── StandardTTFFontProvider.java │ │ │ ├── filters │ │ │ ├── CircleInverseFilter.java │ │ │ ├── CurvesOverlayFilter.java │ │ │ ├── GridOverlayFilter.java │ │ │ └── NoiseOverlayFilter.java │ │ │ └── legacy │ │ │ ├── LegacyCaptchaGenerator.java │ │ │ ├── RippleFilter.java │ │ │ └── ScratchFilter.java │ └── resources │ │ └── assets │ │ └── fonts │ │ └── Kingthings_Trypewriter_2.ttf │ └── test │ └── java │ └── Main.java ├── common ├── build.gradle.kts └── src │ └── main │ ├── java │ └── xyz │ │ └── jonesdev │ │ └── sonar │ │ └── common │ │ ├── boot │ │ ├── LibraryLoader.java │ │ └── SonarBootstrap.java │ │ ├── fallback │ │ ├── FallbackBandwidthHandler.java │ │ ├── FallbackInboundHandler.java │ │ ├── FallbackInboundHandlerAdapter.java │ │ ├── FallbackUserWrapper.java │ │ ├── netty │ │ │ ├── FallbackInjectedChannelInitializer.java │ │ │ ├── FallbackTailExceptionsHandler.java │ │ │ ├── FallbackTimeoutHandler.java │ │ │ ├── FallbackVarInt21FrameDecoder.java │ │ │ └── FallbackVarIntLengthEncoder.java │ │ ├── protocol │ │ │ ├── CaptchaPreparer.java │ │ │ ├── FallbackPacket.java │ │ │ ├── FallbackPacketDecoder.java │ │ │ ├── FallbackPacketEncoder.java │ │ │ ├── FallbackPacketListener.java │ │ │ ├── FallbackPacketRegistry.java │ │ │ ├── FallbackPacketSnapshot.java │ │ │ ├── FallbackPreparer.java │ │ │ ├── block │ │ │ │ ├── BlockType.java │ │ │ │ └── BlockUpdate.java │ │ │ ├── dimension │ │ │ │ ├── DimensionRegistry.java │ │ │ │ └── DimensionType.java │ │ │ ├── entity │ │ │ │ └── EntityType.java │ │ │ ├── item │ │ │ │ └── ItemType.java │ │ │ ├── map │ │ │ │ ├── MapCaptchaInfo.java │ │ │ │ └── MapColorPalette.java │ │ │ └── packets │ │ │ │ ├── configuration │ │ │ │ ├── FinishConfigurationPacket.java │ │ │ │ └── RegistryDataPacket.java │ │ │ │ ├── handshake │ │ │ │ └── HandshakePacket.java │ │ │ │ ├── login │ │ │ │ ├── LoginAcknowledgedPacket.java │ │ │ │ ├── LoginStartPacket.java │ │ │ │ └── LoginSuccessPacket.java │ │ │ │ └── play │ │ │ │ ├── AnimationPacket.java │ │ │ │ ├── ChunkDataPacket.java │ │ │ │ ├── ClientInformationPacket.java │ │ │ │ ├── ClientTickEndPacket.java │ │ │ │ ├── ConfirmTeleportationPacket.java │ │ │ │ ├── DisconnectPacket.java │ │ │ │ ├── EntityAnimationPacket.java │ │ │ │ ├── GameEventPacket.java │ │ │ │ ├── JoinGamePacket.java │ │ │ │ ├── KeepAlivePacket.java │ │ │ │ ├── MapDataPacket.java │ │ │ │ ├── PaddleBoatPacket.java │ │ │ │ ├── PlayerAbilitiesPacket.java │ │ │ │ ├── PlayerInputPacket.java │ │ │ │ ├── PluginMessagePacket.java │ │ │ │ ├── RemoveEntitiesPacket.java │ │ │ │ ├── SetContainerSlotPacket.java │ │ │ │ ├── SetDefaultSpawnPositionPacket.java │ │ │ │ ├── SetExperiencePacket.java │ │ │ │ ├── SetHeldItemPacket.java │ │ │ │ ├── SetPassengersPacket.java │ │ │ │ ├── SetPlayerOnGround.java │ │ │ │ ├── SetPlayerPositionPacket.java │ │ │ │ ├── SetPlayerPositionRotationPacket.java │ │ │ │ ├── SetPlayerRotationPacket.java │ │ │ │ ├── SpawnEntityPacket.java │ │ │ │ ├── SystemChatPacket.java │ │ │ │ ├── TransactionPacket.java │ │ │ │ ├── TransferPacket.java │ │ │ │ ├── UpdateSectionBlocksPacket.java │ │ │ │ ├── UpdateTimePacket.java │ │ │ │ └── VehicleMovePacket.java │ │ ├── ratelimit │ │ │ ├── CaffeineCacheRatelimiter.java │ │ │ └── NoopCacheRatelimiter.java │ │ └── verification │ │ │ ├── FallbackCaptchaHandler.java │ │ │ ├── FallbackGravityHandler.java │ │ │ ├── FallbackPreJoinHandler.java │ │ │ ├── FallbackProtocolHandler.java │ │ │ ├── FallbackVehicleHandler.java │ │ │ └── FallbackVerificationHandler.java │ │ ├── service │ │ └── ScheduledServiceManager.java │ │ ├── statistics │ │ └── GlobalSonarStatistics.java │ │ ├── subcommand │ │ ├── BlacklistCommand.java │ │ ├── DumpCommand.java │ │ ├── NotifyCommand.java │ │ ├── ReloadCommand.java │ │ ├── StatisticsCommand.java │ │ ├── VerboseCommand.java │ │ └── VerifiedCommand.java │ │ └── util │ │ ├── ComponentHolder.java │ │ ├── FakeChannelUtil.java │ │ ├── FastUuidSansHyphens.java │ │ ├── GeyserUtil.java │ │ ├── ProtocolUtil.java │ │ └── exception │ │ ├── QuietDecoderException.java │ │ └── ReflectiveOperationException.java │ └── resources │ └── assets │ ├── codecs │ ├── codec_1_16.nbt │ ├── codec_1_16_2.nbt │ ├── codec_1_18_2.nbt │ ├── codec_1_19.nbt │ ├── codec_1_19_1.nbt │ ├── codec_1_19_4.nbt │ ├── codec_1_20.nbt │ ├── codec_1_20_5.nbt │ ├── codec_1_21.nbt │ ├── codec_1_21_2.nbt │ ├── codec_1_21_4.nbt │ └── codec_1_21_5.nbt │ ├── config │ ├── cs.yml │ ├── de.yml │ ├── en.yml │ ├── fr.yml │ ├── ka.yml │ ├── nl.yml │ ├── pl.yml │ ├── pt-br.yml │ ├── ru.yml │ └── zh.yml │ ├── language.properties │ ├── messages │ ├── cs.yml │ ├── de.yml │ ├── en.yml │ ├── es.yml │ ├── fr.yml │ ├── id.yml │ ├── ka.yml │ ├── nl.yml │ ├── pl.yml │ ├── pt-br.yml │ ├── ru.yml │ ├── tr.yml │ └── zh.yml │ └── webhook │ ├── cs.yml │ ├── de.yml │ ├── en.yml │ ├── es.yml │ ├── fr.yml │ ├── id.yml │ ├── ka.yml │ ├── nl.yml │ ├── pl.yml │ ├── pt-br.yml │ ├── ru.yml │ └── zh.yml ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lombok.config ├── settings.gradle.kts └── velocity ├── build.gradle.kts └── src └── main ├── java └── xyz │ └── jonesdev │ └── sonar │ └── velocity │ ├── SonarVelocity.java │ ├── SonarVelocityPlugin.java │ ├── command │ └── VelocitySonarCommand.java │ └── fallback │ ├── FallbackVelocityInboundHandler.java │ └── FallbackVelocityInjector.java └── resources └── velocity-plugin.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [**] 4 | charset = UTF-8 5 | indent_style = space 6 | indent_size = 2 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.java] 11 | ij_java_wrap_long_lines = true 12 | 13 | [{*.md,*.yml}] 14 | indent_style = unset 15 | insert_final_newline = unset 16 | trim_trailing_whitespace = unset 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Credits to https://github.com/alexkaratarakis/gitattributes/blob/master/Java.gitattributes 5 | # Java sources 6 | *.java text diff=java 7 | *.kt text diff=kotlin 8 | *.groovy text diff=java 9 | *.scala text diff=java 10 | *.gradle text diff=java 11 | *.gradle.kts text diff=kotlin 12 | 13 | # These files are binary and should be left untouched 14 | # (binary is a macro for -text -diff) 15 | *.class binary 16 | *.dll binary 17 | *.ear binary 18 | *.jar binary 19 | *.so binary 20 | *.war binary 21 | *.jks binary 22 | 23 | # Common build-tool wrapper scripts ('.cmd' versions are handled by 'Common.gitattributes') 24 | gradlew text eol=lf 25 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Before you start contributing, please take a moment to review our contributing guidelines. 2 | If you can't contribute but like the project, feel free to show your support by starring the project on GitHub or 3 | joining the [Discord](https://jonesdev.xyz/discord). 4 | 5 | ## Contributing Guidelines: 6 | 7 | 1. Fork the repository and create a new branch for your contribution. 8 | 2. Follow the coding guidelines for your code. 9 | 3. Test your code before committing and pushing it. 10 | 4. Use [semantic](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) commit messages for your commits. 11 | 12 | ## Coding Guidelines: 13 | 14 | - Use the same code style and formatting as the rest of the project. 15 | - Optional: Use an IDE that supports .editorconfig files. 16 | - Use meaningful names for variables, classes, and methods. 17 | - Write clear comments to explain complex parts of your code. 18 | - Ensure your code is easy to read and maintain. 19 | 20 | ## Bug Reports: 21 | 22 | 1. Check if someone has already reported the bug. 23 | 2. If not, open a new issue with a clear and detailed title. 24 | 3. Describe the bug, including the steps to reproduce it. 25 | 4. Include all logs related to the issue. 26 | 5. Provide the output of '/sonar dump'. 27 | 6. Feel free to provide any additional information. 28 | 29 | ## Feature Requests: 30 | 31 | 1. Check if someone has already made the same request. 32 | 2. If not, open a new issue with a clear and detailed title. 33 | 3. Explain the feature you want to see in Sonar and provide an example. 34 | 4. Explain why you want to see the feature in Sonar. 35 | 5. Feel free to provide any additional information. 36 | 37 | ## Pull Requests: 38 | 39 | - Use a clear and descriptive title for your pull request. 40 | - Provide a detailed description of the changes you made. 41 | - Reference related issues or pull requests. 42 | - Make sure everything is properly tested. 43 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: jonesdev -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report bugs to improve security, stability and usability 3 | title: "Bug Report" 4 | labels: ["bug"] 5 | 6 | assignees: [] 7 | 8 | body: 9 | - type: textarea 10 | id: info_and_expected_outcome 11 | attributes: 12 | label: "General information" 13 | description: | 14 | Describe the bug and the expected outcome. 15 | validations: 16 | required: true 17 | 18 | - type: textarea 19 | id: steps_to_reproduce 20 | attributes: 21 | label: "Steps to reproduce" 22 | description: | 23 | Please provide a short list of steps you need to do to reproduce the issue. 24 | placeholder: | 25 | 1. Join the server [...] 26 | 2. ... 27 | validations: 28 | required: true 29 | 30 | - type: textarea 31 | id: sonar_dump 32 | attributes: 33 | label: "Sonar dump" 34 | description: "Please provide the output of the command /sonar dump" 35 | validations: 36 | required: true 37 | 38 | - type: textarea 39 | id: additional_information 40 | attributes: 41 | label: "Additional information" 42 | description: | 43 | Is there any additional information you would like to provide? 44 | validations: 45 | required: false 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Documentation 4 | url: https://docs.jonesdev.xyz/ 5 | about: Need help configuring Sonar or have questions regarding the installation and usage? 6 | - name: Discord 7 | url: https://jonesdev.xyz/discord/ 8 | about: If you have any further questions, please feel free to join the Discord server and open a ticket. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest a feature to improve the plugin 3 | title: "Feature Request" 4 | labels: ["enhancement"] 5 | 6 | assignees: [] 7 | 8 | body: 9 | - type: textarea 10 | id: general 11 | attributes: 12 | label: "Information" 13 | description: | 14 | Please provide some information about the feature you would like to be implemented. 15 | Is it related to an existing problem/bug/issue? 16 | Are there any screenshots or videos showcasing the feature to better understand your request? 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | id: reason 22 | attributes: 23 | label: "Reason" 24 | description: | 25 | Is there a specific reason why you would like this feature to be implemented? 26 | validations: 27 | required: true 28 | 29 | - type: textarea 30 | id: additional 31 | attributes: 32 | label: "Additional information" 33 | description: | 34 | Is there any additional information you would like to provide? 35 | validations: 36 | required: false 37 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Reporting a security vulnerability 2 | 3 | If you encounter a bug, issue, or vulnerability that doesn't pose an immediate security risk, you can report it through the regular issue tracker. 4 | 5 | If you discover a security vulnerability within Sonar, please follow these steps to report it: 6 | 1. Do not disclose serious issues publicly before they are fixed. 7 | 2. Please provide as much detail as possible about the vulnerability. 8 | 3. Depending on the severity and complexity of the issue, the response time may vary. 9 | 4. Additional information might be requested. 10 | 5. Once the vulnerability is confirmed, an update with the fixes will roll out. 11 | 6. Users will be notified some time later to ensure safety for those who are using a vulnerable version. 12 | 7. You will be publicly acknowledged for your contribution if you choose to be credited. 13 | 14 | ## Contact 15 | 16 | If you have any questions or concerns regarding the security of this project, please open a ticket on Discord or contact me via email at contact@jonesdev.xyz. 17 | 18 | ## Acknowledgments 19 | 20 | - Special thanks to the [contributors of Sonar](https://github.com/jonesdevelopment/sonar/graphs/contributors), 21 | and also those who reported security issues or bugs. 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gradle" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time 6 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle 7 | 8 | name: Sonar CI 9 | 10 | on: 11 | push: 12 | branches: [ "main" ] 13 | pull_request: 14 | branches: [ "main" ] 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Set up JDK 17 27 | uses: actions/setup-java@v3 28 | with: 29 | java-version: '17' 30 | distribution: 'temurin' 31 | 32 | - name: Setup Gradle 33 | uses: gradle/actions/setup-gradle@v4 34 | 35 | - name: Build with Gradle 36 | run: ./gradlew build-sonar 37 | 38 | - name: Upload Bukkit Artifact 39 | uses: actions/upload-artifact@v4 40 | with: 41 | name: Sonar-Bukkit 42 | path: bukkit/build/libs/Sonar-Bukkit.jar 43 | if-no-files-found: error 44 | 45 | - name: Upload BungeeCord Artifact 46 | uses: actions/upload-artifact@v4 47 | with: 48 | name: Sonar-Bungee 49 | path: bungeecord/build/libs/Sonar-Bungee.jar 50 | if-no-files-found: error 51 | 52 | - name: Upload Velocity Artifact 53 | uses: actions/upload-artifact@v4 54 | with: 55 | name: Sonar-Velocity 56 | path: velocity/build/libs/Sonar-Velocity.jar 57 | if-no-files-found: error 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # GitHub 2 | .github/ 3 | HEADER 4 | LICENSE 5 | .*ignore 6 | .*config 7 | .*attributes 8 | 9 | # Editor configurations 10 | .idea/ 11 | .gradle/ 12 | vscode/ 13 | .fleet/ 14 | 15 | # Build directories 16 | target/ 17 | out/ 18 | gradle/ 19 | build/ 20 | gradlew* 21 | 22 | # Uncommon files 23 | *.bat 24 | *.cmd 25 | *.jar 26 | *.class 27 | *.iml 28 | *.exe 29 | *.png 30 | *.jpg 31 | *.jpeg 32 | *.log 33 | *.svg 34 | *.txt 35 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | -------------------------------------------------------------------------------- /api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | repositories { 2 | maven(url = "https://jitpack.io/") // simple-yaml 3 | } 4 | 5 | dependencies { 6 | compileOnly(rootProject.libs.simpleyaml) { 7 | exclude(group = "org.yaml") 8 | } 9 | compileOnly(rootProject.libs.annotations) 10 | } 11 | 12 | tasks { 13 | shadowJar { 14 | archiveFileName = "sonar-api-${rootProject.version}.jar" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/SonarPlatform.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api; 19 | 20 | import io.netty.channel.ChannelPipeline; 21 | import lombok.Getter; 22 | import lombok.RequiredArgsConstructor; 23 | 24 | import java.util.function.Function; 25 | 26 | @Getter 27 | @RequiredArgsConstructor 28 | public enum SonarPlatform { 29 | BUKKIT("Bukkit", 19110, "packet_handler", 30 | pipeline -> pipeline.context("outbound_config") != null ? "outbound_config" : "encoder"), 31 | BUNGEE("BungeeCord", 19109, "inbound-boss", 32 | pipeline -> "packet-encoder"), 33 | VELOCITY("Velocity", 19107, "handler", 34 | pipeline -> "minecraft-encoder"); 35 | 36 | private final String displayName; 37 | private final int metricsId; 38 | private final String connectionHandler; 39 | private final Function encoder; 40 | } 41 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/SonarSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api; 19 | 20 | import lombok.experimental.UtilityClass; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | @UtilityClass 24 | public class SonarSupplier { 25 | Sonar sonar; 26 | 27 | public void set(final @NotNull Sonar _sonar) { 28 | if (sonar != null) { 29 | throw new IllegalStateException("Sonar is already initialized"); 30 | } 31 | sonar = _sonar; 32 | } 33 | 34 | public Sonar get() { 35 | if (sonar == null) { 36 | throw new IllegalStateException("Sonar is not initialized yet"); 37 | } 38 | return sonar; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/SonarVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api; 19 | 20 | import lombok.Getter; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.net.URL; 26 | import java.util.jar.Manifest; 27 | 28 | @Getter 29 | public final class SonarVersion { 30 | static final SonarVersion INSTANCE = new SonarVersion(); 31 | 32 | private final String version, formatted, gitBranch, gitCommit; 33 | 34 | SonarVersion() { 35 | // No need to null-check since we'll always just throw an exception if 36 | // we can't find the version information in this file. 37 | final Manifest manifest = getManifest(); 38 | 39 | this.version = manifest.getMainAttributes().getValue("Implementation-Version"); 40 | this.gitBranch = manifest.getMainAttributes().getValue("Git-Branch"); 41 | this.gitCommit = manifest.getMainAttributes().getValue("Git-Commit"); 42 | this.formatted = version + " (" + gitCommit + ")"; 43 | } 44 | 45 | // https://github.com/PaperMC/Velocity/pull/1336/ 46 | private static @NotNull Manifest getManifest() { 47 | final String classLocation = "/" + Sonar.class.getName().replace(".", "/") + ".class"; 48 | final URL resource = Sonar.class.getResource(classLocation); 49 | 50 | if (resource == null) { 51 | throw new IllegalStateException("Could not find version information. Is the manifest missing?"); 52 | } 53 | 54 | final String classFilePath = resource.toString().replace("\\", "/"); 55 | final String archivePath = classFilePath.substring(0, classFilePath.length() - classLocation.length()); 56 | final String manifestPath = archivePath + "/META-INF/MANIFEST.MF"; 57 | 58 | try (final InputStream stream = new URL(manifestPath).openStream()) { 59 | return new Manifest(stream); 60 | } catch (IOException exception) { 61 | throw new IllegalStateException(exception); 62 | } 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return formatted; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/command/InvocationSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.command; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import net.kyori.adventure.audience.Audience; 23 | import net.kyori.adventure.text.Component; 24 | 25 | import java.util.UUID; 26 | import java.util.function.Predicate; 27 | 28 | @Getter 29 | @RequiredArgsConstructor 30 | public final class InvocationSource { 31 | private final UUID uuid; 32 | private final Audience audience; 33 | private final Predicate permissionFunction; 34 | 35 | /** 36 | * @return true if {@link InvocationSource#uuid} is not null 37 | */ 38 | public boolean isPlayer() { 39 | return uuid != null; 40 | } 41 | 42 | /** 43 | * Sends a message to the command executor 44 | */ 45 | public void sendMessage(final Component component) { 46 | audience.sendMessage(component); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/command/subcommand/SubcommandInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.command.subcommand; 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | @Retention(RetentionPolicy.RUNTIME) 26 | @Target(ElementType.TYPE) 27 | public @interface SubcommandInfo { 28 | String name(); 29 | 30 | String[] aliases() default {}; 31 | 32 | String[] arguments() default {}; 33 | 34 | boolean argumentsRequired() default true; 35 | 36 | boolean onlyPlayers() default false; 37 | 38 | boolean onlyConsole() default false; 39 | } 40 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/command/subcommand/SubcommandRegistry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.command.subcommand; 19 | 20 | import lombok.Getter; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.Vector; 26 | 27 | @Getter 28 | public final class SubcommandRegistry { 29 | private final List subcommands = new Vector<>(); 30 | 31 | /** 32 | * Registers a single or multiple subcommand(s) 33 | * 34 | * @param subcommand Array of Subcommands to register 35 | */ 36 | public void register(final Subcommand @NotNull ... subcommand) { 37 | subcommands.addAll(Arrays.asList(subcommand)); 38 | } 39 | 40 | /** 41 | * Unregisters a single or multiple subcommand(s) 42 | * 43 | * @param subcommand Array of Subcommands to unregister 44 | */ 45 | @SuppressWarnings("unused") 46 | public void unregister(final Subcommand @NotNull ... subcommand) { 47 | subcommands.removeAll(Arrays.asList(subcommand)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/database/model/VerifiedPlayer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.database.model; 19 | 20 | import com.j256.ormlite.field.DatabaseField; 21 | import com.j256.ormlite.table.DatabaseTable; 22 | import lombok.AccessLevel; 23 | import lombok.Getter; 24 | import lombok.NoArgsConstructor; 25 | import lombok.ToString; 26 | import org.jetbrains.annotations.NotNull; 27 | 28 | import java.sql.Timestamp; 29 | 30 | @Getter 31 | @ToString 32 | @DatabaseTable(tableName = "sonar_fingerprints") 33 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 34 | public final class VerifiedPlayer { 35 | @SuppressWarnings("unused") 36 | @DatabaseField(generatedId = true) 37 | private int id; 38 | 39 | @DatabaseField( 40 | columnName = "fingerprint", 41 | canBeNull = false, 42 | width = 48 43 | ) 44 | private String fingerprint; 45 | 46 | @DatabaseField( 47 | columnName = "timestamp", 48 | canBeNull = false 49 | ) 50 | private Timestamp timestamp; 51 | 52 | public VerifiedPlayer(final @NotNull String fingerprint, 53 | final long timestamp) { 54 | this.fingerprint = fingerprint; 55 | this.timestamp = new Timestamp(timestamp); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/database/ormlite/H2DatabaseTypeAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.database.ormlite; 19 | 20 | import com.j256.ormlite.jdbc.db.H2DatabaseType; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | public final class H2DatabaseTypeAdapter extends H2DatabaseType { 24 | 25 | // We need to override the default driver class name 26 | // to use the custom relocated H2 driver 27 | @Override 28 | protected String @NotNull [] getDriverClassNames() { 29 | return new String[]{"xyz.jonesdev.sonar.libs.h2.Driver"}; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/database/ormlite/MariaDbDatabaseTypeAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.database.ormlite; 19 | 20 | import com.j256.ormlite.jdbc.db.MariaDbDatabaseType; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | public final class MariaDbDatabaseTypeAdapter extends MariaDbDatabaseType { 24 | 25 | // We need to override the default driver class name 26 | // to use the custom relocated MariaDB driver 27 | @Override 28 | protected String @NotNull [] getDriverClassNames() { 29 | return new String[]{"xyz.jonesdev.sonar.libs.mariadb.jdbc.Driver"}; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/database/ormlite/MysqlDatabaseTypeAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.database.ormlite; 19 | 20 | import com.j256.ormlite.jdbc.db.MysqlDatabaseType; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | public final class MysqlDatabaseTypeAdapter extends MysqlDatabaseType { 24 | 25 | // We need to override the default driver class name 26 | // to use the custom relocated MySQL driver 27 | @Override 28 | protected String @NotNull [] getDriverClassNames() { 29 | return new String[]{"xyz.jonesdev.sonar.libs.mysql.cj.jdbc.Driver"}; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/SonarEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event; 19 | 20 | public interface SonarEvent { 21 | } 22 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/SonarEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event; 19 | 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | @FunctionalInterface 23 | public interface SonarEventListener { 24 | 25 | /** 26 | * Handles the publishing of an event through Sonar's API 27 | */ 28 | void handle(final @NotNull SonarEvent event); 29 | } 30 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/AttackDetectedEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import xyz.jonesdev.sonar.api.event.SonarEvent; 21 | 22 | public final class AttackDetectedEvent implements SonarEvent { 23 | } 24 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/AttackMitigatedEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | import xyz.jonesdev.sonar.api.event.SonarEvent; 24 | import xyz.jonesdev.sonar.api.tracker.AttackTracker; 25 | 26 | @Getter 27 | @ToString 28 | @RequiredArgsConstructor 29 | public final class AttackMitigatedEvent implements SonarEvent { 30 | private final AttackTracker.AttackStatistics attackStatistics; 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/CaptchaGenerationEndEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | import xyz.jonesdev.sonar.api.event.SonarEvent; 24 | import xyz.jonesdev.sonar.api.timer.SystemTimer; 25 | 26 | @Getter 27 | @ToString 28 | @RequiredArgsConstructor 29 | public final class CaptchaGenerationEndEvent implements SonarEvent { 30 | private final SystemTimer timer; 31 | private final int amountGenerated; 32 | } 33 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/CaptchaGenerationStartEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.AllArgsConstructor; 21 | import lombok.Getter; 22 | import lombok.Setter; 23 | import xyz.jonesdev.sonar.api.event.SonarEvent; 24 | import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator; 25 | 26 | @Getter 27 | @Setter 28 | @AllArgsConstructor 29 | public final class CaptchaGenerationStartEvent implements SonarEvent { 30 | private CaptchaGenerator captchaGenerator; 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserBlacklistedEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | import xyz.jonesdev.sonar.api.event.SonarEvent; 24 | import xyz.jonesdev.sonar.api.fallback.FallbackUser; 25 | 26 | @Getter 27 | @ToString 28 | @RequiredArgsConstructor 29 | public final class UserBlacklistedEvent implements SonarEvent { 30 | private final FallbackUser user; 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserVerifyFailedEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | import org.jetbrains.annotations.NotNull; 24 | import xyz.jonesdev.sonar.api.event.SonarEvent; 25 | import xyz.jonesdev.sonar.api.fallback.FallbackUser; 26 | 27 | @Getter 28 | @ToString 29 | @RequiredArgsConstructor 30 | public final class UserVerifyFailedEvent implements SonarEvent { 31 | private final @NotNull FallbackUser user; 32 | private final @NotNull String reason; 33 | } 34 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserVerifyJoinEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | import xyz.jonesdev.sonar.api.event.SonarEvent; 24 | import xyz.jonesdev.sonar.api.fallback.FallbackUser; 25 | 26 | @Getter 27 | @ToString 28 | @RequiredArgsConstructor 29 | public final class UserVerifyJoinEvent implements SonarEvent { 30 | private final FallbackUser user; 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/event/impl/UserVerifySuccessEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.event.impl; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import lombok.ToString; 23 | import xyz.jonesdev.sonar.api.event.SonarEvent; 24 | import xyz.jonesdev.sonar.api.fallback.FallbackUser; 25 | 26 | @Getter 27 | @ToString 28 | @RequiredArgsConstructor 29 | public final class UserVerifySuccessEvent implements SonarEvent { 30 | private final FallbackUser user; 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fallback/Fallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fallback; 19 | 20 | import com.github.benmanes.caffeine.cache.Cache; 21 | import lombok.AccessLevel; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.Setter; 25 | import xyz.jonesdev.sonar.api.Sonar; 26 | import xyz.jonesdev.sonar.api.config.SonarConfiguration; 27 | import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator; 28 | import xyz.jonesdev.sonar.api.fallback.ratelimit.Ratelimiter; 29 | 30 | import java.net.InetAddress; 31 | import java.util.concurrent.ConcurrentHashMap; 32 | import java.util.concurrent.ConcurrentMap; 33 | 34 | @Getter 35 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 36 | public final class Fallback { 37 | public static final Fallback INSTANCE = new Fallback(); 38 | 39 | private final ConcurrentMap online = new ConcurrentHashMap<>(128); 40 | private final ConcurrentMap connected = new ConcurrentHashMap<>(256); 41 | private final FallbackLoginQueue queue = new FallbackLoginQueue(); 42 | @Setter 43 | private Cache blacklist; 44 | @Setter 45 | private long blacklistTime; 46 | @Setter 47 | private CaptchaGenerator captchaGenerator; 48 | @Setter 49 | private Ratelimiter ratelimiter; 50 | 51 | public boolean shouldVerifyNewPlayers() { 52 | return shouldPerform(Sonar.get0().getConfig().getVerification().getTiming()); 53 | } 54 | 55 | public boolean shouldPerformCaptcha() { 56 | return shouldPerform(Sonar.get0().getConfig().getVerification().getMap().getTiming()); 57 | } 58 | 59 | private static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) { 60 | return timing == SonarConfiguration.Verification.Timing.ALWAYS 61 | || (timing == SonarConfiguration.Verification.Timing.DURING_ATTACK 62 | && Sonar.get0().getAttackTracker().getCurrentAttack() != null); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fallback/FallbackLoginQueue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fallback; 19 | 20 | import lombok.AccessLevel; 21 | import lombok.Getter; 22 | import lombok.RequiredArgsConstructor; 23 | import xyz.jonesdev.sonar.api.Sonar; 24 | 25 | import java.net.InetAddress; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | import java.util.concurrent.ConcurrentMap; 28 | import java.util.concurrent.ExecutorService; 29 | import java.util.concurrent.Executors; 30 | 31 | @Getter 32 | @RequiredArgsConstructor(access = AccessLevel.PROTECTED) 33 | public final class FallbackLoginQueue { 34 | // Fixed thread pool executor for all new verifications 35 | private static final int THREAD_POOL_SIZE = Math.min(0x7fff, Runtime.getRuntime().availableProcessors() * 2); 36 | private static final ExecutorService QUEUE_EXECUTOR = Executors.newFixedThreadPool(THREAD_POOL_SIZE); 37 | 38 | private final ConcurrentMap players = new ConcurrentHashMap<>(512); 39 | 40 | public void poll() { 41 | final int maxQueuePolls = Math.min(players.size(), Sonar.get0().getConfig().getQueue().getMaxQueuePolls()); 42 | // No need to initiate an executor service task if nobody is currently queued 43 | if (maxQueuePolls <= 0) return; 44 | // We need to be cautious here since we don't want any concurrency issues 45 | QUEUE_EXECUTOR.execute(() -> { 46 | final var iterator = players.entrySet().iterator(); 47 | for (int index = 0; index < maxQueuePolls && iterator.hasNext(); index++) { 48 | iterator.next().getValue().run(); 49 | iterator.remove(); 50 | } 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fallback/FallbackPipelines.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fallback; 19 | 20 | public interface FallbackPipelines { 21 | String FALLBACK_INACTIVE_LISTENER = "sonar-inactive-listener"; 22 | String FALLBACK_INBOUND_HANDLER = "sonar-inbound-handler"; 23 | String FALLBACK_FRAME_DECODER = "sonar-frame-decoder"; 24 | String FALLBACK_FRAME_ENCODER = "sonar-frame-encoder"; 25 | String FALLBACK_TIMEOUT = "sonar-timeout"; 26 | String FALLBACK_PACKET_HANDLER = "sonar-packet-handler"; 27 | String FALLBACK_PACKET_ENCODER = "sonar-packet-encoder"; 28 | String FALLBACK_PACKET_DECODER = "sonar-packet-decoder"; 29 | String FALLBACK_TAIL_EXCEPTIONS = "sonar-exception-tail"; 30 | String FALLBACK_BANDWIDTH = "sonar-bandwidth-counter"; 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fallback/FallbackUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fallback; 19 | 20 | import io.netty.channel.Channel; 21 | import io.netty.util.ReferenceCountUtil; 22 | import net.kyori.adventure.text.Component; 23 | import org.jetbrains.annotations.NotNull; 24 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 25 | import xyz.jonesdev.sonar.api.timer.SystemTimer; 26 | 27 | import java.net.InetAddress; 28 | 29 | public interface FallbackUser { 30 | @NotNull Channel channel(); 31 | 32 | @NotNull InetAddress getInetAddress(); 33 | 34 | @NotNull ProtocolVersion getProtocolVersion(); 35 | 36 | @NotNull SystemTimer getLoginTimer(); 37 | 38 | @NotNull String getFingerprint(); 39 | 40 | @NotNull String getUsername(); 41 | 42 | boolean isForceCaptcha(); 43 | 44 | void setForceCaptcha(final boolean isForceCaptcha); 45 | 46 | boolean isGeyser(); 47 | 48 | /** 49 | * Disconnect the player during/after verification 50 | * using our custom Disconnect packet. 51 | * 52 | * @param reason Disconnect message component 53 | */ 54 | void disconnect(final @NotNull Component reason); 55 | 56 | /** 57 | * Sends a packet/message to the player 58 | * 59 | * @param msg Message to send to the player 60 | */ 61 | default void write(final @NotNull Object msg) { 62 | if (channel().isActive()) { 63 | channel().writeAndFlush(msg, channel().voidPromise()); 64 | } else { 65 | ReferenceCountUtil.release(msg); 66 | } 67 | } 68 | 69 | /** 70 | * Queues a buffered message that will be 71 | * sent once all messages are flushed. 72 | */ 73 | default void delayedWrite(final @NotNull Object msg) { 74 | if (channel().isActive()) { 75 | channel().write(msg, channel().voidPromise()); 76 | } else { 77 | ReferenceCountUtil.release(msg); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fallback/captcha/CaptchaGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fallback.captcha; 19 | 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | import java.awt.image.BufferedImage; 23 | 24 | @FunctionalInterface 25 | public interface CaptchaGenerator { 26 | 27 | /** 28 | * Generates a {@link java.awt.image.BufferedImage} that shows the answer to the CAPTCHA 29 | */ 30 | @NotNull BufferedImage createImage(final char @NotNull [] answer); 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fallback/ratelimit/Ratelimiter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fallback.ratelimit; 19 | 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | @FunctionalInterface 23 | public interface Ratelimiter { 24 | boolean attempt(final @NotNull T t); 25 | } 26 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/fingerprint/FingerprintingUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.fingerprint; 19 | 20 | import lombok.experimental.UtilityClass; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | @UtilityClass 24 | public class FingerprintingUtil { 25 | 26 | /** 27 | * Returns a hex string representing a hash of the username and IP address 28 | */ 29 | public @NotNull String getFingerprint(final @NotNull String username, 30 | final @NotNull String hostAddress) { 31 | final int hash0 = username.hashCode(); 32 | final int hash1 = hostAddress.hashCode(); 33 | final int combined = hash0 + hash1; 34 | return Integer.toHexString(hash0 >> 4) 35 | + Integer.toHexString(combined << 2) 36 | + Integer.toHexString(hash1 >> 4); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/notification/NotificationHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.notification; 19 | 20 | import lombok.Getter; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | import java.util.Collection; 24 | import java.util.UUID; 25 | import java.util.Vector; 26 | 27 | @Getter 28 | public abstract class NotificationHandler { 29 | protected final @NotNull Collection subscribers = new Vector<>(0); 30 | 31 | public abstract void handleNotification(); 32 | 33 | /** 34 | * @param uuid UUID of the player 35 | * @return Whether the audience is subscribed or not 36 | */ 37 | public final boolean isSubscribed(final @NotNull UUID uuid) { 38 | return getSubscribers().contains(uuid); 39 | } 40 | 41 | /** 42 | * @param uuid UUID of the player 43 | */ 44 | public final void subscribe(final UUID uuid) { 45 | getSubscribers().add(uuid); 46 | } 47 | 48 | /** 49 | * @param uuid UUID of the player 50 | */ 51 | public final void unsubscribe(final UUID uuid) { 52 | getSubscribers().remove(uuid); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/statistics/SonarStatistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.statistics; 19 | 20 | @SuppressWarnings("unused") 21 | public interface SonarStatistics { 22 | long getConnectionsPerSecond(); 23 | 24 | long getLoginsPerSecond(); 25 | 26 | long getCurrentIncomingBandwidth(); 27 | 28 | long getCurrentOutgoingBandwidth(); 29 | 30 | long getTotalIncomingBandwidth(); 31 | 32 | long getTotalOutgoingBandwidth(); 33 | 34 | String getPerSecondIncomingBandwidthFormatted(); 35 | 36 | String getPerSecondOutgoingBandwidthFormatted(); 37 | 38 | int getTotalPlayersJoined(); 39 | 40 | int getTotalPlayersVerified(); 41 | 42 | int getTotalSuccessfulVerifications(); 43 | 44 | int getTotalFailedVerifications(); 45 | 46 | long getCurrentAttemptedVerifications(); 47 | 48 | int getTotalAttemptedVerifications(); 49 | 50 | long getCurrentBlacklistSize(); 51 | 52 | long getTotalBlacklistSize(); 53 | } 54 | -------------------------------------------------------------------------------- /api/src/main/java/xyz/jonesdev/sonar/api/timer/SystemTimer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.api.timer; 19 | 20 | import lombok.Getter; 21 | 22 | import java.text.SimpleDateFormat; 23 | 24 | @Getter 25 | public final class SystemTimer { 26 | public static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("mm:ss"); 27 | 28 | private long start = System.currentTimeMillis(); 29 | 30 | public void reset() { 31 | start = System.currentTimeMillis(); 32 | } 33 | 34 | /** 35 | * @return Time between the current timestamp and the start timestamp 36 | */ 37 | public long delay() { 38 | return System.currentTimeMillis() - start; 39 | } 40 | 41 | /** 42 | * @apiNote Read more: {@link SystemTimer#delay} 43 | */ 44 | public boolean elapsed(final long amount) { 45 | return delay() >= amount; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return String.format("%.3f", delay() / 1000D); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bukkit/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import net.minecrell.pluginyml.bukkit.BukkitPluginDescription 2 | 3 | plugins { 4 | alias(libs.plugins.pluginyml.bukkit) apply true 5 | } 6 | 7 | bukkit { 8 | name = rootProject.name 9 | main = "xyz.jonesdev.sonar.bukkit.SonarBukkitPlugin" 10 | authors = listOf("Jones Development", "Sonar Contributors") 11 | website = "https://jonesdev.xyz/discord/" 12 | load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD 13 | softDepend = listOf("Geyser-Spigot", "floodgate", "Protocolize", "ProtocolSupport", 14 | "ViaVersion", "packetevents", "ProtocolLib", "FastLogin") 15 | apiVersion = "1.13" // ignore legacy plugin warning 16 | foliaSupported = true 17 | 18 | commands { 19 | register("sonar") { 20 | // No permission checks here 21 | } 22 | } 23 | } 24 | 25 | repositories { 26 | maven(url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot 27 | maven(url = "https://oss.sonatype.org/content/repositories/snapshots/") // BungeeCord Chat API 28 | } 29 | 30 | dependencies { 31 | implementation(project(":api")) 32 | implementation(project(":common")) 33 | 34 | compileOnly(rootProject.libs.spigot) 35 | testCompileOnly(rootProject.libs.spigot) 36 | 37 | implementation(rootProject.libs.adventure.platform.bukkit) { 38 | exclude(module = "adventure-nbt") 39 | } 40 | implementation(rootProject.libs.bstats.bukkit) 41 | implementation(rootProject.libs.libby.bukkit) 42 | } 43 | 44 | tasks { 45 | shadowJar { 46 | relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /bukkit/src/main/java/xyz/jonesdev/sonar/bukkit/SonarBukkitPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.bukkit; 19 | 20 | import org.bukkit.plugin.java.JavaPlugin; 21 | import xyz.jonesdev.sonar.bukkit.fallback.FallbackBukkitInjector; 22 | 23 | public final class SonarBukkitPlugin extends JavaPlugin { 24 | private SonarBukkit bootstrap; 25 | 26 | @Override 27 | public void onLoad() { 28 | // Inject early if late-bind is disabled 29 | if (!FallbackBukkitInjector.isLateBindEnabled()) { 30 | FallbackBukkitInjector.inject(); 31 | } 32 | } 33 | 34 | @Override 35 | public void onEnable() { 36 | bootstrap = new SonarBukkit(this); 37 | bootstrap.initialize(); 38 | } 39 | 40 | @Override 41 | public void onDisable() { 42 | bootstrap.shutdown(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bukkit/src/main/java/xyz/jonesdev/sonar/bukkit/command/BukkitSonarCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.bukkit.command; 19 | 20 | import org.bukkit.command.Command; 21 | import org.bukkit.command.CommandExecutor; 22 | import org.bukkit.command.CommandSender; 23 | import org.bukkit.command.TabExecutor; 24 | import org.bukkit.entity.Player; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.Sonar; 27 | import xyz.jonesdev.sonar.api.command.InvocationSource; 28 | import xyz.jonesdev.sonar.api.command.SonarCommand; 29 | 30 | import java.util.Collections; 31 | import java.util.List; 32 | 33 | public final class BukkitSonarCommand implements CommandExecutor, TabExecutor, SonarCommand { 34 | 35 | @Override 36 | public boolean onCommand(final CommandSender sender, 37 | final Command command, 38 | final String label, 39 | final String[] args) { 40 | // Create our own invocation source wrapper to handle messages properly 41 | final InvocationSource invocationSource = new InvocationSource( 42 | sender instanceof Player ? ((Player) sender).getUniqueId() : null, 43 | Sonar.get0().sender(sender), 44 | sender::hasPermission); 45 | // Pass the invocation source and command arguments to our command handler 46 | handle(invocationSource, args); 47 | return true; 48 | } 49 | 50 | @Override 51 | public List onTabComplete(final @NotNull CommandSender sender, 52 | final Command command, 53 | final String commandAlias, 54 | final String @NotNull [] args) { 55 | // Do not allow tab completion if the player does not have the required permission 56 | return sender.hasPermission("sonar.command") ? getCachedTabSuggestions(args) : Collections.emptyList(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bungeecord/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.pluginyml.bungee) apply true 3 | } 4 | 5 | bungee { 6 | name = rootProject.name 7 | main = "xyz.jonesdev.sonar.bungee.SonarBungeePlugin" 8 | author = "Jones Development, Sonar Contributors" 9 | softDepends = setOf("Geyser-BungeeCord", "floodgate", "Protocolize", "ViaVersion", "packetevents", "FastLogin") 10 | } 11 | 12 | dependencies { 13 | implementation(project(":api")) 14 | implementation(project(":common")) 15 | 16 | compileOnly(rootProject.libs.bungeecord) 17 | testCompileOnly(rootProject.libs.bungeecord) 18 | 19 | implementation(rootProject.libs.adventure.platform.bungee) { 20 | exclude(module = "adventure-nbt") 21 | } 22 | implementation(rootProject.libs.bstats.bungee) 23 | implementation(rootProject.libs.libby.bungee) 24 | } 25 | 26 | tasks { 27 | shadowJar { 28 | relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori") 29 | 30 | archiveFileName = "Sonar-Bungee.jar" // Hardcode a shortened version of the name 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bungeecord/src/main/java/xyz/jonesdev/sonar/bungee/SonarBungeePlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.bungee; 19 | 20 | import lombok.Getter; 21 | import net.md_5.bungee.api.ProxyServer; 22 | import net.md_5.bungee.api.plugin.Plugin; 23 | 24 | @Getter 25 | public final class SonarBungeePlugin extends Plugin { 26 | private ProxyServer server; 27 | private SonarBungee bootstrap; 28 | 29 | @Override 30 | public void onEnable() { 31 | server = ProxyServer.getInstance(); 32 | 33 | bootstrap = new SonarBungee(this); 34 | bootstrap.initialize(); 35 | } 36 | 37 | @Override 38 | public void onDisable() { 39 | bootstrap.shutdown(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /bungeecord/src/main/java/xyz/jonesdev/sonar/bungee/command/BungeeSonarCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.bungee.command; 19 | 20 | import net.md_5.bungee.api.CommandSender; 21 | import net.md_5.bungee.api.connection.ProxiedPlayer; 22 | import net.md_5.bungee.api.plugin.Command; 23 | import net.md_5.bungee.api.plugin.TabExecutor; 24 | import org.jetbrains.annotations.NotNull; 25 | import xyz.jonesdev.sonar.api.Sonar; 26 | import xyz.jonesdev.sonar.api.command.InvocationSource; 27 | import xyz.jonesdev.sonar.api.command.SonarCommand; 28 | 29 | import java.util.Collections; 30 | 31 | public final class BungeeSonarCommand extends Command implements TabExecutor, SonarCommand { 32 | public BungeeSonarCommand() { 33 | super("sonar"); 34 | } 35 | 36 | @Override 37 | public void execute(final @NotNull CommandSender sender, final String[] args) { 38 | // Create our own invocation source wrapper to handle messages properly 39 | final InvocationSource invocationSource = new InvocationSource( 40 | sender instanceof ProxiedPlayer ? ((ProxiedPlayer) sender).getUniqueId() : null, 41 | Sonar.get0().sender(sender), 42 | sender::hasPermission); 43 | // Pass the invocation source and command arguments to our command handler 44 | handle(invocationSource, args); 45 | } 46 | 47 | @Override 48 | public Iterable onTabComplete(final @NotNull CommandSender sender, final String @NotNull [] args) { 49 | // Do not allow tab completion if the player does not have the required permission 50 | return sender.hasPermission("sonar.command") ? getCachedTabSuggestions(args) : Collections.emptyList(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /captcha/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly(project(":api")) 3 | compileOnly(rootProject.libs.imagefilters) 4 | 5 | testImplementation(project(":api")) 6 | testImplementation(rootProject.libs.imagefilters) 7 | } 8 | -------------------------------------------------------------------------------- /captcha/src/main/java/xyz/jonesdev/sonar/captcha/StandardTTFFontProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.captcha; 19 | 20 | import lombok.experimental.UtilityClass; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | import java.awt.*; 24 | import java.io.InputStream; 25 | import java.util.Objects; 26 | 27 | @UtilityClass 28 | class StandardTTFFontProvider { 29 | private static final String[] FONT_NAMES = {"Kingthings_Trypewriter_2"}; 30 | static final Font[] FONTS = new Font[FONT_NAMES.length]; 31 | static final int STANDARD_FONT_SIZE = 25; 32 | 33 | static { 34 | for (int i = 0; i < FONT_NAMES.length; i++) { 35 | FONTS[i] = loadFont(String.format("/assets/fonts/%s.ttf", FONT_NAMES[i])); 36 | } 37 | } 38 | 39 | private static Font loadFont(final @NotNull String path) { 40 | try (final InputStream inputStream = StandardCaptchaGenerator.class.getResourceAsStream(path)) { 41 | // Load the font from the TTF file 42 | final Font customFont = Font.createFont(Font.TRUETYPE_FONT, Objects.requireNonNull(inputStream)); 43 | // Set the font size and style 44 | return customFont.deriveFont(Font.PLAIN, STANDARD_FONT_SIZE); 45 | } catch (Exception exception) { 46 | throw new IllegalStateException(exception); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /captcha/src/main/java/xyz/jonesdev/sonar/captcha/filters/CurvesOverlayFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.captcha.filters; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.awt.*; 25 | import java.awt.geom.CubicCurve2D; 26 | import java.awt.image.BufferedImage; 27 | import java.util.Random; 28 | 29 | @Getter 30 | @RequiredArgsConstructor 31 | public final class CurvesOverlayFilter { 32 | private final int amount; 33 | 34 | private static final Random RANDOM = new Random(); 35 | 36 | public void transform(final @NotNull BufferedImage image, 37 | final @NotNull Graphics2D graphics) { 38 | // Randomize the stroke width 39 | graphics.setStroke(new BasicStroke(1 + RANDOM.nextFloat())); 40 | 41 | final int halfWidth = image.getWidth() / 2; 42 | 43 | for (int i = 0; i < amount; ++i) { 44 | final float randomX = image.getWidth() * RANDOM.nextFloat(); 45 | final float randomY = image.getHeight() * RANDOM.nextFloat(); 46 | final float amplitude = 6.2831855f * (RANDOM.nextFloat() - 0.5f); 47 | final float sin = (float) Math.sin(amplitude) * halfWidth; 48 | final float cos = (float) Math.cos(amplitude) * halfWidth; 49 | final float x1 = randomX - cos; 50 | final float y1 = randomY - sin; 51 | final float x2 = randomX + cos; 52 | final float y2 = randomY + sin; 53 | // Control points for the cubic curve 54 | final float ctrlX1 = randomX + sin / 2; 55 | final float ctrlY1 = randomY - cos / 2; 56 | final float ctrlX2 = randomX - sin / 2; 57 | final float ctrlY2 = randomY + cos / 2; 58 | // Draw a cubic curve instead of a straight line 59 | graphics.draw(new CubicCurve2D.Float(x1, y1, ctrlX1, ctrlY1, ctrlX2, ctrlY2, x2, y2)); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /captcha/src/main/java/xyz/jonesdev/sonar/captcha/filters/GridOverlayFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.captcha.filters; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.awt.*; 25 | import java.awt.image.BufferedImage; 26 | import java.util.Random; 27 | 28 | @Getter 29 | @RequiredArgsConstructor 30 | public final class GridOverlayFilter { 31 | private final int amount, lineWidth, randomOffset; 32 | 33 | private static final Random RANDOM = new Random(); 34 | 35 | public void transform(final @NotNull BufferedImage image, 36 | final @NotNull Graphics2D graphics) { 37 | final int spacingX = image.getWidth() / amount + lineWidth; 38 | final int spacingY = image.getHeight() / amount + lineWidth; 39 | int currentX = spacingX / 2; 40 | int currentY = spacingY / 2; 41 | 42 | for (int i = 0; i < amount; i++) { 43 | graphics.setStroke(new BasicStroke(lineWidth * 0.5f + lineWidth * RANDOM.nextFloat())); 44 | graphics.drawLine(currentX, 0, currentX + RANDOM.nextInt(randomOffset), image.getHeight()); 45 | graphics.drawLine(0, currentY, image.getWidth(), currentY + RANDOM.nextInt(randomOffset)); 46 | 47 | currentX += spacingX + lineWidth; 48 | currentY += spacingY + lineWidth; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /captcha/src/main/java/xyz/jonesdev/sonar/captcha/filters/NoiseOverlayFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.captcha.filters; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.awt.image.BufferedImage; 25 | import java.util.Random; 26 | 27 | @Getter 28 | @RequiredArgsConstructor 29 | public final class NoiseOverlayFilter { 30 | private final float density, amount; 31 | 32 | private static final Random RANDOM = new Random(); 33 | 34 | private int randomGaussian(int x) { 35 | x += (int) (RANDOM.nextGaussian() * amount); 36 | return Math.max(Math.min(x, 0xff), 0); 37 | } 38 | 39 | public void transform(final @NotNull BufferedImage image) { 40 | for (int x = 0; x < image.getWidth(); x++) { 41 | for (int y = 0; y < image.getHeight(); y++) { 42 | if (RANDOM.nextFloat() <= density) { 43 | final int rgb = image.getRGB(x, y); 44 | int r = (rgb >> 16) & 0xff; 45 | int g = (rgb >> 8) & 0xff; 46 | int b = rgb & 0xff; 47 | r = randomGaussian(r); 48 | g = randomGaussian(g); 49 | b = randomGaussian(b); 50 | image.setRGB(x, y, (r << 16) | (g << 8) | b); 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /captcha/src/main/java/xyz/jonesdev/sonar/captcha/legacy/RippleFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.captcha.legacy; 19 | 20 | import com.jhlabs.image.TransformFilter; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.Setter; 25 | import org.jetbrains.annotations.NotNull; 26 | 27 | @Getter 28 | @Setter 29 | @NoArgsConstructor 30 | @AllArgsConstructor 31 | public final class RippleFilter extends TransformFilter { 32 | private float xAmplitude, yAmplitude; 33 | 34 | @Override 35 | protected void transformInverse(final int x, final int y, final float @NotNull [] out) { 36 | final float nx = (float) y / 13f; 37 | final float ny = (float) x / 13f; 38 | final float fx = (float) Math.sin(nx); 39 | final float fy = (float) Math.sin(ny); 40 | 41 | out[0] = (float) x + xAmplitude * fx; 42 | out[1] = (float) y + yAmplitude * fy; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /captcha/src/main/java/xyz/jonesdev/sonar/captcha/legacy/ScratchFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.captcha.legacy; 19 | 20 | import com.jhlabs.image.AbstractBufferedImageOp; 21 | import lombok.RequiredArgsConstructor; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.awt.*; 25 | import java.awt.image.BufferedImage; 26 | import java.util.Random; 27 | 28 | @RequiredArgsConstructor 29 | public final class ScratchFilter extends AbstractBufferedImageOp { 30 | private static final Random RANDOM = new Random(); 31 | 32 | private final int amount; 33 | 34 | @Override 35 | public @NotNull BufferedImage filter(final @NotNull BufferedImage src, final BufferedImage dst) { 36 | final Graphics2D graphics = src.createGraphics(); 37 | 38 | // Apply some gradient effect on them 39 | final Color color0 = Color.getHSBColor(RANDOM.nextFloat(), RANDOM.nextFloat(), 1); 40 | final Color color1 = new Color(~color0.getRGB()); 41 | final GradientPaint gradient = new GradientPaint(0, 0, color0, src.getWidth(), src.getHeight(), color1); 42 | graphics.setPaint(gradient); 43 | 44 | final float halfWidth = src.getWidth() * 0.5f; 45 | 46 | for (int i = 0; i < amount; ++i) { 47 | final float randomX = src.getWidth() * RANDOM.nextFloat(); 48 | final float randomY = src.getHeight() * RANDOM.nextFloat(); 49 | final float amplitude = 6.2831855f * (RANDOM.nextFloat() - 0.5f); 50 | final float sin = (float) Math.sin(amplitude) * halfWidth; 51 | final float cos = (float) Math.cos(amplitude) * halfWidth; 52 | final float x1 = randomX - cos; 53 | final float y1 = randomY - sin; 54 | final float x2 = randomX + cos; 55 | final float y2 = randomY + sin; 56 | graphics.drawLine((int) x1, (int) y1, (int) x2, (int) y2); 57 | } 58 | 59 | graphics.dispose(); 60 | return src; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /captcha/src/main/resources/assets/fonts/Kingthings_Trypewriter_2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/captcha/src/main/resources/assets/fonts/Kingthings_Trypewriter_2.ttf -------------------------------------------------------------------------------- /captcha/src/test/java/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | import lombok.experimental.UtilityClass; 19 | import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator; 20 | 21 | import javax.imageio.ImageIO; 22 | import java.awt.image.BufferedImage; 23 | import java.io.File; 24 | import java.io.IOException; 25 | import java.util.Random; 26 | 27 | @UtilityClass 28 | public class Main { 29 | public void main(final String... args) throws IOException { 30 | final Random random = new Random(); 31 | final StandardCaptchaGenerator standardCaptchaGenerator = new StandardCaptchaGenerator(null); 32 | 33 | final long start = System.currentTimeMillis(); 34 | final char[] dictionary = {'a', 'b', 'c', 'd', 'e', 'f'/*, 'g'*/, 'h'/*, 'i'*/, 'j', 35 | 'k', 'm', 'n', 'o', 'p'/*, 'q'*/, 'r', 's', 't', 'u'/*, 'v', 'w'*/, 'x', 'y', 'z'}; 36 | 37 | // Generate image 38 | final int amount = 1; 39 | for (int i = 0; i < amount; i++) { 40 | final char[] answer = new char[3 + random.nextInt(2)]; 41 | for (int j = 0; j < answer.length; j++) { 42 | answer[j] = dictionary[random.nextInt(dictionary.length)]; 43 | } 44 | final BufferedImage bufferedImage = standardCaptchaGenerator.createImage(answer); 45 | 46 | // Save image 47 | ImageIO.write(bufferedImage, "png", new File(i + ".png")); 48 | } 49 | System.out.println("Took " + (System.currentTimeMillis() - start) + "ms to generate " + amount + " image(s)"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly(project(":api")) 3 | implementation(project(":captcha")) 4 | compileOnly(rootProject.libs.adventure.nbt) 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/FallbackBandwidthHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelDuplexHandler; 22 | import io.netty.channel.ChannelHandler; 23 | import io.netty.channel.ChannelHandlerContext; 24 | import io.netty.channel.ChannelPromise; 25 | import lombok.AccessLevel; 26 | import lombok.NoArgsConstructor; 27 | import org.jetbrains.annotations.NotNull; 28 | import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics; 29 | 30 | @ChannelHandler.Sharable 31 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 32 | public final class FallbackBandwidthHandler extends ChannelDuplexHandler { 33 | public static final ChannelHandler INSTANCE = new FallbackBandwidthHandler(); 34 | 35 | @Override 36 | public void channelRead(final ChannelHandlerContext ctx, final @NotNull Object msg) throws Exception { 37 | if (msg instanceof ByteBuf) { 38 | // Increment the incoming traffic by the number of readable bytes 39 | final int readableBytes = ((ByteBuf) msg).readableBytes(); 40 | GlobalSonarStatistics.perSecondIncomingTraffic += readableBytes; 41 | } 42 | ctx.fireChannelRead(msg); 43 | } 44 | 45 | @Override 46 | public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) throws Exception { 47 | if (msg instanceof ByteBuf) { 48 | // Increment the outgoing traffic by the number of readable bytes 49 | final int readableBytes = ((ByteBuf) msg).readableBytes(); 50 | GlobalSonarStatistics.perSecondOutgoingTraffic += readableBytes; 51 | } 52 | ctx.write(msg, promise); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackTailExceptionsHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.netty; 19 | 20 | import io.netty.channel.ChannelDuplexHandler; 21 | import io.netty.channel.ChannelHandler; 22 | import io.netty.channel.ChannelHandlerContext; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | @ChannelHandler.Sharable 26 | public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler { 27 | public static final FallbackTailExceptionsHandler INSTANCE = new FallbackTailExceptionsHandler(); 28 | 29 | // We can override the default exceptionCaught method since the server 30 | // does not have any other pipelines that could handle this error. 31 | // Additionally, this will also run after our custom decoder. 32 | @Override 33 | public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception { 34 | // Close the channel if we encounter any errors. 35 | ctx.close(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackTimeoutHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.netty; 19 | 20 | import io.netty.channel.ChannelHandlerContext; 21 | import io.netty.handler.timeout.IdleStateEvent; 22 | import io.netty.handler.timeout.IdleStateHandler; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.util.concurrent.TimeUnit; 26 | 27 | public final class FallbackTimeoutHandler extends IdleStateHandler { 28 | public FallbackTimeoutHandler(final int readTimeout, final int writeTimeout, final TimeUnit timeUnit) { 29 | super(false, readTimeout, writeTimeout, 0L, timeUnit); 30 | } 31 | 32 | @Override 33 | protected void channelIdle(final @NotNull ChannelHandlerContext ctx, 34 | final IdleStateEvent idleStateEvent) throws Exception { 35 | // The netty (default) ReadTimeoutHandler would normally just throw an Exception 36 | // The default ReadTimeoutHandler does only check for the boolean 'closed' and 37 | // still throws the Exception even if the channel is closed 38 | if (ctx.channel().isActive()) { 39 | ctx.close(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/netty/FallbackVarIntLengthEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.netty; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelHandler; 22 | import io.netty.channel.ChannelHandlerContext; 23 | import io.netty.handler.codec.MessageToMessageEncoder; 24 | import org.jetbrains.annotations.NotNull; 25 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 26 | 27 | import java.util.List; 28 | 29 | // https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java 30 | @ChannelHandler.Sharable 31 | public final class FallbackVarIntLengthEncoder extends MessageToMessageEncoder { 32 | public static final FallbackVarIntLengthEncoder INSTANCE = new FallbackVarIntLengthEncoder(); 33 | 34 | @Override 35 | protected void encode(final @NotNull ChannelHandlerContext ctx, 36 | final @NotNull ByteBuf byteBuf, 37 | final @NotNull List out) throws Exception { 38 | final int readableBytes = byteBuf.readableBytes(); 39 | final int length = ProtocolUtil.varIntBytes(readableBytes); 40 | 41 | final ByteBuf lenBuf = ctx.alloc().buffer(length); 42 | 43 | ProtocolUtil.writeVarInt(lenBuf, readableBytes); 44 | out.add(lenBuf); 45 | out.add(byteBuf.retain()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/FallbackPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 22 | 23 | public interface FallbackPacket { 24 | 25 | /** 26 | * Encodes the packet sent by the server 27 | * 28 | * @param byteBuf ByteBuf 29 | * @param protocolVersion Protocol version of the player 30 | */ 31 | void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception; 32 | 33 | /** 34 | * Decodes the packet sent by the client 35 | * 36 | * @param byteBuf ByteBuf 37 | * @param protocolVersion Protocol version of the player 38 | */ 39 | void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception; 40 | 41 | /** 42 | * @param protocolVersion Protocol version of the player 43 | * @return The minimum allowed length of the decoded packet 44 | */ 45 | default int expectedMinLength(final ProtocolVersion protocolVersion) { 46 | return -1; 47 | } 48 | 49 | /** 50 | * @param protocolVersion Protocol version of the player 51 | * @return The maximum allowed length of the decoded packet 52 | */ 53 | default int expectedMaxLength(final ProtocolVersion protocolVersion) { 54 | return -1; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/FallbackPacketEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelHandlerContext; 22 | import io.netty.handler.codec.MessageToByteEncoder; 23 | import lombok.Getter; 24 | import lombok.RequiredArgsConstructor; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 28 | 29 | @RequiredArgsConstructor 30 | public final class FallbackPacketEncoder extends MessageToByteEncoder { 31 | private final ProtocolVersion protocolVersion; 32 | @Getter 33 | private FallbackPacketRegistry packetRegistry; 34 | private FallbackPacketRegistry.ProtocolRegistry protocolRegistry; 35 | 36 | public void updateRegistry(final @NotNull FallbackPacketRegistry packetRegistry) { 37 | this.packetRegistry = packetRegistry; 38 | this.protocolRegistry = packetRegistry.getProtocolRegistry(FallbackPacketRegistry.Direction.CLIENTBOUND, protocolVersion); 39 | } 40 | 41 | @Override 42 | protected void encode(final ChannelHandlerContext ctx, 43 | final @NotNull FallbackPacket packet, 44 | final @NotNull ByteBuf out) throws Exception { 45 | final Class originalPacket = packet instanceof FallbackPacketSnapshot 46 | ? ((FallbackPacketSnapshot) packet).getOriginalPacketClass() : packet.getClass(); 47 | final int packetId = protocolRegistry.getPacketId(originalPacket); 48 | ProtocolUtil.writeVarInt(out, packetId); 49 | packet.encode(out, protocolVersion); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/FallbackPacketListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol; 19 | 20 | import org.jetbrains.annotations.NotNull; 21 | 22 | @FunctionalInterface 23 | public interface FallbackPacketListener { 24 | 25 | /** 26 | * Handles the incoming packet 27 | * 28 | * @param packet Packet to handle 29 | */ 30 | void handle(final @NotNull FallbackPacket packet); 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/block/BlockUpdate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.block; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | @Getter 25 | public final class BlockUpdate { 26 | private final BlockPosition position; 27 | private final BlockType blockType; 28 | private final int legacyBlockState, blockState; 29 | 30 | public BlockUpdate(final @NotNull BlockPosition position, final BlockType blockType) { 31 | this.position = position; 32 | this.blockType = blockType; 33 | final int x = position.getX() - (position.getChunkX() << 4); 34 | final int y = position.getY(); 35 | final int z = position.getZ() - (position.getChunkZ() << 4); 36 | this.legacyBlockState = x << 12 | z << 8 | y; 37 | this.blockState = x << 8 | z << 4 | y - ((y >> 4) << 4); 38 | } 39 | 40 | @Getter 41 | @RequiredArgsConstructor 42 | public static final class BlockPosition { 43 | private final int x, y, z; 44 | private final int chunkX, chunkZ; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/dimension/DimensionType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.dimension; 19 | 20 | import lombok.Getter; 21 | import lombok.RequiredArgsConstructor; 22 | 23 | @Getter 24 | @RequiredArgsConstructor 25 | public enum DimensionType { 26 | OVERWORLD("minecraft:overworld", 0, 0), 27 | @Deprecated 28 | THE_NETHER("minecraft:the_nether", -1, 1), 29 | @Deprecated 30 | THE_END("minecraft:the_end", 1, 2); 31 | 32 | private final String key; 33 | private final int legacyId, id; 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/map/MapCaptchaInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.map; 19 | 20 | import lombok.Getter; 21 | import org.jetbrains.annotations.NotNull; 22 | import xyz.jonesdev.sonar.api.fallback.FallbackUser; 23 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 24 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 25 | import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.MapDataPacket; 26 | 27 | @Getter 28 | public final class MapCaptchaInfo { 29 | private final String answer; 30 | 31 | private final FallbackPacket[] legacy; 32 | private final FallbackPacket modern; 33 | 34 | public MapCaptchaInfo(final @NotNull String answer, final byte @NotNull [] buffer) { 35 | this.answer = answer; 36 | 37 | // Prepare 1.7 map data using a grid 38 | final byte[][] grid = new byte[128][128]; 39 | for (int i = 0; i < buffer.length; i++) { 40 | grid[i & Byte.MAX_VALUE][i >> 7] = buffer[i]; 41 | } 42 | this.legacy = new FallbackPacket[grid.length]; 43 | for (int i = 0; i < grid.length; i++) { 44 | this.legacy[i] = new MapDataPacket(grid[i], i, 0, 0, true); 45 | } 46 | 47 | // Prepare 1.8+ map data 48 | this.modern = new MapDataPacket(buffer, 0, 0, 0, true); 49 | } 50 | 51 | public void delayedWrite(final @NotNull FallbackUser user) { 52 | if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_8)) { 53 | // 1.7.2-1.7.10 needs separate packets for each axis 54 | for (final FallbackPacket packet : legacy) { 55 | user.delayedWrite(packet); 56 | } 57 | return; 58 | } 59 | user.delayedWrite(modern); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/configuration/FinishConfigurationPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AccessLevel; 22 | import lombok.NoArgsConstructor; 23 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 24 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 25 | 26 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 27 | public final class FinishConfigurationPacket implements FallbackPacket { 28 | public static final FinishConfigurationPacket INSTANCE = new FinishConfigurationPacket(); 29 | 30 | @Override 31 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 32 | } 33 | 34 | @Override 35 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 36 | } 37 | 38 | @Override 39 | public int expectedMaxLength(final ProtocolVersion protocolVersion) { 40 | // This packet is always empty; see https://wiki.vg/Protocol#Finish_Configuration 41 | return 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/handshake/HandshakePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.Getter; 22 | import lombok.ToString; 23 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 24 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 25 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 26 | 27 | @Getter 28 | @ToString(of = {"protocolVersionId", "hostname", "port"}) 29 | public final class HandshakePacket implements FallbackPacket { 30 | private int protocolVersionId; 31 | private String hostname; 32 | private int port; 33 | private int intent; 34 | 35 | private static final String FORGE_TOKEN = "\0FML\0"; 36 | private static final int MAXIMUM_HOSTNAME_LENGTH = 255 + FORGE_TOKEN.length() + 1; 37 | 38 | // https://wiki.vg/Protocol#Handshaking 39 | public static final int STATUS = 1; 40 | public static final int LOGIN = 2; 41 | public static final int TRANSFER = 3; 42 | 43 | @Override 44 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 45 | throw new UnsupportedOperationException(); 46 | } 47 | 48 | @Override 49 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 50 | protocolVersionId = ProtocolUtil.readVarInt(byteBuf); 51 | hostname = ProtocolUtil.readString(byteBuf, MAXIMUM_HOSTNAME_LENGTH); 52 | port = byteBuf.readUnsignedShort(); 53 | intent = ProtocolUtil.readVarInt(byteBuf); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/login/LoginAcknowledgedPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.login; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 22 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 23 | 24 | public final class LoginAcknowledgedPacket implements FallbackPacket { 25 | 26 | @Override 27 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | @Override 32 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 33 | } 34 | 35 | @Override 36 | public int expectedMaxLength(final ProtocolVersion protocolVersion) { 37 | // This packet is always empty; see https://wiki.vg/Protocol#Login_Acknowledged 38 | return 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/ClientTickEndPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 22 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 23 | 24 | public final class ClientTickEndPacket implements FallbackPacket { 25 | 26 | @Override 27 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 28 | throw new UnsupportedOperationException(); 29 | } 30 | 31 | @Override 32 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 33 | } 34 | 35 | @Override 36 | public int expectedMaxLength(final ProtocolVersion protocolVersion) { 37 | // This packet is always empty 38 | return 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/ConfirmTeleportationPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 26 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 27 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class ConfirmTeleportationPacket implements FallbackPacket { 34 | private int teleportId; 35 | 36 | @Override 37 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 38 | throw new UnsupportedOperationException(); 39 | } 40 | 41 | @Override 42 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 43 | teleportId = ProtocolUtil.readVarInt(byteBuf); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/DisconnectPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import net.kyori.adventure.text.Component; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ComponentHolder; 29 | 30 | @Getter 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class DisconnectPacket implements FallbackPacket { 34 | private @NotNull ComponentHolder componentHolder; 35 | private boolean duringLogin; 36 | 37 | public DisconnectPacket(final @NotNull Component component, final boolean duringLogin) { 38 | this.componentHolder = new ComponentHolder(component); 39 | this.duringLogin = duringLogin; 40 | } 41 | 42 | @Override 43 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 44 | // Force JSON serialization during login phase 45 | componentHolder.write(byteBuf, protocolVersion, duringLogin); 46 | } 47 | 48 | @Override 49 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 50 | throw new UnsupportedOperationException(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/EntityAnimationPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.Setter; 25 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 26 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 27 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 28 | 29 | @Getter 30 | @Setter 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class EntityAnimationPacket implements FallbackPacket { 34 | private int entityId; 35 | private Type type; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 39 | ProtocolUtil.writeVarInt(byteBuf, entityId); 40 | byteBuf.writeByte(type.ordinal()); 41 | } 42 | 43 | @Override 44 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 45 | throw new UnsupportedOperationException(); 46 | } 47 | 48 | public enum Type { 49 | SWING_MAIN_ARM, 50 | HURT, 51 | WAKE_UP, 52 | // 1.9+? 53 | SWING_OFF_HAND, // Eat food on 1.7 54 | CRITICAL_HIT, 55 | MAGIC_CRITICAL_HIT 56 | // unknown (102), crouch (104), uncrouch(105) only exist on 1.7 and unused here 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/GameEventPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Data; 23 | import lombok.NoArgsConstructor; 24 | import org.jetbrains.annotations.NotNull; 25 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 26 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 27 | 28 | @Data 29 | @NoArgsConstructor 30 | @AllArgsConstructor 31 | public final class GameEventPacket implements FallbackPacket { 32 | private int type; 33 | private float value; 34 | 35 | @Override 36 | public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 37 | byteBuf.writeByte(type); 38 | byteBuf.writeFloat(value); 39 | } 40 | 41 | @Override 42 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 43 | throw new UnsupportedOperationException(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/KeepAlivePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 29 | 30 | @Getter 31 | @ToString 32 | @NoArgsConstructor 33 | @AllArgsConstructor 34 | public final class KeepAlivePacket implements FallbackPacket { 35 | private long id; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 39 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_12_2)) { 40 | byteBuf.writeLong(id); 41 | } else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_8)) { 42 | ProtocolUtil.writeVarInt(byteBuf, (int) id); 43 | } else { 44 | byteBuf.writeInt((int) id); 45 | } 46 | } 47 | 48 | @Override 49 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 50 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_12_2)) { 51 | id = byteBuf.readLong(); 52 | } else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_8)) { 53 | id = ProtocolUtil.readVarInt(byteBuf); 54 | } else { 55 | id = byteBuf.readInt(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/PaddleBoatPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class PaddleBoatPacket implements FallbackPacket { 34 | private boolean leftPaddle, rightPaddle; 35 | 36 | @Override 37 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 38 | throw new UnsupportedOperationException(); 39 | } 40 | 41 | @Override 42 | public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 43 | leftPaddle = byteBuf.readBoolean(); 44 | rightPaddle = byteBuf.readBoolean(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/PlayerAbilitiesPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class PlayerAbilitiesPacket implements FallbackPacket { 34 | private int encodedFlags; 35 | private float flySpeed, walkSpeed; 36 | 37 | @Override 38 | public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 39 | byteBuf.writeByte(encodedFlags); 40 | byteBuf.writeFloat(flySpeed); 41 | byteBuf.writeFloat(walkSpeed); 42 | } 43 | 44 | @Override 45 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 46 | throw new UnsupportedOperationException(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/PlayerInputPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class PlayerInputPacket implements FallbackPacket { 34 | private float sideways, forward; 35 | private boolean jump, sneak; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 39 | throw new UnsupportedOperationException(); 40 | } 41 | 42 | @Override 43 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 44 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) { 45 | final byte mask = byteBuf.readByte(); 46 | jump = (mask & 16) != 0; 47 | sneak = (mask & 32) != 0; 48 | return; 49 | } 50 | 51 | sideways = byteBuf.readFloat(); 52 | forward = byteBuf.readFloat(); 53 | 54 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) { 55 | jump = byteBuf.readBoolean(); 56 | sneak = byteBuf.readBoolean(); 57 | } else { 58 | final byte flags = byteBuf.readByte(); 59 | jump = (flags & 0x01) != 0; 60 | sneak = (flags & 0x02) != 0; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/PluginMessagePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.Getter; 22 | import lombok.ToString; 23 | import org.jetbrains.annotations.NotNull; 24 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 25 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 26 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 27 | import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException; 28 | 29 | @Getter 30 | @ToString 31 | public final class PluginMessagePacket implements FallbackPacket { 32 | private String channel; 33 | private byte[] data; 34 | 35 | private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 39 | throw new UnsupportedOperationException(); 40 | } 41 | 42 | @Override 43 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 44 | channel = ProtocolUtil.readString(byteBuf, 48); 45 | 46 | final int length; 47 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_8)) { 48 | length = byteBuf.readableBytes(); 49 | if (length > Short.MAX_VALUE) { 50 | throw QuietDecoderException.INSTANCE; 51 | } 52 | } else { 53 | length = ProtocolUtil.readExtendedForgeShort(byteBuf); 54 | if (length > FORGE_MAX_ARRAY_LENGTH) { 55 | throw QuietDecoderException.INSTANCE; 56 | } 57 | } 58 | 59 | data = new byte[length]; 60 | byteBuf.readBytes(data); 61 | } 62 | 63 | @Override 64 | public int expectedMinLength(final ProtocolVersion protocolVersion) { 65 | return 4; 66 | } 67 | 68 | @Override 69 | public int expectedMaxLength(final ProtocolVersion protocolVersion) { 70 | return Short.MAX_VALUE; // vanilla size limit 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/RemoveEntitiesPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 29 | 30 | @Getter 31 | @ToString 32 | @NoArgsConstructor 33 | @AllArgsConstructor 34 | public final class RemoveEntitiesPacket implements FallbackPacket { 35 | private int entityId; // We only need one entityId 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 39 | // No idea why Mojang decided that this is a good idea, but whatever 40 | if (!protocolVersion.equals(ProtocolVersion.MINECRAFT_1_17)) { 41 | ProtocolUtil.writeVarInt(byteBuf, 1); // size 42 | } 43 | 44 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) { 45 | byteBuf.writeInt(entityId); 46 | } else { 47 | ProtocolUtil.writeVarInt(byteBuf, entityId); 48 | } 49 | } 50 | 51 | @Override 52 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) { 53 | throw new UnsupportedOperationException(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetDefaultSpawnPositionPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class SetDefaultSpawnPositionPacket implements FallbackPacket { 34 | private int x, y, z; 35 | 36 | @Override 37 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 38 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) { 39 | byteBuf.writeInt(x); 40 | byteBuf.writeInt(y); 41 | byteBuf.writeInt(z); 42 | } else { 43 | final long encoded = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_14) 44 | ? ((x & 0x3FFFFFFL) << 38) | ((y & 0xFFFL) << 26) | (z & 0x3FFFFFFL) 45 | : ((x & 0x3FFFFFFL) << 38) | ((y & 0x3FFFFFFL) << 12) | (z & 0xFFFL); 46 | 47 | byteBuf.writeLong(encoded); 48 | 49 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_17)) { 50 | byteBuf.writeFloat(0f); 51 | } 52 | } 53 | } 54 | 55 | @Override 56 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 57 | throw new UnsupportedOperationException(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetExperiencePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 29 | 30 | @Getter 31 | @ToString 32 | @NoArgsConstructor 33 | @AllArgsConstructor 34 | public final class SetExperiencePacket implements FallbackPacket { 35 | private float experienceBar; 36 | private int level; 37 | private int totalExperience; 38 | 39 | @Override 40 | public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 41 | byteBuf.writeFloat(experienceBar); 42 | 43 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) { 44 | byteBuf.writeShort(level); 45 | byteBuf.writeShort(totalExperience); 46 | return; 47 | } 48 | 49 | ProtocolUtil.writeVarInt(byteBuf, level); 50 | ProtocolUtil.writeVarInt(byteBuf, totalExperience); 51 | } 52 | 53 | @Override 54 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 55 | throw new UnsupportedOperationException(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetHeldItemPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 29 | 30 | @Getter 31 | @ToString 32 | @NoArgsConstructor 33 | @AllArgsConstructor 34 | public final class SetHeldItemPacket implements FallbackPacket { 35 | private int slot; 36 | 37 | @Override 38 | public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 39 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_4)) { 40 | ProtocolUtil.writeVarInt(byteBuf, slot); 41 | } else { 42 | byteBuf.writeByte(slot); 43 | } 44 | } 45 | 46 | @Override 47 | public void decode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 48 | slot = byteBuf.readShort(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetPassengersPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 29 | 30 | @Getter 31 | @ToString 32 | @NoArgsConstructor 33 | @AllArgsConstructor 34 | public final class SetPassengersPacket implements FallbackPacket { 35 | private int entityId, passengerId; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 39 | // You can find this in the EntityAttach packet, 40 | // which was later replaced by SetPassengers in 1.9+ 41 | if (protocolVersion.lessThanOrEquals(ProtocolVersion.MINECRAFT_1_8)) { 42 | byteBuf.writeInt(passengerId); 43 | byteBuf.writeInt(entityId); 44 | byteBuf.writeByte(0); // leash 45 | return; 46 | } 47 | 48 | ProtocolUtil.writeVarInt(byteBuf, entityId); 49 | ProtocolUtil.writeVarInt(byteBuf, 1); // passenger count 50 | ProtocolUtil.writeVarInt(byteBuf, passengerId); 51 | } 52 | 53 | @Override 54 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) { 55 | throw new UnsupportedOperationException(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetPlayerOnGround.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class SetPlayerOnGround implements FallbackPacket { 34 | private boolean onGround, horizontalCollision; 35 | 36 | @Override 37 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 38 | throw new UnsupportedOperationException(); 39 | } 40 | 41 | @Override 42 | public void decode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 43 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) { 44 | final short flag = byteBuf.readUnsignedByte(); 45 | onGround = (flag & 1) != 0; 46 | horizontalCollision = (flag & 2) != 0; 47 | } else { 48 | onGround = byteBuf.readBoolean(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetPlayerPositionPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class SetPlayerPositionPacket implements FallbackPacket { 34 | private double x, y, z; 35 | private boolean onGround, horizontalCollision; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 39 | throw new UnsupportedOperationException(); 40 | } 41 | 42 | @Override 43 | public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 44 | x = byteBuf.readDouble(); 45 | y = byteBuf.readDouble(); 46 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) { 47 | // 1.7.2-1.7.10 send the minimum bounding box Y coordinate 48 | byteBuf.readDouble(); 49 | } 50 | z = byteBuf.readDouble(); 51 | if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_21_2)) { 52 | short flag = byteBuf.readUnsignedByte(); 53 | onGround = (flag & 1) != 0; 54 | horizontalCollision = (flag & 2) != 0; 55 | } else { 56 | onGround = byteBuf.readBoolean(); 57 | } 58 | } 59 | 60 | @Override 61 | public int expectedMaxLength(final @NotNull ProtocolVersion protocolVersion) { 62 | return protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8) ? 33 : 25; 63 | } 64 | 65 | @Override 66 | public int expectedMinLength(final ProtocolVersion protocolVersion) { 67 | return 25; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/SetPlayerRotationPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class SetPlayerRotationPacket implements FallbackPacket { 34 | private float yaw, pitch; 35 | private boolean onGround, horizontalCollision; 36 | 37 | @Override 38 | public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 39 | throw new UnsupportedOperationException(); 40 | } 41 | 42 | @Override 43 | public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 44 | yaw = byteBuf.readFloat(); 45 | pitch = byteBuf.readFloat(); 46 | if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_21_2)) { 47 | short flag = byteBuf.readUnsignedByte(); 48 | onGround = (flag & 1) != 0; 49 | horizontalCollision = (flag & 2) != 0; 50 | } else { 51 | onGround = byteBuf.readBoolean(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/TransactionPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class TransactionPacket implements FallbackPacket { 34 | private int windowId, transactionId; 35 | private boolean accepted; 36 | 37 | @Override 38 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 39 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_17)) { 40 | windowId = byteBuf.readByte(); 41 | transactionId = byteBuf.readShort(); 42 | accepted = byteBuf.readBoolean(); 43 | } else { 44 | transactionId = byteBuf.readInt(); 45 | // Always set accepted to true since 1.17 or higher don't use 46 | // transactions for inventory confirmation anymore. 47 | accepted = true; 48 | } 49 | } 50 | 51 | @Override 52 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 53 | if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_17)) { 54 | byteBuf.writeByte(windowId); 55 | byteBuf.writeShort((short) transactionId); 56 | byteBuf.writeBoolean(accepted); 57 | } else { 58 | byteBuf.writeInt(transactionId); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/TransferPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | import xyz.jonesdev.sonar.common.util.ProtocolUtil; 29 | 30 | @Getter 31 | @ToString 32 | @NoArgsConstructor 33 | @AllArgsConstructor 34 | public final class TransferPacket implements FallbackPacket { 35 | private String destinationHost; 36 | private int destinationPort; 37 | 38 | @Override 39 | public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 40 | ProtocolUtil.writeString(byteBuf, destinationHost); 41 | ProtocolUtil.writeVarInt(byteBuf, destinationPort); 42 | } 43 | 44 | @Override 45 | public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) { 46 | throw new UnsupportedOperationException(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/UpdateTimePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import org.jetbrains.annotations.NotNull; 25 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 26 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 27 | 28 | @Getter 29 | @NoArgsConstructor 30 | @AllArgsConstructor 31 | public final class UpdateTimePacket implements FallbackPacket { 32 | private long worldAge, timeOfDay; 33 | private boolean tickDayTime; 34 | 35 | @Override 36 | public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) { 37 | byteBuf.writeLong(worldAge); 38 | byteBuf.writeLong(timeOfDay); 39 | 40 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) { 41 | byteBuf.writeBoolean(tickDayTime); 42 | } 43 | } 44 | 45 | @Override 46 | public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) { 47 | throw new UnsupportedOperationException(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/protocol/packets/play/VehicleMovePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.protocol.packets.play; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.NoArgsConstructor; 24 | import lombok.ToString; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion; 27 | import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket; 28 | 29 | @Getter 30 | @ToString 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public final class VehicleMovePacket implements FallbackPacket { 34 | private double x, y, z; 35 | private float yaw, pitch; 36 | private boolean onGround; 37 | 38 | @Override 39 | public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception { 40 | throw new UnsupportedOperationException(); 41 | } 42 | 43 | @Override 44 | public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception { 45 | x = byteBuf.readDouble(); 46 | y = byteBuf.readDouble(); 47 | z = byteBuf.readDouble(); 48 | yaw = byteBuf.readFloat(); 49 | pitch = byteBuf.readFloat(); 50 | if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_4)) { 51 | onGround = byteBuf.readBoolean(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/ratelimit/CaffeineCacheRatelimiter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.ratelimit; 19 | 20 | import com.github.benmanes.caffeine.cache.Cache; 21 | import com.github.benmanes.caffeine.cache.Caffeine; 22 | import com.github.benmanes.caffeine.cache.Ticker; 23 | import lombok.RequiredArgsConstructor; 24 | import lombok.Setter; 25 | import org.jetbrains.annotations.NotNull; 26 | import xyz.jonesdev.sonar.api.fallback.ratelimit.Ratelimiter; 27 | 28 | import java.net.InetAddress; 29 | import java.time.Duration; 30 | 31 | // Idea taken from Velocity 32 | @Setter 33 | @RequiredArgsConstructor 34 | public final class CaffeineCacheRatelimiter implements Ratelimiter { 35 | private long timeout; 36 | private Cache expiringCache; 37 | 38 | public CaffeineCacheRatelimiter(final @NotNull Duration duration) { 39 | this.timeout = duration.toNanos(); 40 | this.expiringCache = Caffeine.newBuilder() 41 | .ticker(Ticker.systemTicker()) 42 | .expireAfterWrite(duration) 43 | .build(); 44 | } 45 | 46 | @Override 47 | public boolean attempt(final @NotNull InetAddress inetAddress) { 48 | final long expectedNewTimestamp = System.nanoTime() + timeout; 49 | final long last = expiringCache.get(inetAddress, result -> expectedNewTimestamp); 50 | return expectedNewTimestamp == last; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/fallback/ratelimit/NoopCacheRatelimiter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.fallback.ratelimit; 19 | 20 | import lombok.AccessLevel; 21 | import lombok.NoArgsConstructor; 22 | import org.jetbrains.annotations.NotNull; 23 | import xyz.jonesdev.sonar.api.fallback.ratelimit.Ratelimiter; 24 | 25 | import java.net.InetAddress; 26 | 27 | // Idea taken from Velocity 28 | @NoArgsConstructor(access = AccessLevel.PRIVATE) 29 | public final class NoopCacheRatelimiter implements Ratelimiter { 30 | public static final NoopCacheRatelimiter INSTANCE = new NoopCacheRatelimiter(); 31 | 32 | @Override 33 | public boolean attempt(final @NotNull InetAddress inetAddress) { 34 | // Accept all connections 35 | return true; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/subcommand/NotifyCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.subcommand; 19 | 20 | import net.kyori.adventure.text.minimessage.MiniMessage; 21 | import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; 22 | import org.jetbrains.annotations.NotNull; 23 | import xyz.jonesdev.sonar.api.Sonar; 24 | import xyz.jonesdev.sonar.api.command.InvocationSource; 25 | import xyz.jonesdev.sonar.api.command.subcommand.Subcommand; 26 | import xyz.jonesdev.sonar.api.command.subcommand.SubcommandInfo; 27 | 28 | @SubcommandInfo( 29 | name = "notify", 30 | onlyPlayers = true 31 | ) 32 | public final class NotifyCommand extends Subcommand { 33 | 34 | @Override 35 | protected void execute(final @NotNull InvocationSource source, final String @NotNull [] args) { 36 | if (Sonar.get0().getChatNotificationHandler().isSubscribed(source.getUuid())) { 37 | Sonar.get0().getChatNotificationHandler().unsubscribe(source.getUuid()); 38 | source.sendMessage(MiniMessage.miniMessage().deserialize( 39 | Sonar.get0().getConfig().getMessagesConfig().getString("commands.notify.unsubscribe"), 40 | Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()))); 41 | return; 42 | } 43 | 44 | Sonar.get0().getChatNotificationHandler().subscribe(source.getUuid()); 45 | source.sendMessage(MiniMessage.miniMessage().deserialize( 46 | Sonar.get0().getConfig().getMessagesConfig().getString("commands.notify.subscribe"), 47 | Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/subcommand/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.subcommand; 19 | 20 | import net.kyori.adventure.text.minimessage.MiniMessage; 21 | import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; 22 | import org.jetbrains.annotations.NotNull; 23 | import xyz.jonesdev.sonar.api.Sonar; 24 | import xyz.jonesdev.sonar.api.command.InvocationSource; 25 | import xyz.jonesdev.sonar.api.command.subcommand.Subcommand; 26 | import xyz.jonesdev.sonar.api.command.subcommand.SubcommandInfo; 27 | import xyz.jonesdev.sonar.api.timer.SystemTimer; 28 | 29 | @SubcommandInfo( 30 | name = "reload" 31 | ) 32 | public final class ReloadCommand extends Subcommand { 33 | 34 | @Override 35 | protected void execute(final @NotNull InvocationSource source, final String @NotNull [] args) { 36 | source.sendMessage(MiniMessage.miniMessage().deserialize( 37 | Sonar.get0().getConfig().getMessagesConfig().getString("commands.reload.start"), 38 | Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()))); 39 | 40 | final SystemTimer timer = new SystemTimer(); 41 | 42 | Sonar.get0().reload(); 43 | 44 | source.sendMessage(MiniMessage.miniMessage().deserialize( 45 | Sonar.get0().getConfig().getMessagesConfig().getString("commands.reload.finish"), 46 | Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()), 47 | Placeholder.unparsed("time-taken", String.valueOf(timer.delay())))); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/subcommand/VerboseCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.subcommand; 19 | 20 | import net.kyori.adventure.text.Component; 21 | import net.kyori.adventure.text.minimessage.MiniMessage; 22 | import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; 23 | import org.jetbrains.annotations.NotNull; 24 | import xyz.jonesdev.sonar.api.Sonar; 25 | import xyz.jonesdev.sonar.api.command.InvocationSource; 26 | import xyz.jonesdev.sonar.api.command.subcommand.Subcommand; 27 | import xyz.jonesdev.sonar.api.command.subcommand.SubcommandInfo; 28 | 29 | @SubcommandInfo( 30 | name = "verbose", 31 | onlyPlayers = true 32 | ) 33 | public final class VerboseCommand extends Subcommand { 34 | 35 | @Override 36 | protected void execute(final @NotNull InvocationSource source, final String @NotNull [] args) { 37 | if (Sonar.get0().getActionBarNotificationHandler().isSubscribed(source.getUuid())) { 38 | Sonar.get0().getActionBarNotificationHandler().unsubscribe(source.getUuid()); 39 | // Reset ActionBar component when unsubscribing 40 | source.getAudience().sendActionBar(Component.empty()); 41 | source.sendMessage(MiniMessage.miniMessage().deserialize( 42 | Sonar.get0().getConfig().getMessagesConfig().getString("commands.verbose.unsubscribe"), 43 | Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()))); 44 | return; 45 | } 46 | 47 | Sonar.get0().getActionBarNotificationHandler().subscribe(source.getUuid()); 48 | source.sendMessage(MiniMessage.miniMessage().deserialize( 49 | Sonar.get0().getConfig().getMessagesConfig().getString("commands.verbose.subscribe"), 50 | Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()))); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/util/FakeChannelUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.util; 19 | 20 | import io.netty.channel.Channel; 21 | import lombok.experimental.UtilityClass; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | // https://github.com/retrooper/packetevents/blob/2.0/api/src/main/java/com/github/retrooper/packetevents/util/FakeChannelUtil.java 25 | @UtilityClass 26 | public class FakeChannelUtil { 27 | 28 | /** 29 | * Checks if the provided channel is a fake channel, typically used by player spoofing plugins. 30 | * 31 | * @param channel The channel to be checked. 32 | * @return true if the channel is identified as a fake channel 33 | */ 34 | public boolean isFakeChannel(final @NotNull Channel channel) { 35 | final String simpleClassName = channel.getClass().getSimpleName(); 36 | // Player spoof plugins use fake channels (e.g., Spoof Engine uses "FakeChannel") 37 | return "FakeChannel".equals(simpleClassName) 38 | || "SpoofedChannel".equals(simpleClassName) 39 | || "EmbeddedChannel".equals(simpleClassName); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/util/GeyserUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.util; 19 | 20 | import io.netty.channel.Channel; 21 | import io.netty.util.AttributeKey; 22 | import lombok.experimental.UtilityClass; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.net.InetSocketAddress; 26 | 27 | @UtilityClass 28 | public class GeyserUtil { 29 | // https://github.com/GeyserMC/Floodgate/blob/master/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java#L206 30 | private final AttributeKey PLAYER_ATTRIBUTE = AttributeKey.valueOf("floodgate-player"); 31 | 32 | public boolean isGeyserConnection(final @NotNull Channel channel, final @NotNull InetSocketAddress originalAddress) { 33 | /* 34 | * This method performs two checks: 35 | * 1. It checks if the player is joining through Floodgate, which is installed on the server. 36 | * 2. It checks if the player is joining through a Floodgate proxy hosted externally. 37 | */ 38 | return originalAddress.getPort() == 0 || channel.attr(PLAYER_ATTRIBUTE).get() != null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/util/exception/QuietDecoderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.util.exception; 19 | 20 | import io.netty.handler.codec.DecoderException; 21 | 22 | public final class QuietDecoderException extends DecoderException { 23 | public static final QuietDecoderException INSTANCE = new QuietDecoderException(); 24 | 25 | @Override 26 | public Throwable fillInStackTrace() { 27 | return this; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /common/src/main/java/xyz/jonesdev/sonar/common/util/exception/ReflectiveOperationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.common.util.exception; 19 | 20 | import xyz.jonesdev.sonar.api.Sonar; 21 | 22 | public final class ReflectiveOperationException extends RuntimeException { 23 | public ReflectiveOperationException(final Throwable throwable) { 24 | super(throwable); 25 | 26 | Sonar.get0().getLogger().error("A reflective operation resulted in error:"); 27 | throwable.printStackTrace(System.err); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_16.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_16.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_16_2.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_16_2.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_18_2.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_18_2.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_19.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_19.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_19_1.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_19_1.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_19_4.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_19_4.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_20.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_20.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_20_5.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_20_5.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_21.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_21.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_21_2.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_21_2.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_21_4.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_21_4.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/codecs/codec_1_21_5.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/common/src/main/resources/assets/codecs/codec_1_21_5.nbt -------------------------------------------------------------------------------- /common/src/main/resources/assets/language.properties: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Need help or have questions? https://jonesdev.xyz/discord 12 | # Source code: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, licensed under GPL-3.0 14 | # 15 | 16 | # Which language should Sonar use for all configurations? 17 | # For this to take effect, restart your server or reload Sonar. 18 | # 19 | # Values will not be translated if you change your language 20 | # when all configuration files already exist. 21 | # If you still want all configuration files to be translated, 22 | # you have to reset the configuration, messages, and webhook settings. 23 | # 24 | # You can view a full list of existing translations here: 25 | # https://docs.jonesdev.xyz/sonar/translations 26 | # If a translation does not exist yet, Sonar will use English (en) 27 | # 28 | # If you set this option to "system", Sonar will use the system language. 29 | language=system 30 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/cs.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Potřebujete pomoc nebo máte otázky? https://jonesdev.xyz/discord 12 | # Zdrojový kód: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, licencováno pod GPL-3.0 14 | # 15 | 16 | # Notifikace útoků můžou být poslány na discord server pomocí webhooků 17 | webhook: 18 | # URL Discord webhooku (Ponechejte '' pro žádné webhooky) 19 | url: '' 20 | # Jméno discord webhooku 21 | username: Sonar 22 | # URL pro avatara discord webhooku (Ponechejte na '' pro žádného) 23 | avatar-url: '' 24 | # Obsah zprávy webhooku (Ponechte na '' pro žadnou) 25 | # Můžete to použít k např. upozorvování členů staff týmu pomocí <@userId> 26 | # Pokuď budete chtít upozornit role, budete muset použít <@&roleId> 27 | content: '' 28 | # Přidejte zprávu pro webhook, kterou ma poslat když skončil útok 29 | embed: 30 | # Malé zápatí pro poslanou zprávu webhookem 31 | footer: 32 | # Obsah zápatí kterou discord webhooku 33 | text: © Jones Development and Sonar Contributors 34 | # URL ikony zápatí zprávy 35 | icon-url: '' 36 | # Nadpis discord webhook zprávy 37 | title: ':white_check_mark: Útok zahájen' 38 | # URL, na kterou se bude moct na webhook zprávě kliknout 39 | title-url: '' 40 | # Popisek (kontext) discord webhook zprávy 41 | description: 42 | - Útok na váš server byl ukončen!. 43 | - '' 44 | - 'Začátek útoku: :T>' 45 | - 'Konec útoku: :T>' 46 | - 'Délka útoku: ' 47 | - '' 48 | - 'Nejvyšší využití CPU při útoku: %' 49 | - 'Nejvyšší využití paměti při útoku: ' 50 | - 'Nejvyšší počet botů za sekundu při útoku: ' 51 | - '' 52 | - 'IP přidány na černou listinu: ' 53 | - 'Nepovedené verifikace při útoku: ' 54 | - 'Povedené verifikace při útoku: ' 55 | # RGB barvy discord webhook zprávy 56 | # Barvy: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/en.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Need help or have questions? https://jonesdev.xyz/discord 12 | # Source code: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, licensed under GPL-3.0 14 | # 15 | 16 | # Bot attack notifications can also be sent to your Discord server using webhooks 17 | webhook: 18 | # URL of the Discord webhook (Set this to '' to disable webhooks) 19 | url: '' 20 | # Username of the Discord webhook sender 21 | username: Sonar 22 | # URL to the avatar of the Discord webhook sender (Set this to '' to disable) 23 | avatar-url: '' 24 | # Content of the Discord webhook message (Set this to '' to disable) 25 | # You can use this to e.g. ping staff members using <@userId> 26 | # If you want to ping roles, you will need to use <@&roleId> 27 | content: '' 28 | # Embed Discord webhook message that is sent when an attack has stopped 29 | embed: 30 | # Small footer message of the Discord webhook embed 31 | footer: 32 | # Content of the footer message of the Discord webhook embed 33 | text: © Jones Development and Sonar Contributors 34 | # URL of the footer message icon of the Discord webhook embed 35 | icon-url: '' 36 | # Title of the Discord webhook embed 37 | title: ':white_check_mark: Attack mitigated' 38 | # Clickable URL of the title of the Discord webhook embed 39 | title-url: '' 40 | # Description (content) of the Discord webhook embed 41 | description: 42 | - The attack on your server has been mitigated. 43 | - '' 44 | - 'Attack start: :T>' 45 | - 'Attack end: :T>' 46 | - 'Attack duration: ' 47 | - '' 48 | - 'Peak process CPU usage during the attack: %' 49 | - 'Peak process memory usage during the attack: ' 50 | - 'Peak bots per second during the attack: ' 51 | - '' 52 | - 'Blacklisted IP addresses during the attack: ' 53 | - 'Failed verifications during the attack: ' 54 | - 'Successful verifications during the attack: ' 55 | # RGB colors of the Discord webhook embed 56 | # Color picker: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/es.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # ¿Necesita ayuda o tiene alguna pregunta? https://jonesdev.xyz/discord 12 | # Código fuente: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, bajo licencia GPL-3.0 14 | # 15 | 16 | # Bot attack notifications can also be sent to your Discord server using webhooks 17 | webhook: 18 | # URL of the Discord webhook (Set this to '' to disable webhooks) 19 | url: '' 20 | # Username of the Discord webhook sender 21 | username: Sonar 22 | # URL to the avatar of the Discord webhook sender (Set this to '' to disable) 23 | avatar-url: '' 24 | # Content of the Discord webhook message (Set this to '' to disable) 25 | # You can use this to e.g. ping staff members using <@userId> 26 | # If you want to ping roles, you will need to use <@&roleId> 27 | content: '' 28 | # Embed Discord webhook message that is sent when an attack has stopped 29 | embed: 30 | # Small footer message of the Discord webhook embed 31 | footer: 32 | # Content of the footer message of the Discord webhook embed 33 | text: © Jones Development and Sonar Contributors 34 | # URL of the footer message icon of the Discord webhook embed 35 | icon-url: '' 36 | # Title of the Discord webhook embed 37 | title: ':white_check_mark: Ataque mitigado' 38 | # Clickable URL of the title of the Discord webhook embed 39 | title-url: '' 40 | # Description (content) of the Discord webhook embed 41 | description: 42 | - El ataque a su servidor ha sido mitigado. 43 | - '' 44 | - 'Inicio del ataque: :T>' 45 | - 'Fin del ataque: :T>' 46 | - 'Duración del ataque: ' 47 | - '' 48 | - 'Uso máximo de CPU del proceso durante el ataque: %' 49 | - 'Uso máximo de memoria de proceso durante el ataque: ' 50 | - 'Bots máximos por segundo durante el ataque: ' 51 | - '' 52 | - 'Direcciones IP incluidas en la lista negra durante el ataque: ' 53 | - 'Verificaciones fallidas durante el ataque: ' 54 | - 'Verificaciones exitosas durante el ataque: ' 55 | # RGB colors of the Discord webhook embed 56 | # Color picker: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/fr.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Besoin d'aide ou d'autres questions ? https://jonesdev.xyz/discord 12 | # Code source : https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, licence sous GPL-3.0 14 | # 15 | 16 | # Les notifications d'attaque bot peuvent être envoyé à discord via un webhook 17 | webhook: 18 | # Lien du webhook discord (Mettez '' pour désactiver les webhooks) 19 | url: '' 20 | # Nom d'utilisateur du webhook 21 | username: Sonar 22 | # Lien vers l'avatar du webhook (Mettez '' pour désactiver) 23 | avatar-url: '' 24 | # Message à envoyer (Mettez '' pour désactiver) 25 | # Vous pouvez mentionner des personnes en utilisant <@idUtilisateur> 26 | # Si vous voulez mentionner un rôle vous devriez utiliser <@&idRole> 27 | content: '' 28 | # Embed qui sera envoyé quand il y a une attaque 29 | embed: 30 | # Petit footer de l'embed 31 | footer: 32 | # Message du footer 33 | text: © Jones Development et Contributeurs Sonar 34 | # Lien de l'icône du footer 35 | icon-url: '' 36 | # Titre du webhook discord 37 | title: '✅ Attaque mitigé' 38 | # Lien clickable du titre 39 | title-url: '' 40 | # Description (message) de l'embed 41 | description: 42 | - 'L''attaque sur votre serveur a été mitigé' 43 | - '' 44 | - 'Démarré à: :T>' 45 | - 'Fini à: :T>' 46 | - 'Durée: ' 47 | - '' 48 | - 'Pique du processeur: %' 49 | - 'Pique de la mémoire ram: ' 50 | - 'Pique du nombre de bots par secondes: ' 51 | - '' 52 | - "IP Blacklisté durant l'attaque: " 53 | - "Vérification échoué durant l'attaque: " 54 | - "Vérification réussi durant l'attaque: " 55 | # Code couleur RGB pour l'embed 56 | # Sélectionner la couleur: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/id.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Butuh bantuan atau punya pertanyaan? https://jonesdev.xyz/discord 12 | # Kode sumber: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, dilisensikan di bawah GPL-3.0 14 | # 15 | 16 | # Notifikasi serangan bot juga dapat dikirim ke server Discord Anda menggunakan webhook 17 | webhook: 18 | # URL dari webhook Discord (Atur ini ke '' untuk menonaktifkan webhook) 19 | url: '' 20 | # Nama pengguna pengirim webhook Discord 21 | username: Sonar 22 | # URL avatar pengirim webhook Discord (Atur ini ke '' untuk menonaktifkan) 23 | avatar-url: '' 24 | # Konten pesan webhook Discord (Atur ini ke '' untuk menonaktifkan) 25 | # Anda dapat menggunakan ini untuk misalnya memberi ping ke anggota staf menggunakan <@userId> 26 | # Jika Anda ingin memberi ping ke peran, Anda harus menggunakan <@&roleId> 27 | content: '' 28 | # Pesan embed webhook Discord yang dikirim ketika serangan telah berhenti 29 | embed: 30 | # Pesan footer kecil dari embed webhook Discord 31 | footer: 32 | # Konten pesan footer dari embed webhook Discord 33 | text: © Jones Development dan Kontributor Sonar 34 | # URL ikon pesan footer dari embed webhook Discord 35 | icon-url: '' 36 | # Judul dari embed webhook Discord 37 | title: '✅ Serangan berhasil diatasi' 38 | # URL yang dapat diklik dari judul embed webhook Discord 39 | title-url: '' 40 | # Deskripsi (konten) dari embed webhook Discord 41 | description: 42 | - Serangan pada server Anda telah berhasil diatasi. 43 | - '' 44 | - 'Mulai serangan: :T>' 45 | - 'Akhir serangan: :T>' 46 | - 'Durasi serangan: ' 47 | - '' 48 | - 'Penggunaan CPU proses puncak selama serangan: %' 49 | - 'Penggunaan memori proses puncak selama serangan: ' 50 | - 'Bot per detik puncak selama serangan: ' 51 | - '' 52 | - 'Alamat IP yang masuk daftar hitam selama serangan: ' 53 | - 'Verifikasi yang gagal selama serangan: ' 54 | - 'Verifikasi yang berhasil selama serangan: ' 55 | # Warna RGB dari embed webhook Discord 56 | # Pemilih warna: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/ka.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # დახმარება გჭირდება ან კითხვა გაქვს? https://jonesdev.xyz/discord 12 | # საწყისი კოდი: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, licensed under GPL-3.0 14 | # 15 | 16 | # შემოტევასთან დაკავშირებული მესიჯების გაგზავნა თქვენს Discord სერვერში შეიძლება ვებჰუკების მეშვეობით 17 | webhook: 18 | # ვებჰუკის ლინკი (დააყენეთ ეს '' თუ გინდათ, რომ გათიშოთ ეს ფუნქცია) 19 | url: '' 20 | # სახელი ვებჰუკის გამგზავნელის 21 | username: Sonar 22 | # ლინკი ავატარის, რომელიც იქნება ვებჰუკის ავატარად გამოყენებული (დააყენეთ ეს '' თუ გინდათ, რომ გათიშოთ ეს ფუნქცია) 23 | avatar-url: '' 24 | # ვებჰუკის შეტყობინების შინაარსი (დააყენეთ ეს '' თუ გინდათ, რომ გათიშოთ ეს ფუნქცია) 25 | # თქვენ შეგიძლიათ ეს გამოიყენოთ, რომ მაგალითად მოთაგოთ სტაფის წევრი <@userId> 26 | # თუ გინდათ, რომ მოთაგოთ როლი, გამოიყენეთ ეს <@&roleId> 27 | content: '' 28 | # განათავსეთ ვებჰუკის შეტყობინება, რომელიც იგზავნება შეტევის შეჩერებისას 29 | embed: 30 | # ვებჰუკის შეტყობინების ქვედა მცირე ტექსტი 31 | footer: 32 | # ვებჰუკის ქვედა მცირე შეტყობინების შინაარსი 33 | text: © Jones Development and Sonar Contributors 34 | # ლინკი ქვედა მცირე შეტყობინობის ავატარისთვის 35 | icon-url: '' 36 | # ვებჰუკის სათაური 37 | title: ':white_check_mark: შეტევა გადატანილია' 38 | # ლინკი რომელზეც გადავნენ ვებჰუკის სათაურზე დაჭერის შემდეგ 39 | title-url: '' 40 | # აღწერა (ტექსტი) ვებჰუკის მესიჯის 41 | description: 42 | - თქვენს სერვზე განხორციელებული შემოტევა წარმატებულად იყო გადატანილი. 43 | - '' 44 | - 'შემოტევა დაიწყო: :T>' 45 | - 'შემოტევა დასრულდა: :T>' 46 | - 'შემოტევის ხანგრძლივობა: ' 47 | - '' 48 | - 'CPU-ის გამოყენების პიკი შეტევის დროს: %' 49 | - 'RAM-ის გამოყენების პიკი შეტევის დროს: ' 50 | - 'ბოტების პიკი წამში შეტევის დროს: ' 51 | - '' 52 | - 'შეტევის დროს შავ სიაში IP მისამართები: ' 53 | - 'შეტევის დროს ვერიფიკაცია ვერ შეასრულა: ' 54 | - 'წარმატებულად ვერიფირებული თავდასხმის დროს: ' 55 | # RGB ფერები ვებჰუკის მესიჯისთვის 56 | # Color picker: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/nl.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Hulp nodig of vragen? https://jonesdev.xyz/discord 12 | # Broncode: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, gelicentieerd onder GPL-3.0 14 | # 15 | 16 | # Bot aanval meldingen kunnen ook met behulp van webhooks naar uw Discord-server worden verzonden 17 | webhook: 18 | # URL van de Discord-webhook (zet dit op '' om webhooks uit te schakelen) 19 | url: '' 20 | # Gebruikersnaam van de Discord-webhook-afzender 21 | username: Sonar 22 | # URL naar de avatar van de Discord-webhook-afzender (zet dit op '' om uit te schakelen) 23 | avatar-url: '' 24 | # Inhoud van het Discord-webhook (zet dit op '' om uit te schakelen) 25 | # U kunt dit gebruiken om bv. ping medewerkers met <@userId> 26 | # Als u rollen wilt pingen, moet u <@&roleId> gebruiken 27 | content: '' 28 | # Embed Discord-webhook dat wordt verzonden wanneer een aanval is gestopt 29 | embed: 30 | # Klein voettekst bericht van de Discord-webhook-insluiting 31 | footer: 32 | # Inhoud van de voettekst bericht van de Discord-webhook-insluiting 33 | text: © Jones Development and Sonar Contributors 34 | # URL van de voettekst pictogram van de Discord-webhook-insluiting 35 | icon-url: '' 36 | # Titel van de Discord-webhook-insluiting 37 | title: ':white_check_mark: Aanval verzacht' 38 | # Klikbare URL van de titel van de Discord-webhook-insluiting 39 | title-url: '' 40 | # Beschrijving (inhoud) van de Discord-webhook-insluiting 41 | description: 42 | - De aanval op uw server is afgezwakt. 43 | - '' 44 | - 'Aanval beginnen: :T>' 45 | - 'Einde aanval: :T>' 46 | - 'Duur van de aanval: ' 47 | - '' 48 | - 'Maximaal proces CPU-gebruik tijdens de aanval: %' 49 | - 'Maximaal proces-geheugengebruik tijdens de aanval: ' 50 | - 'Maximaal bots per seconde tijdens de aanval: ' 51 | - '' 52 | - 'IP-adressen op de zwarte lijst gezet tijdens de aanval: ' 53 | - 'Mislukte verificaties tijdens de aanval: ' 54 | - 'Succesvolle verificaties tijdens de aanval: ' 55 | # RGB-kleuren van de Discord-webhook-insluiting 56 | # Kleur kiezer: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/pl.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Potrzebujesz pomocy lub masz pytania? https://jonesdev.xyz/discord 12 | # Source code: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, na licencji GPL-3.0 14 | # 15 | 16 | # Bot attack notifications can also be sent to your Discord server using webhooks 17 | webhook: 18 | # URL of the Discord webhook (Set this to '' to disable webhooks) 19 | url: '' 20 | # Username of the Discord webhook sender 21 | username: Sonar 22 | # URL to the avatar of the Discord webhook sender (Set this to '' to disable) 23 | avatar-url: '' 24 | # Content of the Discord webhook message (Set this to '' to disable) 25 | # You can use this to e.g. ping staff members using <@userId> 26 | # If you want to ping roles, you will need to use <@&roleId> 27 | content: '' 28 | # Embed Discord webhook message that is sent when an attack has stopped 29 | embed: 30 | # Small footer message of the Discord webhook embed 31 | footer: 32 | # Content of the footer message of the Discord webhook embed 33 | text: © Jones Development and Sonar Contributors 34 | # URL of the footer message icon of the Discord webhook embed 35 | icon-url: '' 36 | # Title of the Discord webhook embed 37 | title: ':white_check_mark: Atak został złagodzony' 38 | # Clickable URL of the title of the Discord webhook embed 39 | title-url: '' 40 | # Description (content) of the Discord webhook embed 41 | description: 42 | - Atak na serwer został złagodzony. 43 | - '' 44 | - 'Początek ataku: :T>' 45 | - 'Koniec ataku: :T>' 46 | - 'Czas trwania ataku: ' 47 | - '' 48 | - 'Szczytowe użycie procesora przez proces podczas ataku: %' 49 | - 'Szczytowe użycie pamięci procesu podczas ataku: ' 50 | - 'Szczytowa liczba botów na sekundę podczas ataku: ' 51 | - '' 52 | - 'Adresy IP na czarnej liście podczas ataku: ' 53 | - 'Nieudane weryfikacje podczas ataku: ' 54 | - 'Pomyślne weryfikacje podczas ataku: ' 55 | # RGB colors of the Discord webhook embed 56 | # Color picker: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/ru.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # Нужна помощь или есть вопросы? https://jonesdev.xyz/discord 12 | # Исходный код: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, под лицензией GPL-3.0 14 | # 15 | 16 | # Уведомления о бот-атаках могут быть отправлены на ваш сервер Discord с помощью вебхуков 17 | webhook: 18 | # URL вебхука Discord (Установите значение '' чтобы отключить вебхук) 19 | url: '' 20 | # Ник вебхука Discord 21 | username: Sonar 22 | # URL аватара вебхука Discord (Установите значение '' чтобы не использовать аватар) 23 | avatar-url: '' 24 | # Контент сообщения вебхука Discord (Установите значение '' чтобы не использовать контент) 25 | # Вы можете использовать это для оповещения персонала, например: <@userId> 26 | # Если вы хотите пинговать роли, вам нужно использовать <@&roleId> 27 | content: '' 28 | # Embed сообщение, отправляемое после прекращения атаки 29 | embed: 30 | # Нижний текст в панельном сообщении 31 | footer: 32 | # Содержимое нижнего текста в панельном сообщении 33 | text: © Jones Development and Sonar Contributors 34 | # Иконка нижнего текста в панельном сообщении 35 | icon-url: '' 36 | # Заголовок панельного сообщения 37 | title: ':white_check_mark: Attack mitigated' 38 | # Кликабельный URL-адрес заголовка 39 | title-url: '' 40 | # Описание (контент) панельного сообщения 41 | description: 42 | - Атака на ваш сервер была устранена. 43 | - '' 44 | - 'Начало атаки: :T>' 45 | - 'Конец атаки: :T>' 46 | - 'Продолжительность атаки: ' 47 | - '' 48 | - 'Пиковое использование процессора во время атаки: %' 49 | - 'Пиковое использование памяти во время атаки: ' 50 | - 'Пиковая скорость входа ботов в секунду во время атаки: ' 51 | - '' 52 | - 'IP-адреса, внесенные в черный список во время атаки: ' 53 | - 'Проваленные проверки во время атаки: ' 54 | - 'Успешные проверки во время атаки: ' 55 | # Цвета RGB используемые в панельном сообщении 56 | # Выбор цвета: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/webhook/zh.yml: -------------------------------------------------------------------------------- 1 | # 2 | # /$$$$$$ 3 | # /$$__ $$ 4 | # | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ 5 | # | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$ 6 | # \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/ 7 | # /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$ 8 | # | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$ 9 | # \______/ \______/ |__/ |__/ \_______/|__/ 10 | # 11 | # 需要帮助吗? https://jonesdev.xyz/discord 12 | # 源代码: https://github.com/jonesdevelopment/sonar 13 | # Copyright Jones Development and Sonar Contributors, 以 GPL-3.0 许可 14 | # 15 | 16 | # 当遭到机器人攻击时也可以将webhook消息发送到Discord服务器中. 17 | webhook: 18 | # Discord webhook 的 URL 链接. (可能需要使用代理!) 19 | url: '' 20 | # Webhook 的用户名 21 | username: Sonar 22 | # 指向 Webhook 的头像的 URL 链接. (设置为空就是再 webhook 中设置的默认头像) 23 | avatar-url: '' 24 | # Webhook 中的原始消息内容 (设置为空即隐藏) 25 | # 您可以使用 <@用户ID> 来提及指定的 Discord 用户 26 | # 如果你想提及一整个身份组, 则可以使用 <@&组ID>. 27 | content: '' 28 | # 当攻击停止时向 Discord 发送的嵌入式 webhook 消息 29 | embed: 30 | # 页脚(位于消息底部的)消息 31 | footer: 32 | # 页脚消息中的文本内容 33 | text: © Jones Development and Sonar Contributors 34 | # 页脚消息中的图标指向的 URL 链接 35 | icon-url: '' 36 | # 嵌入式消息中的标题 37 | title: ':white_check_mark: 已缓解攻击' 38 | # 标题中可嵌入的 URL 链接 39 | title-url: '' 40 | # 嵌入式消息中的描述消息 41 | description: 42 | - 已缓解针对于您服务器的攻击. 43 | - '' 44 | - '检测到此次攻击的时间: :T>' 45 | - '此次攻击结束的时间: :T>' 46 | - '此次攻击的总时长: ' 47 | - '' 48 | - '攻击期间进程所使用的处理器峰值使用率: %' 49 | - '攻击期间进程所使用的内存峰值: ' 50 | - '攻击期间每秒涌入的机器人数量的峰值: ' 51 | - '' 52 | - '此次攻击期间被列入黑名单的 IP 地址数量: ' 53 | - '此次攻击期间验证失败的会话: ' 54 | - '此次攻击期间通过验证的玩家数量: ' 55 | # 嵌入式消息的左侧边框的颜色 56 | # 颜色选取器: https://www.rapidtables.com/web/color/RGB_Color.html 57 | color: 58 | red: 0 59 | green: 255 60 | blue: 0 61 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=xyz.jonesdev 2 | version=2.1.32 3 | description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit. 4 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | netty = "4.2.1.Final" 3 | adventure = "4.21.0" 4 | adventure-platform = "4.4.0" 5 | bstats = "3.1.0" 6 | libby = "2.0.0-SNAPSHOT" 7 | pluginyml = "0.6.0" 8 | 9 | [plugins] 10 | indra-git = "net.kyori.indra.git:3.1.3" 11 | shadow = "com.gradleup.shadow:8.3.6" 12 | spotless = "com.diffplug.spotless:7.0.4" 13 | pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" } 14 | pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" } 15 | 16 | [libraries] 17 | netty = { module = "io.netty:netty-all", version.ref = "netty" } 18 | adventure-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure" } 19 | adventure-serializer = { module = "net.kyori:adventure-text-serializer-gson", version.ref = "adventure" } 20 | adventure-nbt = { module = "net.kyori:adventure-nbt", version.ref = "adventure" } 21 | adventure-platform-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform" } 22 | adventure-platform-bungee = { module = "net.kyori:adventure-platform-bungeecord", version.ref = "adventure-platform" } 23 | libby-core = { module = "com.alessiodp.libby:libby-core", version.ref = "libby" } 24 | libby-bungee = { module = "com.alessiodp.libby:libby-bungee", version.ref = "libby" } 25 | libby-bukkit = { module = "com.alessiodp.libby:libby-bukkit", version.ref = "libby" } 26 | libby-velocity = { module = "com.alessiodp.libby:libby-velocity", version.ref = "libby" } 27 | bstats-bungee = { module = "org.bstats:bstats-bungeecord", version.ref = "bstats" } 28 | bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } 29 | bstats-velocity = { module = "org.bstats:bstats-velocity", version.ref = "bstats" } 30 | imagefilters = "com.jhlabs:filters:2.0.235-1" 31 | caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.0" 32 | annotations = "org.jetbrains:annotations:26.0.2" 33 | simpleyaml = "com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4" 34 | ormlite = "com.j256.ormlite:ormlite-jdbc:6.1" 35 | lombok = "org.projectlombok:lombok:1.18.38" 36 | bungeecord = "net.md-5:bungeecord-proxy:1.21-SNAPSHOT" 37 | velocity = "com.velocitypowered:velocity-proxy:3.4.0-SNAPSHOT" 38 | # We have to use 1.8.8 for backwards compatibility 39 | spigot = "org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT" 40 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonesdevelopment/sonar/d7f48ecdf084a12786100c46425f3295106449de/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.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /lombok.config: -------------------------------------------------------------------------------- 1 | lombok.addLombokGeneratedAnnotation = false 2 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "Sonar" 2 | 3 | sequenceOf( 4 | "api", 5 | "captcha", 6 | "common", 7 | "bukkit", 8 | "bungeecord", 9 | "velocity" 10 | ).forEach { 11 | include(":$it") 12 | } 13 | -------------------------------------------------------------------------------- /velocity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation(project(":api")) 3 | implementation(project(":common")) 4 | 5 | compileOnly(rootProject.libs.velocity) 6 | testCompileOnly(rootProject.libs.velocity) 7 | 8 | implementation(rootProject.libs.bstats.velocity) 9 | implementation(rootProject.libs.libby.velocity) 10 | } 11 | 12 | tasks { 13 | processResources { 14 | val props = mapOf( 15 | "version" to rootProject.version.toString(), 16 | "description" to rootProject.description, 17 | "url" to "https://jonesdev.xyz/discord/", 18 | "main" to "xyz.jonesdev.sonar.velocity.SonarVelocityPlugin" 19 | ) 20 | inputs.properties(props) 21 | filesMatching("velocity-plugin.json") { 22 | expand(props) 23 | } 24 | } 25 | } 26 | 27 | java.sourceCompatibility = JavaVersion.VERSION_17 28 | java.targetCompatibility = JavaVersion.VERSION_17 29 | -------------------------------------------------------------------------------- /velocity/src/main/java/xyz/jonesdev/sonar/velocity/SonarVelocityPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.velocity; 19 | 20 | import com.google.inject.Inject; 21 | import com.velocitypowered.api.event.Subscribe; 22 | import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; 23 | import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; 24 | import com.velocitypowered.api.plugin.annotation.DataDirectory; 25 | import com.velocitypowered.api.proxy.ProxyServer; 26 | import lombok.Getter; 27 | import org.bstats.velocity.Metrics; 28 | import org.slf4j.Logger; 29 | 30 | import java.nio.file.Path; 31 | 32 | @Getter 33 | public final class SonarVelocityPlugin { 34 | private final ProxyServer server; 35 | private final Logger logger; 36 | private final Path dataDirectory; 37 | private final Metrics.Factory metricsFactory; 38 | private SonarVelocity bootstrap; 39 | 40 | @Inject 41 | public SonarVelocityPlugin(final ProxyServer server, 42 | final Logger logger, 43 | final @DataDirectory Path dataDirectory, 44 | final Metrics.Factory metricsFactory) { 45 | this.server = server; 46 | this.logger = logger; 47 | this.dataDirectory = dataDirectory; 48 | this.metricsFactory = metricsFactory; 49 | } 50 | 51 | @Subscribe 52 | public void handle(final ProxyInitializeEvent event) { 53 | bootstrap = new SonarVelocity(this); 54 | bootstrap.initialize(); 55 | } 56 | 57 | @Subscribe 58 | public void handle(final ProxyShutdownEvent event) { 59 | bootstrap.shutdown(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /velocity/src/main/java/xyz/jonesdev/sonar/velocity/command/VelocitySonarCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.velocity.command; 19 | 20 | import com.velocitypowered.api.command.SimpleCommand; 21 | import com.velocitypowered.api.proxy.Player; 22 | import org.jetbrains.annotations.NotNull; 23 | import xyz.jonesdev.sonar.api.command.InvocationSource; 24 | import xyz.jonesdev.sonar.api.command.SonarCommand; 25 | 26 | import java.util.Collections; 27 | import java.util.List; 28 | 29 | public final class VelocitySonarCommand implements SimpleCommand, SonarCommand { 30 | 31 | @Override 32 | public void execute(final @NotNull Invocation invocation) { 33 | // Create our own invocation source wrapper to handle messages properly 34 | final InvocationSource invocationSource = new InvocationSource( 35 | invocation.source() instanceof Player ? ((Player) invocation.source()).getUniqueId() : null, 36 | invocation.source(), 37 | invocation.source()::hasPermission); 38 | // Pass the invocation source and command arguments to our command handler 39 | handle(invocationSource, invocation.arguments()); 40 | } 41 | 42 | @Override 43 | public List suggest(final @NotNull Invocation invocation) { 44 | // Do not allow tab completion if the player does not have the required permission 45 | return invocation.source().hasPermission("sonar.command") 46 | ? getCachedTabSuggestions(invocation.arguments()) : Collections.emptyList(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /velocity/src/main/java/xyz/jonesdev/sonar/velocity/fallback/FallbackVelocityInboundHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2025 Sonar Contributors 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package xyz.jonesdev.sonar.velocity.fallback; 19 | 20 | import com.velocitypowered.proxy.connection.MinecraftConnection; 21 | import com.velocitypowered.proxy.protocol.packet.HandshakePacket; 22 | import com.velocitypowered.proxy.protocol.packet.ServerLoginPacket; 23 | import io.netty.channel.ChannelHandlerContext; 24 | import org.jetbrains.annotations.NotNull; 25 | import xyz.jonesdev.sonar.common.fallback.FallbackInboundHandlerAdapter; 26 | 27 | import java.net.InetSocketAddress; 28 | 29 | import static xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake.HandshakePacket.STATUS; 30 | 31 | final class FallbackVelocityInboundHandler extends FallbackInboundHandlerAdapter { 32 | 33 | @Override 34 | public void channelRead(final @NotNull ChannelHandlerContext ctx, final Object msg) throws Exception { 35 | if (msg instanceof HandshakePacket handshake) { 36 | // We don't care about server pings; remove the handler 37 | if (handshake.getNextStatus() == STATUS) { 38 | ctx.pipeline().remove(this); 39 | } else { 40 | handleHandshake(ctx, handshake.getServerAddress(), handshake.getProtocolVersion().getProtocol()); 41 | } 42 | } else if (msg instanceof ServerLoginPacket serverLogin) { 43 | // Deject this pipeline and let Sonar process the login packet 44 | ctx.pipeline().remove(this); 45 | // Make sure to use the potentially modified, original IP 46 | final MinecraftConnection minecraftConnection = ctx.pipeline().get(MinecraftConnection.class); 47 | final InetSocketAddress socketAddress = (InetSocketAddress) minecraftConnection.getRemoteAddress(); 48 | handleLogin(ctx, () -> ctx.fireChannelRead(msg), serverLogin.getUsername(), socketAddress); 49 | return; 50 | } 51 | ctx.fireChannelRead(msg); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /velocity/src/main/resources/velocity-plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "sonar", 3 | "name": "Sonar", 4 | "version": "$version", 5 | "description": "$description", 6 | "url": "$url", 7 | "authors": [ 8 | "Jones Development", 9 | "Sonar Contributors" 10 | ], 11 | "dependencies": [ 12 | { 13 | "id": "geyser", 14 | "optional": true 15 | }, 16 | { 17 | "id": "floodgate", 18 | "optional": true 19 | }, 20 | { 21 | "id": "protocolize", 22 | "optional": true 23 | }, 24 | { 25 | "id": "viaversion", 26 | "optional": true 27 | }, 28 | { 29 | "id": "packetevents", 30 | "optional": true 31 | }, 32 | { 33 | "id": "vpacketevents", 34 | "optional": true 35 | }, 36 | { 37 | "id": "fastlogin", 38 | "optional": true 39 | } 40 | ], 41 | "main": "$main" 42 | } 43 | --------------------------------------------------------------------------------