Compare commits

..
61 Commits
Author SHA1 Message Date
Jones 3497cb116c chore(release): bump version to 2.1.53 (#646) 2026-10-17 18:31:48 +02:00
Jones 4d491531bb feat(captcha): increase generation randomness 2026-10-17 18:27:38 +02:00
FeGmbHandJones 7b2d2db614 Remove adventure-platform to prevent Adventure 4.x/5.x class conflict (#642)
* Remove adventure platform dependencies

Removed adventure-platform-bukkit and adventure-platform-bungee dependencies.

* fix(bungee): remove adventure-platform to prevent Adventure 4.x/5.x class conflict

* fix(bukkit): restore missing adventure-platform-bukkit catalog entry

* Remove adventure-platform-bukkit dependency

Removed adventure-platform-bukkit dependency from libs.versions.toml

* Readd adventure-platform-bukkit dependency

* Update copyright year and refactor action bar method

Updated copyright year from 2025 to 2026 and refactored action bar message sending as commented by @jonesdevelopment

* Refactor title code as commented

* I forgot a closing bracket :(

* Change LibraryLoader to public class with state management

Refactor LibraryLoader to a public class and add loaded state management.

* Update copyright year and load libraries earlier

* Add imports for BungeeLibraryManager and SonarPlatform

* Avoid double library loading without tracking state

* Invert BungeeAudience#showTitle player check

* Now makes use of Java 17+ features

* Avoid storing extra 1.16 protocol version ID

---------

Co-authored-by: Jones <admin@jonesdev.xyz>
2026-10-13 13:45:41 +02:00
dependabot[bot] 4547b1632d Bump com.diffplug.spotless from 8.10.3 to 8.10.4 (#643)
Bumps [com.diffplug.spotless](https://github.com/diffplug/spotless) from 8.10.3 to 8.10.4.
- [Release notes](https://github.com/diffplug/spotless/releases)
- [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md)
- [Commits](https://github.com/diffplug/spotless/compare/gradle/8.10.3...gradle/8.10.4)

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 14:18:31 +02:00
dependabot[bot] 943872ed62 Bump io.netty:netty-all from 4.2.18.Final to 4.2.19.Final (#645)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.18.Final to 4.2.19.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.18.Final...netty-4.2.19.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.19.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 14:18:14 +02:00
dependabot[bot] f1239a7412 Bump gradle-wrapper from 9.8.0 to 9.8.1 (#644)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.8.0 to 9.8.1.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.8.0...v9.8.1)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.8.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-12 14:18:12 +02:00
dependabot[bot] 1794a2f24e Bump com.diffplug.spotless from 8.10.2 to 8.10.3 (#640)
Bumps [com.diffplug.spotless](https://github.com/diffplug/spotless) from 8.10.2 to 8.10.3.
- [Release notes](https://github.com/diffplug/spotless/releases)
- [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md)
- [Commits](https://github.com/diffplug/spotless/compare/gradle/8.10.2...gradle/8.10.3)

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-05 16:13:47 +02:00
dependabot[bot] 18f40fea3e Bump gradle-wrapper from 9.7.1 to 9.8.0 (#638)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.7.1 to 9.8.0.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.7.1...v9.8.0)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-28 21:57:19 +02:00
Jones cf865978b4 Release 2.1.52 (#637) 2026-09-27 15:40:37 +02:00
Akkariin eccfb26b30 26.3 Support (#635)
* 26.3 Support

* Add 26.3 protocol version (777)
* Add 26.3 runtime codec and tags
* Update block state IDs for 26.3
* Update item and entity IDs for 26.3
* Update packet registry mappings for 26.3
* Update ConfirmTeleportationPacket, AnimationPacket, EntityAnimationPacket, and JoinGamePacket for 26.3 wire format changes

* Fix non-compound element serialization in RegistryDataPacket

In 26.3, registry entries such as minecraft:block_transformer use ListTag rather than CompoundTag for their element data. Allow any BinaryTag in RegistryDataPacket to prevent empty compound tags from being sent to clients.

* [ci skip] Fix gamemode and previousGamemode encoding in JoinGamePacket for 26.3+

Minecraft 26.3 uses GameType.STREAM_CODEC (VarInt) for gameType and GameType.OPTIONAL_STREAM_CODEC (Optional VarInt where 0 represents none) for previousGameType in CommonPlayerSpawnInfo. Writing previousGamemode as a raw byte (-1 / 0xFF) caused VarInt decoding to consume extra bytes and desynchronize subsequent packet fields.

* Adapt GravityHandler teleport confirmation and movement checks for 26.3+

* Bypass swing arm check in ProtocolHandler for 26.3+

* [ci skip] update annotate for `canFall` field in `GravityHandler`
2026-09-20 13:41:32 +02:00
Jones edf57c280b [skip ci] Update dead wiki.vg link in README 2026-09-15 13:29:29 +02:00
dependabot[bot] 81776712c0 Bump io.netty:netty-all from 4.2.17.Final to 4.2.18.Final (#633)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.17.Final to 4.2.18.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.17.Final...netty-4.2.18.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.18.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 11:54:41 +02:00
dependabot[bot] acc3d0df3a Bump com.diffplug.spotless from 8.10.1 to 8.10.2 (#634)
Bumps com.diffplug.spotless from 8.10.1 to 8.10.2.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 11:54:34 +02:00
dependabot[bot] aafb2a22fe Bump org.projectlombok:lombok from 1.18.46 to 1.18.48 (#632)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.46 to 1.18.48.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.46...v1.18.48)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-version: 1.18.48
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-07 20:59:59 +02:00
Jones b8bbe411e1 Release 2.1.51 (#630) 2026-09-06 14:57:18 +02:00
purpurcof 4ed63ee2dc Prevent TailExceptionsHandler from racing a graceful close (#616) 2026-08-31 23:05:20 +02:00
dependabot[bot] 7cd7f86114 Bump com.diffplug.spotless from 8.10.0 to 8.10.1 (#629)
Bumps com.diffplug.spotless from 8.10.0 to 8.10.1.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-31 11:44:29 +02:00
dependabot[bot] 58c9a6bc25 Bump gradle-wrapper from 9.7.0 to 9.7.1 (#627)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.7.0 to 9.7.1.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.7.0...v9.7.1)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.7.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 13:01:52 +02:00
dependabot[bot] be6fbc78ab Bump com.diffplug.spotless from 8.9.0 to 8.10.0 (#626)
Bumps com.diffplug.spotless from 8.9.0 to 8.10.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 13:01:43 +02:00
Jones cd5eb191fa Fix filled_map item type ID on 26.2 2026-08-23 14:10:56 +02:00
dependabot[bot] 449ff7a55d Bump io.netty:netty-all from 4.2.16.Final to 4.2.17.Final (#620)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.16.Final to 4.2.17.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.16.Final...netty-4.2.17.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.17.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-10 15:04:11 +02:00
dependabot[bot] 89b8033540 Bump gradle-wrapper from 9.6.1 to 9.7.0 (#621)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.6.1 to 9.7.0.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.6.1...v9.7.0)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-10 15:03:59 +02:00
dependabot[bot] 1b003e9872 Bump com.diffplug.spotless from 8.8.0 to 8.9.0 (#619)
Bumps com.diffplug.spotless from 8.8.0 to 8.9.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 16:13:07 +02:00
dependabot[bot] 59d1cd2e66 Bump com.gradleup.shadow from 9.6.0 to 9.6.1 (#617)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 9.6.0 to 9.6.1.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/9.6.0...9.6.1)

---
updated-dependencies:
- dependency-name: com.gradleup.shadow
  dependency-version: 9.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-27 13:53:01 +02:00
dependabot[bot] de377dbde6 Bump com.gradleup.shadow from 9.5.1 to 9.6.0 (#614)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 9.5.1 to 9.6.0.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/9.5.1...9.6.0)

---
updated-dependencies:
- dependency-name: com.gradleup.shadow
  dependency-version: 9.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-20 14:09:59 +02:00
Jones 9b5845f5af Implement missing check for blacklist scores of 0 2026-07-15 21:57:00 +02:00
dependabot[bot] 6cd1f9e5e4 Bump com.gradleup.shadow from 9.4.3 to 9.5.1 (#609)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 9.4.3 to 9.5.1.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/9.4.3...9.5.1)

---
updated-dependencies:
- dependency-name: com.gradleup.shadow
  dependency-version: 9.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-13 17:59:34 +02:00
dependabot[bot] 5ca053cfdd Bump io.netty:netty-all from 4.2.15.Final to 4.2.16.Final (#610)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.15.Final to 4.2.16.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.15.Final...netty-4.2.16.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.16.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-13 12:55:43 +02:00
Jones 95d94e467a Release 2.1.50 (#607) 2026-07-12 12:29:30 +02:00
Jones fdd54c9b34 Bump dynamic adventure from 4.21.0 to 5.2.0 2026-07-12 12:20:34 +02:00
Jones 5d09260fbc Release 2.1.49 (#606) 2026-07-11 14:03:48 +02:00
Jones b7b2d0d501 Adventure 5 and Java 17+ 2026-07-10 18:02:28 +02:00
dependabot[bot] c8bfd7431f Bump com.diffplug.spotless from 8.7.0 to 8.8.0 (#603)
Bumps com.diffplug.spotless from 8.7.0 to 8.8.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 07:25:44 +02:00
dependabot[bot] 312dcca783 Bump com.gradleup.shadow from 9.4.1 to 9.4.3 (#600)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 9.4.1 to 9.4.3.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/9.4.1...9.4.3)

---
updated-dependencies:
- dependency-name: com.gradleup.shadow
  dependency-version: 9.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 15:03:08 +02:00
dependabot[bot] e006bca937 Bump gradle-wrapper from 9.6.0 to 9.6.1 (#602)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.6.0 to 9.6.1.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.6.0...v9.6.1)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-29 15:02:55 +02:00
dependabot[bot] b5c406e5e1 Bump com.diffplug.spotless from 8.6.0 to 8.7.0 (#598)
Bumps com.diffplug.spotless from 8.6.0 to 8.7.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 13:04:47 +02:00
dependabot[bot] 8b9129aeae Bump gradle-wrapper from 9.5.1 to 9.6.0 (#599)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.5.1 to 9.6.0.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.5.1...v9.6.0)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 13:04:26 +02:00
Jones 6ef7866893 Release 2.1.48 (#596) 2026-06-20 15:38:29 +02:00
Jones 90e7808d65 Add missing 26.2 server version 2026-06-20 15:35:14 +02:00
Jones 6c6c28f906 26.2 Support (#594)
* Implement 26.2 protocol version

* Implement 26.2 codec and tags

* Add `onlineMode` field to JoinGamePacket

* Add `sessionId` field to LoginSuccessPacket
2026-06-19 17:29:28 +02:00
Jan1k 3dbc108b8d Fix message placeholder keys (#592) 2026-06-14 20:12:34 +02:00
Jan1k 781d30eb43 Fix Turkish subcommand formatting (#591) 2026-06-14 17:42:19 +02:00
dependabot[bot] 518e602bf3 Bump io.netty:netty-all from 4.2.14.Final to 4.2.15.Final (#590)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.14.Final to 4.2.15.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.14.Final...netty-4.2.15.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.15.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-08 09:59:56 +02:00
Jones d62f0440ad [ci skip] Add LLM Guidelines to CONTRIBUTING.md 2026-06-06 17:25:37 +02:00
MISHA bf29fa5ca7 Add forced hosts support to transfer feature (#588)
* feat: add use-handshake-hostname config option for forced hosts support

* Solve issues
2026-06-03 21:14:43 +02:00
dependabot[bot] 104691b816 Bump com.diffplug.spotless from 8.5.1 to 8.6.0 (#586)
Bumps com.diffplug.spotless from 8.5.1 to 8.6.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-01 13:58:37 +02:00
dependabot[bot] 097816760f Bump io.netty:netty-all from 4.2.13.Final to 4.2.14.Final (#583)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.13.Final to 4.2.14.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.13.Final...netty-4.2.14.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.14.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-25 15:08:46 +02:00
dependabot[bot] 5f1b040c99 Bump com.diffplug.spotless from 8.4.0 to 8.5.1 (#580)
Bumps com.diffplug.spotless from 8.4.0 to 8.5.1.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 17:04:11 +02:00
dependabot[bot] 911a655aaf Bump gradle-wrapper from 9.5.0 to 9.5.1 (#582)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.5.0 to 9.5.1.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.5.0...v9.5.1)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.5.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 17:03:55 +02:00
dependabot[bot] 82133e7ac7 Bump io.netty:netty-all from 4.2.12.Final to 4.2.13.Final (#579)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.12.Final to 4.2.13.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.12.Final...netty-4.2.13.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.13.Final
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-11 19:57:42 +02:00
Jones d85f2bc2d5 Release 2.1.47 (#578) 2026-05-09 13:47:52 +02:00
Jones 877e3630b7 Warn if the default support URL is used 2026-05-08 21:50:21 +02:00
Jones 0c4495e502 Automatically replace legacy support URL 2026-05-08 21:46:05 +02:00
Jones 8cb92bb074 Make individual check timings configurable 2026-05-08 21:45:19 +02:00
dependabot[bot] 89a07cd06e Bump com.github.ben-manes.caffeine:caffeine from 3.2.3 to 3.2.4 (#577)
Bumps [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.2.3...v3.2.4)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-version: 3.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-07 13:45:11 +02:00
dependabot[bot] 698a611511 Bump gradle-wrapper from 9.4.1 to 9.5.0 (#576)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.4.1 to 9.5.0.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.4.1...v9.5.0)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-05 17:09:26 +02:00
Jones 0f598bb1da Implement option to place map in offhand (https://github.com/jonesdevelopment/sonar/issues/574) 2026-04-29 17:39:11 +02:00
dependabot[bot] 1a8c1caa39 Bump org.projectlombok:lombok from 1.18.44 to 1.18.46 (#573)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.44 to 1.18.46.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.44...v1.18.46)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-version: 1.18.46
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-27 09:31:57 +02:00
Jones c24fe4a4d9 [ci skip] Update homepage and documentation links 2026-04-26 15:15:46 +02:00
Jones 2da0cc6761 Use JdbcConnectionSource for H2 2026-04-24 23:51:22 +02:00
Jones 80b7726f18 Update security contact email 2026-04-23 20:45:37 +02:00
67 changed files with 668 additions and 239 deletions

No files matched your search

+12 -1
View File
@@ -5,7 +5,7 @@ joining the [Discord](https://sonar.top/discord).
## Contributing Guidelines:
1. Fork the repository and create a new branch for your contribution.
2. Follow the coding guidelines for your code.
2. Adhere to the Coding Guidelines and LLM Guidelines.
3. Test your code before committing and pushing it.
4. Use [semantic](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) commit messages for your commits.
@@ -17,6 +17,17 @@ joining the [Discord](https://sonar.top/discord).
- Write clear comments to explain complex parts of your code.
- Ensure your code is easy to read and maintain.
## LLM Guidelines
Keep the use of AI (including LLMs) for code generation to an absolute minimum. If possible, avoid using AI entirely due to potential complications regarding authorship, intellectual property, and copyright.
If AI was utilized during the development of a Pull Request, you must disclose its exact use in the PR description. This includes:
- The specific tool and model used (e.g., GPT 5.4, Claude 4.7 Sonnet, Gemini 3.1 Pro)
- The nature of its use (e.g., optimization)
- The exact prompts used, where relevant
Please note that submissions will be rejected if AI usage raises concerns regarding code quality, licensing, or integrity.
## Bug Reports:
1. Check if someone has already reported the bug.
+3 -4
View File
@@ -30,9 +30,8 @@
> ### Notice about Sonar 3.0
>
> We're excited to announce the public release of Sonar 3.0.
> If you are interested, please check out https://sonar.top/. You can read more about what sets Sonar 3.0 apart from Sonar 2.0 [here](<https://docs.sonar.top/faq>).
> If you want more robust protection, better performance, and awesome new features, check out Sonar 3.0!
> If you want more robust protection, better performance, and awesome new features, check out Sonar 3.0 at https://sonar.top/!
> You can read more about what sets Sonar 3.0 apart from Sonar 2.0 [here](<https://sonar.top/docs/features>).
## Design and Goal
* Effective, lightweight, and easy-to-use
@@ -48,7 +47,7 @@ Sonar analyzes a player's behavior before joining the actual server, therefore s
1. Sonar sends the player to a lightweight fake server when they connect for the first time.
2. Sonar verifies that players obey the laws of Minecraft's physics, including gravity and proper block collision.
3. Sonar verifies that players send legitimate packets when interacting with vehicles (e.g. boats).
4. Sonar makes sure that players send legitimate packets according to the [vanilla Minecraft protocol](<https://wiki.vg/Protocol>).
4. Sonar makes sure that players send legitimate packets according to the [vanilla Minecraft protocol](<https://minecraft.wiki/w/Java_Edition_protocol/>).
Sonar also protects against spambot attacks since it queues the incoming connections, therefore making it technically impossible to have a ton of bots join the server at the same time.
+1 -1
View File
@@ -13,7 +13,7 @@ If you discover a security vulnerability within Sonar, please follow these steps
## Contact
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.
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 support@sonar.top.
## Acknowledgments
@@ -56,7 +56,7 @@ public final class AntiBot {
return shouldPerform(Sonar.get0().getConfig().getVerification().getMap().getTiming());
}
private static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) {
public static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) {
return timing == SonarConfiguration.Verification.Timing.ALWAYS
|| (timing == SonarConfiguration.Verification.Timing.DURING_ATTACK
&& Sonar.get0().getAttackTracker().getCurrentAttack() != null);
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2025 Sonar Contributors
* Copyright (C) 2026 Sonar Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@ import io.netty.channel.Channel;
import io.netty.util.ReferenceCountUtil;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.api.timer.SystemTimer;
@@ -45,6 +46,8 @@ public interface SonarUser {
boolean isGeyser();
@Nullable String getHostname();
/**
* Disconnect the player during/after verification
* using our custom Disconnect packet.
@@ -76,7 +76,9 @@ public enum ProtocolVersion {
MINECRAFT_1_21_7(772, "1.21.7"),
MINECRAFT_1_21_9(773, "1.21.9"),
MINECRAFT_1_21_11(774, "1.21.11"),
MINECRAFT_26_1(775, "26.1");
MINECRAFT_26_1(775, "26.1"),
MINECRAFT_26_2(776, "26.2"),
MINECRAFT_26_3(777, "26.3");
private final int protocol;
private final String name;
@@ -167,12 +167,12 @@ public final class SonarConfiguration {
Sonar.get0().getLogger().warn(" ");
}
verification.gravity.enabled = generalConfig.getBoolean("verification.checks.gravity.enabled");
verification.gravity.checkCollisions = generalConfig.getBoolean("verification.checks.collision.enabled");
verification.gravity.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.gravity.timing"));
verification.gravity.collisionTiming = Verification.Timing.valueOf(generalConfig.getString("verification.checks.collision.timing"));
verification.gravity.captchaOnFail = generalConfig.getBoolean("verification.checks.gravity.captcha-on-fail");
verification.gravity.maxMovementTicks = clamp(generalConfig.getInt("verification.checks.gravity.max-movement-ticks"), 2, 100);
verification.vehicle.enabled = generalConfig.getBoolean("verification.checks.vehicle.enabled");
verification.vehicle.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.vehicle.timing"));
verification.vehicle.minimumPackets = clamp(generalConfig.getInt("verification.checks.vehicle.minimum-packets"), 0, 20);
verification.map.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.map-captcha.timing"));
@@ -181,6 +181,7 @@ public final class SonarConfiguration {
verification.map.maxTries = clamp(generalConfig.getInt("verification.checks.map-captcha.max-tries"), 1, 100);
verification.map.alphabet = generalConfig.getString("verification.checks.map-captcha.alphabet");
verification.map.backgroundImage = null;
verification.map.placeInOffhand = generalConfig.getBoolean("verification.checks.map-captcha.place-in-offhand");
final String backgroundPath = generalConfig.getString("verification.checks.map-captcha.background");
if (!backgroundPath.isEmpty()) {
@@ -252,7 +253,12 @@ public final class SonarConfiguration {
SonarCommand.prepareCachedTabSuggestions();
supportUrl = messagesConfig.getString("support-url");
supportUrl = messagesConfig.getString("support-url")
.replace("jonesdev.xyz", "sonar.top") // Migration: Replace legacy URL
.trim();
if (supportUrl.contains("://sonar.top/")) {
Sonar.get0().getLogger().warn("Consider entering a custom support URL (if applicable).");
}
header = MiniMessage.miniMessage().deserialize(
String.join("<newline>", messagesConfig.getStringList("header")),
Placeholder.unparsed("support-url", supportUrl),
@@ -374,19 +380,20 @@ public final class SonarConfiguration {
private int maxTries;
private String alphabet;
private File backgroundImage;
private boolean placeInOffhand;
}
@Getter
public static final class Gravity {
private boolean enabled;
private boolean checkCollisions;
private Timing timing;
private Timing collisionTiming;
private boolean captchaOnFail;
private int maxMovementTicks;
}
@Getter
public static final class Vehicle {
private boolean enabled;
private Timing timing;
private int minimumPackets;
}
@@ -20,6 +20,7 @@ package xyz.jonesdev.sonar.api.database.controller;
import com.alessiodp.libby.LibraryManager;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.jdbc.JdbcPooledConnectionSource;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource;
@@ -93,10 +94,11 @@ public final class VerifiedPlayerController {
"?autoReconnect=true");
}
connectionSource = new JdbcPooledConnectionSource(jdbcURL,
Sonar.get0().getConfig().getGeneralConfig().getString("database.username"),
Sonar.get0().getConfig().getGeneralConfig().getString("database.password"),
cachedDatabaseType.getDatabaseType());
final String user = Sonar.get0().getConfig().getGeneralConfig().getString("database.username");
final String pass = Sonar.get0().getConfig().getGeneralConfig().getString("database.password");
connectionSource = cachedDatabaseType == SonarConfiguration.Database.Type.H2
? new JdbcConnectionSource(jdbcURL, user, pass, cachedDatabaseType.getDatabaseType())
: new JdbcPooledConnectionSource(jdbcURL, user, pass, cachedDatabaseType.getDatabaseType());
try {
TableUtils.createTableIfNotExists(connectionSource, VerifiedPlayer.class);
+6 -3
View File
@@ -75,6 +75,12 @@ allprojects {
compileJava {
options.encoding = "UTF-8"
options.release.set(17)
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
disableAutoTargetJvm()
}
jar {
@@ -93,9 +99,6 @@ allprojects {
attributes["Git-Commit"] = gitCommit
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
}
}
@@ -82,7 +82,9 @@ public enum BukkitServerVersion {
MINECRAFT_1_21_9,
MINECRAFT_1_21_10,
MINECRAFT_1_21_11,
MINECRAFT_26_1;
MINECRAFT_26_1,
MINECRAFT_26_2,
MINECRAFT_26_3;
static final BukkitServerVersion[] REVERSED_VALUES;
-3
View File
@@ -15,9 +15,6 @@ dependencies {
compileOnly(rootProject.libs.bungeecord)
implementation(rootProject.libs.adventure.platform.bungee) {
exclude(module = "adventure-nbt")
}
implementation(rootProject.libs.bstats.bungee)
implementation(rootProject.libs.libby.bungee)
}
@@ -0,0 +1,92 @@
/*
* Copyright (C) 2026 Sonar Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package xyz.jonesdev.sonar.bungee;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.title.Title;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.chat.ComponentSerializer;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
import java.time.Duration;
/**
* Minimal {@link Audience} implementation backed by the native BungeeCord chat API.
* <br>
* BungeeCord does not ship Adventure, so we used to bundle adventure-platform-bungeecord (Adventure 4.x).
* That conflicted with the Adventure 5.x libraries Sonar loads at runtime, because both end up
* in the same relocated package. Converting components to JSON and passing them to BungeeCord's own
* {@link ComponentSerializer} allows us to depend on exactly one Adventure version.
*/
final class BungeeAudience implements Audience {
private final CommandSender sender;
BungeeAudience(final @NotNull CommandSender sender) {
this.sender = sender;
}
@Override
public void sendMessage(final @NotNull Component message) {
sender.sendMessage(toBungee(message));
}
@Override
public void sendActionBar(final @NotNull Component message) {
// Only players have an action bar
if (sender instanceof ProxiedPlayer player) {
player.sendMessage(ChatMessageType.ACTION_BAR, toBungee(message));
}
}
@Override
public void showTitle(final @NotNull Title title) {
// Only players can see titles
if (sender instanceof ProxiedPlayer player) {
final Title.Times times = title.times();
ProxyServer.getInstance().createTitle()
.title(toBungee(title.title()))
.subTitle(toBungee(title.subtitle()))
// Use the same defaults as Title#DEFAULT_TIMES (0.5s, 3.5s, 1s)
.fadeIn(times == null ? 10 : toTicks(times.fadeIn()))
.stay(times == null ? 70 : toTicks(times.stay()))
.fadeOut(times == null ? 20 : toTicks(times.fadeOut()))
.send(player);
}
}
private static int toTicks(final @NotNull Duration duration) {
return (int) (duration.toMillis() / 50L);
}
private @NotNull BaseComponent[] toBungee(final @NotNull Component component) {
// Downsample hex colors for clients that do not support them
final boolean legacyClient = sender instanceof ProxiedPlayer player
&& player.getPendingConnection().getVersion() < ProtocolVersion.MINECRAFT_1_16.getProtocol();
final GsonComponentSerializer serializer = legacyClient
? GsonComponentSerializer.colorDownsamplingGson()
: GsonComponentSerializer.gson();
return ComponentSerializer.parse(serializer.serialize(component));
}
}
@@ -20,8 +20,8 @@ package xyz.jonesdev.sonar.bungee;
import com.alessiodp.libby.BungeeLibraryManager;
import lombok.Getter;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import org.jetbrains.annotations.NotNull;
@@ -36,26 +36,22 @@ import java.util.UUID;
@Getter
public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
public SonarBungee(final @NotNull SonarBungeePlugin plugin) {
super(plugin, SonarPlatform.BUNGEE, plugin.getDataFolder(), new BungeeLibraryManager(plugin));
public SonarBungee(final @NotNull SonarBungeePlugin plugin, final @NotNull BungeeLibraryManager libraryManager) {
super(plugin, SonarPlatform.BUNGEE, plugin.getDataFolder(), libraryManager);
}
/**
* Wrapper for BungeeCord audiences
*/
private final BungeeAudiences bungeeAudiences = BungeeAudiences.create(getPlugin());
@Override
public @Nullable Audience audience(final @Nullable UUID uniqueId) {
if (uniqueId == null) {
return null;
}
return bungeeAudiences.player(uniqueId);
final ProxiedPlayer player = getPlugin().getServer().getPlayer(uniqueId);
return player == null ? null : new BungeeAudience(player);
}
@Override
public @NotNull Audience sender(final @NotNull Object object) {
return bungeeAudiences.sender((CommandSender) object);
return new BungeeAudience((CommandSender) object);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2025 Sonar Contributors
* Copyright (C) 2026 Sonar Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,9 +17,12 @@
package xyz.jonesdev.sonar.bungee;
import com.alessiodp.libby.BungeeLibraryManager;
import lombok.Getter;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import xyz.jonesdev.sonar.api.SonarPlatform;
import xyz.jonesdev.sonar.common.boot.LibraryLoader;
@Getter
public final class SonarBungeePlugin extends Plugin {
@@ -30,7 +33,13 @@ public final class SonarBungeePlugin extends Plugin {
public void onEnable() {
server = ProxyServer.getInstance();
bootstrap = new SonarBungee(this);
// HACK:
// Adventure is not bundled in the jar, so the libraries have to be on the classpath
// before SonarBungee is loaded. The JVM resolves its Adventure types during class verification.
final BungeeLibraryManager libraryManager = new BungeeLibraryManager(this);
LibraryLoader.loadLibraries(libraryManager, SonarPlatform.BUNGEE);
bootstrap = new SonarBungee(this, libraryManager);
bootstrap.initialize();
}
@@ -54,13 +54,13 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
static {
FONT = TTFFontProvider.loadFont("/assets/fonts/Kingthings_Trypewriter_2.ttf");
FBM.setAmount(0.6f);
FBM.setScale(15);
FBM.setAmount(0.55f + RANDOM.nextFloat(0.15f));
FBM.setScale(10 + RANDOM.nextFloat(10));
SMEAR.setShape(SmearFilter.SQUARES);
SMEAR.setDensity(0.1f);
SMEAR.setDistance(0);
SMEAR.setMix(0.35f);
SMEAR.setMix(0.25f + RANDOM.nextFloat(0.25f));
// Create fractions based on the number of colors
for (int i = 0; i < COLOR_FRACTIONS.length; i++) {
@@ -111,7 +111,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
private void applyRandomColorGradient(final @NotNull Graphics2D graphics) {
// Randomize the colors for the gradient effect
for (int i = 0; i < COLORS.length; i++) {
final float random = 0.9f + RANDOM.nextFloat() * 0.1f;
final float random = 0.8f + RANDOM.nextFloat() * 0.2f;
COLORS[i] = Color.getHSBColor(RANDOM.nextFloat(), random * 0.8f, random);
}
@@ -161,8 +161,8 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
}
private void createGlyphOutline(final @NotNull Graphics2D graphics, final @NotNull Shape shape) {
final float txy = 1.25f + RANDOM.nextFloat();
final float width = 1 + RANDOM.nextFloat();
final float txy = RANDOM.nextFloat(0.1f, 2f);
final float width = RANDOM.nextFloat(0.5f, 2f);
// Create a randomly translated and stroked shape based on the original glyph shape
final AffineTransform translation = AffineTransform.getTranslateInstance(txy, txy);
+2 -2
View File
@@ -17,7 +17,7 @@
import lombok.experimental.UtilityClass;
import xyz.jonesdev.sonar.api.antibot.captcha.CaptchaGenerator;
import xyz.jonesdev.sonar.captcha.complex.ComplexCaptchaGenerator;
import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -29,7 +29,7 @@ import java.util.Random;
public class Main {
public void main(final String... args) throws IOException {
final Random random = new Random();
final CaptchaGenerator standardCaptchaGenerator = new ComplexCaptchaGenerator(null);
final CaptchaGenerator standardCaptchaGenerator = new StandardCaptchaGenerator(null);
final long start = System.currentTimeMillis();
final char[] dictionary = {'a', 'b', 'c', 'd', 'e', 'f'/*, 'g'*/, 'h'/*, 'i'*/, 'j',
@@ -48,6 +48,7 @@ import static xyz.jonesdev.sonar.common.protocol.SonarPacketPreparer.*;
public abstract class InboundHandlerAdapter extends ChannelInboundHandlerAdapter {
protected @Nullable String username;
protected ProtocolVersion protocolVersion;
protected @Nullable String handshakeHostname;
protected @Nullable RemovalListener channelRemovalListener;
/**
@@ -65,6 +66,7 @@ public abstract class InboundHandlerAdapter extends ChannelInboundHandlerAdapter
throw QuietDecoderException.INSTANCE;
}
protocolVersion = ProtocolVersion.fromId(protocol);
handshakeHostname = hostname;
ctx.pipeline().addFirst(SONAR_BANDWIDTH, BandwidthHandler.INSTANCE);
}
@@ -166,7 +168,8 @@ public abstract class InboundHandlerAdapter extends ChannelInboundHandlerAdapter
}
// Create an instance for the user and let the verification handler take over the channel
return () -> new UserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser);
return () -> new UserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser,
handshakeHostname);
});
}
@@ -25,6 +25,7 @@ import lombok.ToString;
import lombok.experimental.Accessors;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.jonesdev.sonar.api.Sonar;
import xyz.jonesdev.sonar.api.antibot.SonarUser;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
@@ -47,7 +48,7 @@ import java.net.InetAddress;
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.*;
@Getter
@ToString(of = {"protocolVersion", "inetAddress", "geyser"})
@ToString(of = {"protocolVersion", "inetAddress", "hostname", "geyser"})
public final class UserWrapper implements SonarUser {
@Accessors(fluent = true)
private final Channel channel;
@@ -56,6 +57,7 @@ public final class UserWrapper implements SonarUser {
private final String fingerprint;
private final String username;
private final boolean geyser;
private final @Nullable String hostname;
private final SystemTimer loginTimer;
@Setter
private boolean forceCaptcha;
@@ -65,13 +67,15 @@ public final class UserWrapper implements SonarUser {
final @NotNull ProtocolVersion protocolVersion,
final @NotNull String username,
final @NotNull String fingerprint,
final boolean geyser) {
final boolean geyser,
final @Nullable String hostname) {
this.channel = ctx.channel();
this.inetAddress = inetAddress;
this.protocolVersion = protocolVersion;
this.username = username;
this.fingerprint = fingerprint;
this.geyser = geyser;
this.hostname = hostname;
this.loginTimer = new SystemTimer();
GlobalSonarStatistics.totalAttemptedVerifications++;
@@ -24,8 +24,8 @@ import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.SonarPlatform;
@UtilityClass
class LibraryLoader {
void loadLibraries(final @NotNull LibraryManager libraryManager, final @NotNull SonarPlatform platform) {
public class LibraryLoader {
public void loadLibraries(final @NotNull LibraryManager libraryManager, final @NotNull SonarPlatform platform) {
libraryManager.addMavenCentral();
libraryManager.addJitPack();
libraryManager.loadLibraries(
@@ -69,25 +69,14 @@ class LibraryLoader {
// Only load adventure if not on Velocity
if (platform != SonarPlatform.VELOCITY) {
if (platform != SonarPlatform.PAPER) {
// BungeeCord does not ship Adventure, and we do not bundle adventure-platform there anymore
// (mixing Adventure 4.x and 5.x in the same relocated package causes NoSuchMethodErrors).
// Therefore, adventure-api and everything else Adventure needs has to be resolved at runtime.
final boolean resolveTransitive = platform == SonarPlatform.BUNGEE;
libraryManager.loadLibraries(
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-minimessage")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-serializer-gson")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build()
adventureLibrary("adventure-text-minimessage", resolveTransitive),
adventureLibrary("adventure-text-serializer-gson", resolveTransitive),
adventureLibrary("adventure-nbt", resolveTransitive)
);
} else {
// On Paper, we only relocate the nbt package since the rest of adventure is bundled with the server.
@@ -95,11 +84,25 @@ class LibraryLoader {
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("4.21.0")
.version("5.2.0")
.relocate("net{}kyori{}adventure{}nbt", "xyz{}jonesdev{}sonar{}libs{}kyori{}adventure{}nbt")
.build()
);
}
}
}
private @NotNull Library adventureLibrary(final @NotNull String artifactId, final boolean resolveTransitive) {
final Library.Builder builder = Library.builder()
.groupId("net{}kyori")
.artifactId(artifactId)
.version("5.2.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori");
if (resolveTransitive) {
builder.resolveTransitiveDependencies(true)
// Gson is already provided by the proxy, so we must not load another copy
.excludeTransitiveDependency("com.google.code.gson", "gson");
}
return builder.build();
}
}
@@ -68,7 +68,13 @@ public abstract class SonarBootstrap<T> implements Sonar {
final @NotNull File dataDirectory,
final @NotNull LibraryManager libraryManager) {
// Load all libraries before anything else
LibraryLoader.loadLibraries(libraryManager, platform);
// HACK:
// We manually load the libraries on BungeeCord beforehand,
// so we skip this call to avoid loading libraries twice.
// See SonarBungeePlugin.java#L40
if (platform != SonarPlatform.BUNGEE) {
LibraryLoader.loadLibraries(libraryManager, platform);
}
this.libraryManager = libraryManager;
// Check if Netty is up to date
ProtocolUtil.checkNettyVersion();
@@ -21,6 +21,7 @@ import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
@ChannelHandler.Sharable
public final class TailExceptionsHandler extends ChannelDuplexHandler {
@@ -33,6 +34,20 @@ public final class TailExceptionsHandler extends ChannelDuplexHandler {
// Additionally, this will also run after our custom decoder.
@Override
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
// If ProtocolUtil#closeWith(...) already queued a graceful write-then-close for
// this channel (e.g. VerificationHandler#fail() calls disconnect() and then
// throws to unwind), don't race it with a second, immediate close() here. Doing
// so can abort the still-in-flight kick/disconnect packet write before it's fully
// flushed, so the client only receives a truncated packet instead of our message.
// The scheduled close from closeWith() will still run once the write completes.
// See: https://github.com/jonesdevelopment/sonar/issues/476
if (Boolean.TRUE.equals(ctx.channel().attr(ProtocolUtil.CLOSING).get())) {
if (LOG_EXCEPTIONS) {
cause.printStackTrace(System.err);
}
return;
}
// Close the channel if we encounter any errors.
ctx.close();
if (LOG_EXCEPTIONS) {
@@ -73,6 +73,10 @@ public class SonarPacketPreparer {
0, 36 + MAP_SLOT, 1, ItemType.FILLED_MAP, CompoundBinaryTag.builder()
.put("map", IntBinaryTag.intBinaryTag(0)) // map id
.build());
public static final SonarPacket CAPTCHA_SET_CONTAINER_SLOT_OFFHAND = new SetContainerSlotPacket(
0, 45, 1, ItemType.FILLED_MAP, CompoundBinaryTag.builder()
.put("map", IntBinaryTag.intBinaryTag(0)) // map id
.build());
public final static SonarPacket CAPTCHA_HELD_ITEM_SLOT = new SetHeldItemPacket(MAP_SLOT);
public final SonarPacket DEFAULT_ABILITIES = new PlayerAbilitiesPacket(0x00, 0, 0);
public final SonarPacket NO_MOVE_ABILITIES = new PlayerAbilitiesPacket(0x02, 0, 0);
@@ -101,7 +105,11 @@ public class SonarPacketPreparer {
public final SonarPacket[] REGISTRY_SYNC_1_21_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_5);
public final SonarPacket[] REGISTRY_SYNC_1_21_11 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_11);
public final SonarPacket[] REGISTRY_SYNC_26_1 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_1);
public final SonarPacket[] REGISTRY_SYNC_26_2 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_2);
public final SonarPacket[] REGISTRY_SYNC_26_3 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_3);
public final SonarPacket TAGS_UPDATE_26_1 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_1);
public final SonarPacket TAGS_UPDATE_26_2 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_2);
public final SonarPacket TAGS_UPDATE_26_3 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_3);
public final SonarPacket START_WRITING_CHUNKS = new GameEventPacket(13, 0);
public final static SonarPacket INVALID_HELD_ITEM_SLOT = new SetHeldItemPacket(-1);
public final SonarPacket RANDOM_KEEP_ALIVE = new SonarPacketSnapshot(new KeepAlivePacket(RANDOM.nextInt()));
@@ -124,7 +132,6 @@ public class SonarPacketPreparer {
public SonarPacket spawnPosition;
public SonarPacket fallStartPosition;
public SonarPacket fallStartPositionLegacy;
public static SonarPacket transferToOrigin;
public SonarPacket blacklisted;
public SonarPacket alreadyQueued;
public SonarPacket alreadyVerifying;
@@ -149,7 +156,7 @@ public class SonarPacketPreparer {
if (username.length() > 16) {
username = username.substring(0, 16);
}
loginSuccess = new SonarPacketSnapshot(new LoginSuccessPacket(uuid, username, true));
loginSuccess = new SonarPacketSnapshot(new LoginSuccessPacket(uuid, username, true, UUID.randomUUID()));
// Prepare JoinGame packet
joinGame = new SonarPacketSnapshot(new JoinGamePacket(PLAYER_ENTITY_ID,
@@ -159,7 +166,7 @@ public class SonarPacketPreparer {
new String[]{"minecraft:overworld"}, "minecraft:overworld", "flat",
DimensionType.OVERWORLD, RANDOM.nextLong() & 1337,
false, true, false,
false, false, false, true));
false, false, false, true, false));
// Prepare the gravity check
maxMovementTick = Sonar.get0().getConfig().getVerification().getGravity().getMaxMovementTicks();
@@ -211,15 +218,6 @@ public class SonarPacketPreparer {
unsupportedVersion = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getUnsupportedVersion(), true));
tooManyOnlinePerIP = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getTooManyOnlinePerIp(), true));
// Prepare transfer packet
if (Sonar.get0().getConfig().getGeneralConfig().getBoolean("verification.transfer.enabled")) {
transferToOrigin = new SonarPacketSnapshot(new TransferPacket(
Sonar.get0().getConfig().getGeneralConfig().getString("verification.transfer.destination-host"),
Sonar.get0().getConfig().getGeneralConfig().getInt("verification.transfer.destination-port")));
} else {
transferToOrigin = null;
}
// Prepare update time packet
final int timeOfDay = Sonar.get0().getConfig().getVerification().getTimeOfDay();
if (timeOfDay != 1000) {
@@ -300,14 +298,22 @@ public class SonarPacketPreparer {
}
public static @Nullable SonarPacket getTagsPacket(final @NotNull ProtocolVersion protocolVersion) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return TAGS_UPDATE_26_3;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
return TAGS_UPDATE_26_2;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
return TAGS_UPDATE_26_1;
}
return null; // apparently doesn't crash the client; we're safe... for now.
}
public static SonarPacket[] getRegistryPackets(final @NotNull ProtocolVersion protocolVersion) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return REGISTRY_SYNC_26_3;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
return REGISTRY_SYNC_26_2;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
return REGISTRY_SYNC_26_1;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_11)) {
return REGISTRY_SYNC_1_21_11;
@@ -77,7 +77,8 @@ public enum SonarPacketRegistry {
map(0x05, MINECRAFT_1_20_2, true),
map(0x07, MINECRAFT_1_20_5, true));
clientbound.register(UpdateTagsPacket.class, UpdateTagsPacket::new,
map(0x0D, MINECRAFT_1_20_5, true));
map(0x0D, MINECRAFT_1_20_5, true),
map(0x0E, MINECRAFT_26_3, true));
serverbound.register(ClientInformationPacket.class, ClientInformationPacket::new,
map(0x00, MINECRAFT_1_20_2, false));
@@ -113,7 +114,8 @@ public enum SonarPacketRegistry {
map(0x2C, MINECRAFT_1_21_2, true),
map(0x2B, MINECRAFT_1_21_5, true),
map(0x30, MINECRAFT_1_21_9, true),
map(0x31, MINECRAFT_26_1, true));
map(0x31, MINECRAFT_26_1, true),
map(0x32, MINECRAFT_26_3, true));
// minecraft:keep_alive
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
map(0x00, MINECRAFT_1_7_2, true),
@@ -133,7 +135,8 @@ public enum SonarPacketRegistry {
map(0x27, MINECRAFT_1_21_2, true),
map(0x26, MINECRAFT_1_21_5, true),
map(0x2B, MINECRAFT_1_21_9, true),
map(0x2C, MINECRAFT_26_1, true));
map(0x2C, MINECRAFT_26_1, true),
map(0x2D, MINECRAFT_26_3, true));
// minecraft:disconnect
clientbound.register(DisconnectPacket.class, DisconnectPacket::new,
map(0x40, MINECRAFT_1_7_2, true),
@@ -172,7 +175,8 @@ public enum SonarPacketRegistry {
map(0x42, MINECRAFT_1_21_2, true),
map(0x41, MINECRAFT_1_21_5, true),
map(0x46, MINECRAFT_1_21_9, true),
map(0x48, MINECRAFT_26_1, true));
map(0x48, MINECRAFT_26_1, true),
map(0x49, MINECRAFT_26_3, true));
// minecraft:player_abilities
clientbound.register(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new,
map(0x39, MINECRAFT_1_7_2, true),
@@ -193,7 +197,8 @@ public enum SonarPacketRegistry {
map(0x3A, MINECRAFT_1_21_2, true),
map(0x39, MINECRAFT_1_21_5, true),
map(0x3E, MINECRAFT_1_21_9, true),
map(0x40, MINECRAFT_26_1, true));
map(0x40, MINECRAFT_26_1, true),
map(0x41, MINECRAFT_26_3, true));
// minecraft:level_chunk_with_light
clientbound.register(ChunkDataPacket.class, ChunkDataPacket::new,
map(0x21, MINECRAFT_1_7_2, true),
@@ -213,7 +218,8 @@ public enum SonarPacketRegistry {
map(0x28, MINECRAFT_1_21_2, true),
map(0x27, MINECRAFT_1_21_5, true),
map(0x2C, MINECRAFT_1_21_9, true),
map(0x2D, MINECRAFT_26_1, true));
map(0x2D, MINECRAFT_26_1, true),
map(0x2E, MINECRAFT_26_3, true));
// minecraft:remove_entities
clientbound.register(RemoveEntitiesPacket.class, RemoveEntitiesPacket::new,
map(0x13, MINECRAFT_1_7_2, true),
@@ -236,7 +242,8 @@ public enum SonarPacketRegistry {
map(0x47, MINECRAFT_1_21_2, true),
map(0x46, MINECRAFT_1_21_5, true),
map(0x4B, MINECRAFT_1_21_9, true),
map(0x4D, MINECRAFT_26_1, true));
map(0x4D, MINECRAFT_26_1, true),
map(0x4E, MINECRAFT_26_3, true));
// minecraft:set_passengers
clientbound.register(SetPassengersPacket.class, SetPassengersPacket::new,
map(0x1B, MINECRAFT_1_7_2, true),
@@ -256,7 +263,8 @@ public enum SonarPacketRegistry {
map(0x65, MINECRAFT_1_21_2, true),
map(0x64, MINECRAFT_1_21_5, true),
map(0x69, MINECRAFT_1_21_9, true),
map(0x6B, MINECRAFT_26_1, true));
map(0x6B, MINECRAFT_26_1, true),
map(0x6D, MINECRAFT_26_3, true));
// minecraft:add_entity
clientbound.register(SpawnEntityPacket.class, SpawnEntityPacket::new,
map(0x0E, MINECRAFT_1_7_2, true),
@@ -281,7 +289,8 @@ public enum SonarPacketRegistry {
map(0x4E, MINECRAFT_1_21_2, true),
map(0x4D, MINECRAFT_1_21_5, true),
map(0x52, MINECRAFT_1_21_9, true),
map(0x54, MINECRAFT_26_1, true));
map(0x54, MINECRAFT_26_1, true),
map(0x56, MINECRAFT_26_3, true));
// minecraft:ping
clientbound.register(TransactionPacket.class, TransactionPacket::new,
map(0x32, MINECRAFT_1_7_2, true),
@@ -300,7 +309,8 @@ public enum SonarPacketRegistry {
map(0x37, MINECRAFT_1_21_2, true),
map(0x36, MINECRAFT_1_21_5, true),
map(0x3B, MINECRAFT_1_21_9, true),
map(0x3D, MINECRAFT_26_1, true));
map(0x3D, MINECRAFT_26_1, true),
map(0x3E, MINECRAFT_26_3, true));
// minecraft:set_default_spawn_position
clientbound.register(SetDefaultSpawnPositionPacket.class, SetDefaultSpawnPositionPacket::new,
map(0x05, MINECRAFT_1_7_2, true),
@@ -322,7 +332,8 @@ public enum SonarPacketRegistry {
map(0x5B, MINECRAFT_1_21_2, true),
map(0x5A, MINECRAFT_1_21_5, true),
map(0x5F, MINECRAFT_1_21_9, true),
map(0x61, MINECRAFT_26_1, true));
map(0x61, MINECRAFT_26_1, true),
map(0x63, MINECRAFT_26_3, true));
// minecraft:map_item_data
clientbound.register(MapDataPacket.class, MapDataPacket::new,
map(0x34, MINECRAFT_1_7_2, true),
@@ -341,7 +352,8 @@ public enum SonarPacketRegistry {
map(0x2D, MINECRAFT_1_21_2, true),
map(0x2C, MINECRAFT_1_21_5, true),
map(0x31, MINECRAFT_1_21_9, true),
map(0x33, MINECRAFT_26_1, true));
map(0x33, MINECRAFT_26_1, true),
map(0x34, MINECRAFT_26_3, true));
// minecraft:container_set_slot
clientbound.register(SetContainerSlotPacket.class, SetContainerSlotPacket::new,
map(0x2F, MINECRAFT_1_7_2, true),
@@ -376,7 +388,8 @@ public enum SonarPacketRegistry {
map(0x61, MINECRAFT_1_21_2, true),
map(0x60, MINECRAFT_1_21_5, true),
map(0x65, MINECRAFT_1_21_9, true),
map(0x67, MINECRAFT_26_1, true));
map(0x67, MINECRAFT_26_1, true),
map(0x69, MINECRAFT_26_3, true));
// minecraft:system_chat
clientbound.register(SystemChatPacket.class, SystemChatPacket::new,
map(0x02, MINECRAFT_1_7_2, true),
@@ -395,20 +408,23 @@ public enum SonarPacketRegistry {
map(0x73, MINECRAFT_1_21_2, true),
map(0x72, MINECRAFT_1_21_5, true),
map(0x77, MINECRAFT_1_21_9, true),
map(0x79, MINECRAFT_26_1, true));
map(0x79, MINECRAFT_26_1, true),
map(0x7C, MINECRAFT_26_3, true));
// minecraft:game_event
clientbound.register(GameEventPacket.class, GameEventPacket::new,
map(0x20, MINECRAFT_1_20_3, true),
map(0x22, MINECRAFT_1_20_5, true),
map(0x23, MINECRAFT_1_21_2, true),
map(0x22, MINECRAFT_1_21_5, true),
map(0x26, MINECRAFT_1_21_9, true));
map(0x26, MINECRAFT_1_21_9, true),
map(0x27, MINECRAFT_26_3, true));
// minecraft:transfer
clientbound.register(TransferPacket.class, TransferPacket::new,
map(0x73, MINECRAFT_1_20_5, true),
map(0x7A, MINECRAFT_1_21_2, true),
map(0x7F, MINECRAFT_1_21_9, true),
map(0x81, MINECRAFT_26_1, true));
map(0x81, MINECRAFT_26_1, true),
map(0x84, MINECRAFT_26_3, true));
// minecraft:set_held_slot
clientbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
map(0x09, MINECRAFT_1_7_2, true),
@@ -430,7 +446,8 @@ public enum SonarPacketRegistry {
map(0x63, MINECRAFT_1_21_2, true),
map(0x62, MINECRAFT_1_21_5, true),
map(0x67, MINECRAFT_1_21_9, true),
map(0x69, MINECRAFT_26_1, true));
map(0x69, MINECRAFT_26_1, true),
map(0x6B, MINECRAFT_26_3, true));
// minecraft:animate
clientbound.register(EntityAnimationPacket.class, EntityAnimationPacket::new,
map(0x0B, MINECRAFT_1_7_2, true),
@@ -462,7 +479,8 @@ public enum SonarPacketRegistry {
map(0x6B, MINECRAFT_1_21_2, true),
map(0x6A, MINECRAFT_1_21_5, true),
map(0x6F, MINECRAFT_1_21_9, true),
map(0x71, MINECRAFT_26_1, true));
map(0x71, MINECRAFT_26_1, true),
map(0x73, MINECRAFT_26_3, true));
// minecraft:client_tick_end
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
@@ -486,7 +504,8 @@ public enum SonarPacketRegistry {
map(0x31, MINECRAFT_1_21_2, false),
map(0x33, MINECRAFT_1_21_4, false),
map(0x34, MINECRAFT_1_21_6, false),
map(0x35, MINECRAFT_26_1, false));
map(0x35, MINECRAFT_26_1, false),
map(0x36, MINECRAFT_26_3, false));
// minecraft:paddle_boat
serverbound.register(PaddleBoatPacket.class, PaddleBoatPacket::new,
map(0x11, MINECRAFT_1_9, false),
@@ -525,7 +544,8 @@ public enum SonarPacketRegistry {
map(0x28, MINECRAFT_1_21_2, false),
map(0x29, MINECRAFT_1_21_4, false),
map(0x2A, MINECRAFT_1_21_6, false),
map(0x26, MINECRAFT_26_1, false));
map(0x26, MINECRAFT_26_1, false),
map(0x2B, MINECRAFT_26_3, false));
// minecraft:move_vehicle
serverbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
map(0x10, MINECRAFT_1_9, false),
@@ -734,7 +754,8 @@ public enum SonarPacketRegistry {
map(0x3A, MINECRAFT_1_21_4, false),
map(0x3B, MINECRAFT_1_21_5, false),
map(0x3C, MINECRAFT_1_21_6, false),
map(0x3F, MINECRAFT_26_1, false));
map(0x3F, MINECRAFT_26_1, false),
map(0x2E, MINECRAFT_26_3, false));
}
};
@@ -80,7 +80,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 9250;
}
return 9451;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 9451;
}
return 11185;
}, protocolVersion -> (double) 0.75f),
TRAPDOOR(protocolVersion -> {
// We have to use wooden trapdoors for 1.7 since 1.7 doesn't have iron trapdoors
@@ -135,7 +138,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 12380;
}
return 12582;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 12582;
}
return 14429;
}, protocolVersion -> 0.1875),
END_PORTAL_FRAME(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -183,7 +189,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 9272;
}
return 9473;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 9473;
}
return 11207;
}, protocolVersion -> 0.8125),
DAYLIGHT_SENSOR(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -234,7 +243,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 11093;
}
return 11295;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 11295;
}
return 13062;
}, protocolVersion -> 0.375),
COBBLESTONE_WALL(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -282,7 +294,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 9783;
}
return 9984;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 9984;
}
return 11726;
}, protocolVersion -> 1.5),
STONE_SLABS(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -333,7 +348,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 13197;
}
return 13399;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 13399;
}
return 15252;
}, protocolVersion -> 0.5),
WHITE_CARPET(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -384,7 +402,10 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 12694;
}
return 12896;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 12896;
}
return 14743;
}, protocolVersion -> protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 0 : 0.0625);
private final Function<ProtocolVersion, Integer> id;
@@ -42,7 +42,11 @@ public final class DimensionRegistry {
public final CompoundBinaryTag CODEC_1_21_5;
public final CompoundBinaryTag CODEC_1_21_11;
public final CompoundBinaryTag CODEC_26_1;
public final CompoundBinaryTag CODEC_26_2;
public final CompoundBinaryTag CODEC_26_3;
public final CompoundBinaryTag TAGS_26_1;
public final CompoundBinaryTag TAGS_26_2;
public final CompoundBinaryTag TAGS_26_3;
static {
CODEC_1_16 = getCodec("codec_1_16.nbt");
@@ -59,7 +63,11 @@ public final class DimensionRegistry {
CODEC_1_21_5 = getCodec("codec_1_21_5.nbt");
CODEC_1_21_11 = getCodec("codec_1_21_11.nbt");
CODEC_26_1 = getCodec("codec_26_1.nbt");
CODEC_26_2 = getCodec("codec_26_2.nbt");
CODEC_26_3 = getCodec("codec_26_3.nbt");
TAGS_26_1 = getCodec("tags_26_1.nbt");
TAGS_26_2 = getCodec("tags_26_2.nbt");
TAGS_26_3 = getCodec("tags_26_3.nbt");
}
private @NotNull CompoundBinaryTag getCodec(final @NotNull String fileName) {
@@ -67,7 +67,10 @@ public enum EntityType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
return 87;
}
return 89;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 89;
}
return 90;
}),
MINECART(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
@@ -112,7 +115,10 @@ public enum EntityType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
return 84;
}
return 85;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 85;
}
return 86;
});
private final Function<ProtocolVersion, Integer> id;
@@ -85,7 +85,13 @@ public enum ItemType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 1104;
}
return 1105;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_1)) {
return 1105;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 1133;
}
return 1238;
}, protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
return 26;
@@ -99,7 +105,10 @@ public enum ItemType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
return 44;
}
return 46;
if (protocolVersion.lessThanOrEquals(MINECRAFT_26_2)) {
return 46;
}
return 48;
});
private final Function<ProtocolVersion, Integer> id;
@@ -50,7 +50,7 @@ public final class RegistryDataPacket implements SonarPacket {
for (final RegistryDataPacket.Bundle bundle : bundles) {
ProtocolUtil.writeString(byteBuf, bundle.getName());
// Write the bundle tag
final CompoundBinaryTag tag = bundle.getTag();
final BinaryTag tag = bundle.getTag();
if (tag != null) {
byteBuf.writeBoolean(true);
ProtocolUtil.writeBinaryTag(byteBuf, protocolVersion, tag);
@@ -73,8 +73,7 @@ public final class RegistryDataPacket implements SonarPacket {
final ArrayList<RegistryDataPacket.Bundle> bundles = new ArrayList<>();
for (final BinaryTag binaryTag : rootTag.getCompound(type).getList("value")) {
final CompoundBinaryTag tag = (CompoundBinaryTag) binaryTag;
// CompoundBinaryTag#getCompound(String) will return an empty compound tag when not exist.
bundles.add(new Bundle(tag.getString("name"), tag.get("element") == null ? null : tag.getCompound("element")));
bundles.add(new Bundle(tag.getString("name"), tag.get("element")));
}
packets[index++] = new SonarPacketSnapshot(new RegistryDataPacket(rootTag, type, bundles));
}
@@ -86,6 +85,6 @@ public final class RegistryDataPacket implements SonarPacket {
public static class Bundle {
@NotNull String name;
// In the protocol, it is able to be null
@Nullable CompoundBinaryTag tag;
@Nullable BinaryTag tag;
}
}
@@ -38,6 +38,7 @@ public final class LoginSuccessPacket implements SonarPacket {
private UUID uuid;
private String username;
private boolean strictErrorHandling;
private UUID sessionId;
@Override
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
@@ -61,6 +62,10 @@ public final class LoginSuccessPacket implements SonarPacket {
// Whether the client should disconnect on its own if it receives invalid data from the server
byteBuf.writeBoolean(strictErrorHandling);
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
ProtocolUtil.writeUUID(byteBuf, sessionId);
}
}
@Override
@@ -46,6 +46,8 @@ public final class AnimationPacket implements SonarPacket {
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) {
entityId = byteBuf.readInt();
type = LegacyAnimationType.getById(byteBuf.readByte());
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
hand = MAIN_HAND;
} else if (protocolVersion.greaterThan(ProtocolVersion.MINECRAFT_1_8)) {
// Only 1.9+ clients have an offhand
hand = ProtocolUtil.readVarInt(byteBuf);
@@ -32,6 +32,15 @@ import xyz.jonesdev.sonar.common.util.ProtocolUtil;
@AllArgsConstructor
public final class ConfirmTeleportationPacket implements SonarPacket {
private int teleportId;
private double x;
private double y;
private double z;
private float yaw;
private float pitch;
public ConfirmTeleportationPacket(final int teleportId) {
this.teleportId = teleportId;
}
@Override
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
@@ -41,5 +50,12 @@ public final class ConfirmTeleportationPacket implements SonarPacket {
@Override
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
teleportId = ProtocolUtil.readVarInt(byteBuf);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
x = byteBuf.readDouble();
y = byteBuf.readDouble();
z = byteBuf.readDouble();
yaw = byteBuf.readFloat();
pitch = byteBuf.readFloat();
}
}
}
@@ -58,6 +58,7 @@ public final class JoinGamePacket implements SonarPacket {
private boolean flat;
private boolean limitedCrafting;
private boolean secureProfile;
private boolean onlineMode;
@Override
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
@@ -147,8 +148,14 @@ public final class JoinGamePacket implements SonarPacket {
ProtocolUtil.writeString(byteBuf, levelName);
byteBuf.writeLong(partialHashedSeed);
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
ProtocolUtil.writeVarInt(byteBuf, gamemode);
// ByteBufCodecs#OPTIONAL_VAR_INT: 0 for empty, (value + 1) if present
ProtocolUtil.writeVarInt(byteBuf, previousGamemode == -1 ? 0 : previousGamemode + 1);
} else {
byteBuf.writeByte(gamemode);
byteBuf.writeByte(previousGamemode);
}
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_16)) {
@@ -168,7 +175,10 @@ public final class JoinGamePacket implements SonarPacket {
ProtocolUtil.writeVarInt(byteBuf, seaLevel);
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_2)) {
byteBuf.writeBoolean(onlineMode);
byteBuf.writeBoolean(secureProfile);
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
byteBuf.writeBoolean(secureProfile);
}
}
@@ -24,6 +24,7 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.EncoderException;
import io.netty.util.AttributeKey;
import io.netty.util.Version;
import lombok.experimental.UtilityClass;
import net.kyori.adventure.nbt.BinaryTag;
@@ -217,9 +218,20 @@ public class ProtocolUtil {
}
}
public static final AttributeKey<Boolean> CLOSING = AttributeKey.valueOf("sonar-graceful-close-in-progress");
public static void closeWith(final @NotNull Channel channel,
final @NotNull ProtocolVersion protocolVersion,
final @NotNull Object msg) {
// Mark this channel as already undergoing a graceful close *before* we queue the
// write. If something downstream (e.g. an exception thrown right after this call,
// such as VerificationHandler#fail()'s QuietDecoderException) reaches
// TailExceptionsHandler while our writeAndFlush(...).addListener(CLOSE) is still
// in flight, that handler must not call ctx.close() a second time - doing so can
// abort the still-pending write and deliver only a truncated packet to the client
// (which then sees a bare disconnect/reset instead of our kick message).
// See: https://github.com/jonesdevelopment/sonar/issues/476
channel.attr(CLOSING).set(true);
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) {
channel.eventLoop().execute(() -> {
channel.config().setAutoRead(false);
@@ -20,6 +20,7 @@ package xyz.jonesdev.sonar.common.verification;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.Sonar;
import xyz.jonesdev.sonar.api.antibot.SonarUser;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.protocol.CaptchaPreparer;
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
import xyz.jonesdev.sonar.common.protocol.map.MapCaptchaInfo;
@@ -43,9 +44,15 @@ public final class CaptchaHandler extends VerificationHandler {
this.tries = Sonar.get0().getConfig().getVerification().getMap().getMaxTries();
// We may not be on slot 4, so we need to make sure to synchronize the current slot
user.delayedWrite(CAPTCHA_HELD_ITEM_SLOT);
user.delayedWrite(CAPTCHA_SET_CONTAINER_SLOT);
final boolean placeInOffhand = Sonar.get().getConfig().getVerification().getMap().isPlaceInOffhand()
&& user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_9);
if (placeInOffhand) {
user.delayedWrite(CAPTCHA_SET_CONTAINER_SLOT_OFFHAND);
} else {
// We may not be on slot 4, so we need to make sure to synchronize the current slot
user.delayedWrite(CAPTCHA_HELD_ITEM_SLOT);
user.delayedWrite(CAPTCHA_SET_CONTAINER_SLOT);
}
// Send random captcha to the player
final MapCaptchaInfo captcha = CaptchaPreparer.getRandomCaptcha();
this.answer = captcha.getAnswer().toLowerCase();
@@ -19,6 +19,7 @@ package xyz.jonesdev.sonar.common.verification;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.Sonar;
import xyz.jonesdev.sonar.api.antibot.AntiBot;
import xyz.jonesdev.sonar.api.antibot.SonarUser;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
@@ -35,11 +36,14 @@ public final class GravityHandler extends VerificationHandler {
super(user);
this.preJoinHandler = preJoinHandler;
// Bedrock users start falling immediately
this.canFall = user.isGeyser();
// Client can send movement packet without first position-and-rot packet (usually caused by teleport, < 26.3 Java)
// 26.3+ client will no longer send movement packet for teleports. (positions included in teleport confirm)
this.canFall = user.isGeyser() || user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3);
// We don't want to check Geyser players for valid gravity, as this might cause issues because of the protocol
this.enableGravityCheck = !user.isGeyser() && Sonar.get0().getConfig().getVerification().getGravity().isEnabled();
this.enableCollisionsCheck = !user.isGeyser() && Sonar.get0().getConfig().getVerification().getGravity().isCheckCollisions();
this.enableGravityCheck = !user.isGeyser() && AntiBot.shouldPerform(
Sonar.get0().getConfig().getVerification().getGravity().getTiming());
this.enableCollisionsCheck = !user.isGeyser() && AntiBot.shouldPerform(
Sonar.get0().getConfig().getVerification().getGravity().getCollisionTiming());
// First, write the JoinGame packet to the buffer
user.delayedWrite(joinGame);
@@ -105,6 +109,8 @@ public final class GravityHandler extends VerificationHandler {
final SetPlayerPositionRotationPacket position = (SetPlayerPositionRotationPacket) packet;
if (teleported) {
handleMovement(position.getX(), position.getY(), position.getZ(), position.isOnGround(), true);
} else if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return;
} else if (user.getProtocolVersion().equals(ProtocolVersion.MINECRAFT_1_21_2)) {
lastPositionPacket = position;
return;
@@ -119,6 +125,8 @@ public final class GravityHandler extends VerificationHandler {
if (teleported) {
final SetPlayerPositionPacket position = (SetPlayerPositionPacket) packet;
handleMovement(position.getX(), position.getY(), position.getZ(), position.isOnGround(), false);
} else if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
return;
}
checkClientTick();
} else if (packet instanceof ConfirmTeleportationPacket) {
@@ -130,11 +138,15 @@ public final class GravityHandler extends VerificationHandler {
checkState(confirmTeleport.getTeleportId() == expectedTeleportId,
"expected TP ID " + expectedTeleportId + ", but got " + confirmTeleport.getTeleportId());
final boolean v26_3 = user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3);
final boolean sendPosRotBefore = user.getProtocolVersion().equals(ProtocolVersion.MINECRAFT_1_21_2);
checkState(sendPosRotBefore ? lastPositionPacket != null : !expectTeleportPosRot,
"expected position rotation but got teleport confirm.");
if (!sendPosRotBefore) {
expectTeleportPosRot = true;
if (!v26_3) {
checkState(sendPosRotBefore ? lastPositionPacket != null : !expectTeleportPosRot,
"expected position rotation but got teleport confirm.");
if (!sendPosRotBefore) {
expectTeleportPosRot = true;
}
}
// The first teleport ID is not useful for us in this context, skip it
@@ -144,7 +156,11 @@ public final class GravityHandler extends VerificationHandler {
// Enable the movement checks
teleported = true;
if (sendPosRotBefore) {
if (v26_3) {
handleMovement(
confirmTeleport.getX(), confirmTeleport.getY(), confirmTeleport.getZ(),
false, true);
} else if (sendPosRotBefore) {
handleMovement(
lastPositionPacket.getX(), lastPositionPacket.getY(), lastPositionPacket.getZ(),
lastPositionPacket.isOnGround(), true);
@@ -245,7 +261,8 @@ public final class GravityHandler extends VerificationHandler {
// The deltaY is 0 whenever the player sends their first position packet.
// We have to account for this or the player will falsely fail the verification.
if (deltaY == 0) {
checkState(rotated, "illegal movement packet order: " + deltaY);
checkState(user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3) || rotated,
"illegal movement packet order: " + deltaY);
checkState(movementTick == 0, "illegal y motion: " + movementTick);
// 1.7 clients immediately start falling after this packet
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_8)) {
@@ -19,6 +19,7 @@ package xyz.jonesdev.sonar.common.verification;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.Sonar;
import xyz.jonesdev.sonar.api.antibot.AntiBot;
import xyz.jonesdev.sonar.api.antibot.SonarUser;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
@@ -70,7 +71,8 @@ public final class ProtocolHandler extends VerificationHandler {
waitingSlotConfirm = false;
expectedSlotId = -1;
// The player did not send duplicate packets, so they pass this check
if (user.isGeyser()) {
// 26.3+ removed client-side swing packet echo, so exempt 26.3+ from the arm animation check
if (user.isGeyser() || user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_3)) {
markSuccess();
} else {
sendArmAnimation();
@@ -163,7 +165,8 @@ public final class ProtocolHandler extends VerificationHandler {
private void markSuccess() {
// Pass the player to the next best verification handler
if (!user.isGeyser() && Sonar.get0().getConfig().getVerification().getVehicle().isEnabled()) {
if (!user.isGeyser()
&& AntiBot.shouldPerform(Sonar.get0().getConfig().getVerification().getVehicle().getTiming())) {
user.channel().pipeline().get(SonarPacketDecoder.class).setListener(new VehicleHandler(user));
} else if (user.isForceCaptcha() || Sonar.get0().getAntiBot().shouldPerformCaptcha()) {
user.channel().pipeline().get(SonarPacketDecoder.class).setListener(new CaptchaHandler(user));
@@ -31,14 +31,13 @@ import xyz.jonesdev.sonar.common.netty.MinecraftVarIntLengthEncoder;
import xyz.jonesdev.sonar.common.protocol.SonarPacketDecoder;
import xyz.jonesdev.sonar.common.protocol.SonarPacketEncoder;
import xyz.jonesdev.sonar.common.protocol.SonarPacketListener;
import xyz.jonesdev.sonar.common.protocol.packets.play.TransferPacket;
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
import java.util.Random;
import static xyz.jonesdev.sonar.common.protocol.SonarPacketPreparer.transferToOrigin;
@RequiredArgsConstructor
public abstract class VerificationHandler implements SonarPacketListener {
protected final SonarUser user;
@@ -57,17 +56,28 @@ public abstract class VerificationHandler implements SonarPacketListener {
// If enabled, transfer the player back to the origin server.
// This feature was introduced by Mojang in Minecraft version 1.20.5.
if (transferToOrigin != null && user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)
&& Sonar.get0().getConfig().getGeneralConfig().getBoolean("verification.transfer.enabled")) {
// Use the original handshake hostname if configured and available (for forced hosts / proxy setups),
// otherwise fall back to the configured destination host.
final String hostname = user.getHostname();
final boolean useHandshake = Sonar.get0().getConfig().getGeneralConfig()
.getBoolean("verification.transfer.use-handshake-hostname");
final String destinationHost = useHandshake && hostname != null && !hostname.isEmpty()
? hostname
: Sonar.get0().getConfig().getGeneralConfig().getString("verification.transfer.destination-host");
final int destinationPort = Sonar.get0().getConfig().getGeneralConfig().getInt("verification.transfer.destination-port");
final TransferPacket transferPacket = new TransferPacket(destinationHost, destinationPort);
// Send the transfer packet to the player (and close the channel if on Java Edition)
if (user.isGeyser()) {
user.write(transferToOrigin);
user.write(transferPacket);
// Make sure we cannot receive any more packets from the player
user.channel().pipeline().remove(SonarPacketDecoder.class);
user.channel().pipeline().remove(SonarPacketEncoder.class);
user.channel().pipeline().remove(MinecraftVarInt21FrameDecoder.class);
user.channel().pipeline().remove(MinecraftVarIntLengthEncoder.class);
} else {
ProtocolUtil.closeWith(user.channel(), user.getProtocolVersion(), transferToOrigin);
ProtocolUtil.closeWith(user.channel(), user.getProtocolVersion(), transferPacket);
}
} else {
// Disconnect player with the verification success message
@@ -111,7 +121,7 @@ public abstract class VerificationHandler implements SonarPacketListener {
// The user is allowed to disable the blacklist entirely by setting the threshold to 0
final int limit = Sonar.get0().getConfig().getVerification().getBlacklistThreshold();
// The player hasn't been blacklisted yet, so skip this iteration
if (newScore < limit) break blacklist;
if (limit <= 0 || newScore < limit) break blacklist;
GlobalSonarStatistics.totalBlacklistedPlayers++;
+13 -3
View File
@@ -80,7 +80,7 @@ verification:
# Všechny předpokládané pohyby jsou předpočítány, kvůli ušetření výkonu
gravity:
# Měl by Sonar zkoušet pro gravitaci hráče (Doporučováno)
enabled: true
timing: ALWAYS
# Měl by Sonar přimět hráče, aby vyřešil CAPTCHA, pokud neuspějí při kontrole gravitace?
captcha-on-fail: false
# Maximální počet ticků, který má hráč padat aby byl puštěn na verifikační platformu
@@ -89,12 +89,12 @@ verification:
# Kontroluje, zda hráč naráží do bloků, které se vytvořily pod ním
collision:
# Měl by Sonar zkoušet jestli se hráč dotýka bloku? (Doporučováno)
enabled: true
timing: ALWAYS
# Kontroluje, zda klient odesílá správné pakety při montáži vozidla
vehicle:
# Měl by sonar kontrolovat, zda hráč správně vstoupil na loď?
enabled: true
timing: ALWAYS
# Minimální počet paketů odeslaných klientem
minimum-packets: 2
@@ -125,6 +125,9 @@ verification:
# Znaky (čísla a písmena), které jsou povoleny k zobrazování v CAPTCHE
# Nedoporučuje se přidávat čísla nebo písmena, která by se mohla navzájem podobat
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Zkouší pokuď hráč posílá správný "client brand packet" serveru
client-brand:
@@ -152,12 +155,19 @@ verification:
# TransferTool pro Geyser, aby byli hráči Bedrocku přesměrováni na správný server.
# https://github.com/onebeastchris/TransferTool
enabled: false
# Pokud používáte proxy s forced hosts, Sonar může použít název hostitele,
# se kterým se hráč původně připojil (z handshake paketu), jako cíl přenosu.
# Vypněte to, pokud jsou vaše forced hosts pouze pro interní směrování
# a chcete, aby všichni hráči byli přeneseni na nakonfigurovaný destination-host.
use-handshake-hostname: false
# Na který server by měl Sonar přenést hráče, když projde ověřením?
# Zadejte IP serveru, který hráči používají k běžnému připojení k vašemu serveru.
# Například můžete zadat "mc.hypixel.net" nebo přímou IP jako "1.1.1.1"
destination-host: "play.my-server.com"
# Jaký port by měl Sonar použít při přenosu hráče na původní server?
# Pokud váš server nepotřebuje port pro připojení, můžete toto ponechat jako 25565.
# Pokud používáte forced hosts (use-handshake-hostname: true), nastavte to na port,
# na kterém proxy naslouchá (port "bind" v konfiguraci vašeho proxy).
destination-port: 25565
# Gamemode hráče při verifikaci
+14 -3
View File
@@ -77,7 +77,7 @@ verification:
# Alle vorhergesagten Bewegungen werden vorausberechnet, um die Leistung zu sparen
gravity:
# Soll Sonar auf gültige Client-Gravitation prüfen? (Empfohlen)
enabled: true
timing: ALWAYS
# Soll Sonar den Spieler dazu bringen, ein CAPTCHA zu lösen, wenn er die Schwerkraftprüfung nicht besteht?
captcha-on-fail: false
# Maximale Anzahl an Ticks, die der Spieler fallen muss, um die Plattform erreichen zu dürfen
@@ -86,12 +86,12 @@ verification:
# Prüft, ob der Spieler mit Blöcken kollidiert, die unter ihm gespawnt sind
collision:
# Soll Sonar prüfen, ob der Spieler mit Blöcken kollidiert? (Empfohlen)
enabled: true
timing: ALWAYS
# Überprüft, ob der Spieler beim Einsteigen in ein Boot die richtigen Pakete sendet
vehicle:
# Sollte Sonar prüfen, ob der Spieler richtig in ein Fahrzeug einsteigt?
enabled: true
timing: ALWAYS
# Mindestanzahl der vom Client gesendeten Pakete
minimum-packets: 2
@@ -122,6 +122,9 @@ verification:
# Zeichen (Buchstaben und Zahlen), die im Antwort-CAPTCHA erscheinen dürfen
# Es wird nicht empfohlen, Zahlen oder Buchstaben hinzuzufügen, die einander ähneln könnten
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Überprüft, ob die Spieler eine gültige Client-Marke an den Server senden
client-brand:
@@ -149,12 +152,20 @@ verification:
# TransferTool für Geyser einrichten, damit Bedrock-Spieler auf den richtigen Server umgeleitet werden.
# https://github.com/onebeastchris/TransferTool
enabled: false
# Wenn Sie einen Proxy mit forced hosts verwenden, kann Sonar den Hostnamen,
# mit dem der Spieler ursprünglich verbunden war (aus dem Handshake-Paket),
# als Übertragungsziel verwenden.
# Deaktivieren Sie diese Option, wenn Ihre forced hosts nur für das interne
# Routing sind und alle Spieler zum konfigurierten destination-host übertragen werden sollen.
use-handshake-hostname: false
# Auf welchen Server soll Sonar den Spieler übertragen, wenn die Verifizierung bestanden wurde?
# Bitte geben Sie die Server-IP ein, die von Spielern verwendet wird, um sich zu verbinden.
# Sie können beispielsweise "mc.hypixel.net" oder eine direkte IP wie "1.1.1.1" verwenden.
destination-host: "play.my-server.com"
# Welchen Port sollte Sonar verwenden, wenn der Spieler auf den Ursprungsserver gesendet wird?
# Wenn Ihr Server keinen Port zum Herstellen einer Verbindung benötigt, können Sie diesen auf 25565 belassen.
# Wenn Sie forced hosts verwenden (use-handshake-hostname: true), setzen Sie dies auf
# den Port, auf dem der Proxy horcht (den "Bind"-Port in Ihrer Proxy-Konfiguration).
destination-port: 25565
# Der Spielmodus des Spielers während der Überprüfung
+13 -3
View File
@@ -79,7 +79,7 @@ verification:
# All predicted motions are precalculated to save performance
gravity:
# Should Sonar check for valid client gravity? (Recommended)
enabled: true
timing: ALWAYS
# Should Sonar make the player solve a CAPTCHA if they fail the gravity check?
captcha-on-fail: false
# The number of ticks the player has to fall to be allowed to hit the platform
@@ -88,12 +88,12 @@ verification:
# Checks if the player is colliding with blocks spawned below them
collision:
# Should Sonar check if the player collides with blocks? (Recommended)
enabled: true
timing: ALWAYS
# Checks if the client sends proper packets when entering a boat
vehicle:
# Should Sonar check if the player properly enters a boat?
enabled: true
timing: ALWAYS
# Minimum number of packets sent by the client
minimum-packets: 2
@@ -125,6 +125,9 @@ verification:
# It is not recommended to add numbers or letters that might look like one another.
# You should only edit this if you know what you're doing
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Checks if the players are sending a valid client brand to the server
client-brand:
@@ -152,12 +155,19 @@ verification:
# TransferTool for Geyser, so Bedrock players are redirected to the correct server.
# https://github.com/onebeastchris/TransferTool
enabled: false
# When behind a proxy with forced hosts, Sonar can use the hostname the player
# originally connected with (from the handshake packet) as the transfer destination.
# Disable this if your forced hosts are for internal routing only and you want
# all players to be transferred to the configured destination-host instead.
use-handshake-hostname: false
# Which server should Sonar transfer the player to when the verification is passed?
# Please enter the server IP used by players to normally connect to your server.
# For example, you can put "mc.hypixel.net" or a direct IP like "1.1.1.1"
destination-host: "play.my-server.com"
# Which port should Sonar use when transferring the player to the origin server?
# If your server does not need a port to connect to, you can leave this as 25565.
# If you are using forced hosts (use-handshake-hostname: true), set this to
# the port the proxy is listening on (the "bind" port in your proxy config).
destination-port: 25565
# The gamemode of the player during verification
+14 -3
View File
@@ -79,7 +79,7 @@ verification:
# Tous les mouvements prévus sont précalculés afin d'économiser les performances
gravity:
# Sonar devrait-il vérifier la gravité du client ? (Recommandé)
enabled: true
timing: ALWAYS
# Sonar devrait-il faire résoudre un CAPTCHA au joueur s'il échoue à la vérification de la gravité ?
captcha-on-fail: false
# Nombre maximum de ticks que le joueur a pour tomber avant de pouvoir toucher la plateforme
@@ -88,12 +88,12 @@ verification:
# Vérifie si le joueur entre en collision avec les blocs apparus en dessous de lui
collision:
# Sonar devrait-il vérifier si le joueur entre en collision avec des blocs ? (Recommandé)
enabled: true
timing: ALWAYS
# Vérifie si le client envoie les paquets appropriés lorsqu'il monte dans un véhicule
vehicle:
# Sonar devrait-il vérifier si le joueur entre correctement dans un bateau ?
enabled: true
timing: ALWAYS
# Nombre minimum de paquets envoyés par le client
minimum-packets: 2
@@ -124,6 +124,9 @@ verification:
# Caractères (lettres et chiffres) autorisés à apparaître dans la réponse au CAPTCHA
# Il n'est pas recommandé d'ajouter des chiffres ou des lettres qui pourraient se ressembler
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Vérifie si le joueur envoie une marque client valide au serveur
client-brand:
@@ -151,12 +154,20 @@ verification:
# TransferTool pour Geyser, afin que les joueurs Bedrock soient redirigés vers le bon serveur.
# https://github.com/onebeastchris/TransferTool
enabled: false
# Lorsque vous utilisez un proxy avec forced hosts, Sonar peut utiliser le nom d'hôte
# que le joueur a utilisé initialement pour se connecter (du paquet handshake) comme
# destination du transfert.
# Désactivez cette option si vos forced hosts sont uniquement pour le routage interne
# et que vous souhaitez que tous les joueurs soient transférés vers le destination-host configuré.
use-handshake-hostname: false
# Quel serveur Sonar devrait-il utiliser pour transférer le joueur une fois la vérification réussie ?
# Veuillez entrer l'adresse IP du serveur que les joueurs utilisent normalement pour se connecter à votre serveur.
# Par exemple, vous pouvez mettre "mc.hypixel.net" ou une IP directe comme "1.1.1.1"
destination-host: "play.my-server.com"
# Quel port Sonar devrait-il utiliser pour transférer le joueur au serveur d'origine ?
# Si votre serveur n'a pas besoin d'un port pour se connecter, vous pouvez laisser celui-ci comme 25565.
# Si vous utilisez forced hosts (use-handshake-hostname: true), définissez ce port sur
# le port d'écoute du proxy (le port "bind" dans la configuration de votre proxy).
destination-port: 25565
# Le mode de jeu du joueur pendant la vérification
+14 -3
View File
@@ -79,7 +79,7 @@ verification:
# ყველა პროგნოზირებული მოძრაობა წინასწარ არის გათვლილი შესრულების სისწრაფის შესანარჩუნებლად
gravity:
# უნდა შეამოწმოს თუ არა Sonar-მა მოთამაშის (ან ბოტის) გრავიტაცია? (რეკომენდებულია)
enabled: true
timing: ALWAYS
# უნდა აიძულოს თუ არა Sonar-მა მოთამაშეს შეასრულოს CAPTCHA, თუ ისინი ვერ შეასრულებენ სიმძიმის შემოწმებას?
captcha-on-fail: false
# ტიკების მაქსიმალური რაოდენობა რომელითაც მოთამაშე უნდა დაეცეს, რათა პლატფორმაზე დაცემა შეეძლოს. (20 ტიკი = 1 წამი)
@@ -88,12 +88,12 @@ verification:
# ამოწმებს, ეჯახება თუ არა მოთამაშე მათ ქვემოთ წარმოქმნილ ბლოკებს
collision:
# უნდა შეამოწმოს თუ არა Sonar-მა, ეტაკება თუ არა მოთამაშე ბლოკებს? (რეკომენდებულია)
enabled: true
timing: ALWAYS
# ამოწმებს, აგზავნის თუ არა კლიენტი შესაბამის პაკეტებს სატრანსპორტო საშუალებაზე დაჯდომის დროს
vehicle:
# უნდა შეამოწმოს თუ არა სონარმა მოთამაშე სწორად შესული თუ არა ნავში?
enabled: true
timing: ALWAYS
# კლიენტის მიერ გაგზავნილი პაკეტების მინიმალური რაოდენობა
minimum-packets: 2
@@ -124,6 +124,9 @@ verification:
# სიმბოლოები (ასოები და რიცხვები), რომლებიც დაშვებულია გამოჩნდეს CAPTCHA-ს პასუხში
# არ არის რეკომენდებული რიცხვების ან ასოების დამატება, რომლებიც შეიძლება ერთმანეთს ჰგავდეს
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# ამოწმებს, აგზავნიან თუ არა მოთამაშეები სერვერზე რეალურ მოთამაშის მეტსახელს
client-brand:
@@ -150,12 +153,20 @@ verification:
# TransferTool Geyser-ისთვის, ასე რომ Bedrock მოთამაშეები გადამისამართდებიან სწორ სერვერზე.
# https://github.com/onebeastchris/TransferTool
enabled: false
# როდესაც იყენებთ პროქსის forced hosts-თან, Sonar-ს შეუძლია გამოიყენოს ჰოსტის სახელი,
# რომლითაც მოთამაშე თავდაპირველად დაუკავშირდა (handshake პაკეტიდან), როგორც
# ტრანსფერის დანიშნულება.
# გამორთეთ ეს, თუ თქვენი forced hosts არის მხოლოდ შიდა მარშრუტიზაციისთვის
# და გსურთ ყველა მოთამაშის გადაყვანა კონფიგურირებულ destination-host-ზე.
use-handshake-hostname: false
# რომელ სერვერზე უნდა გადაიყვანოს Sonar-მა მოთამაშე ვერიფიკაციის გავლის შემდეგ?
# გთხოვთ, შეიყვანოთ სერვერის IP მისამართი, რომლითაც მოთამაშეები ჩვეულებრივ უერთდებიან თქვენს სერვერს
# მაგალითად, შეგიძლიათ ჩაწეროთ "mc.hypixel.net" ან პირდაპირი IP როგორიცაა "1.1.1.1"
destination-host: "play.my-server.com"
# რომელი პორტი უნდა გამოიყენოს Sonar-მა მოთამაშის საწყის სერვერზე გადაყვანისას?
# თუ თქვენს სერვერს არ სჭირდება პორტი შესასვლელად, შეგიძლიათ დატოვოთ ეს 25565-ზე
# თუ იყენებთ forced hosts-ს (use-handshake-hostname: true), დააყენეთ ეს იმ პორტზე,
# რომელზეც პროქსი უსმენს ("bind" პორტი თქვენი პროქსის კონფიგურაციაში).
destination-port: 25565
# მოთამაშის თამაშის რეჟიმი გადამოწმების დროს
+14 -3
View File
@@ -79,7 +79,7 @@ verification:
# Alle voorspelde bewegingen worden vooraf berekend om prestaties te besparen
gravity:
# Moet Sonar controleren op geldige zwaartekracht van de cliënt? (Aanbevolen)
enabled: true
timing: ALWAYS
# Moet Sonar de speler een CAPTCHA laten oplossen als hij niet slaagt voor de zwaartekracht controle?
captcha-on-fail: false
# Maximaal aantal ticks dat de speler moet laten vallen om het platform te mogen raken
@@ -88,12 +88,12 @@ verification:
# Controleert of de speler botst met blokken die onder hem zijn gespawned
collision:
# Moet Sonar controleren of de speler tegen blokken botst? (Aanbevolen)
enabled: true
timing: ALWAYS
# Controleert of de klant de juiste pakketten verzendt bij het monteren van een voertuig
vehicle:
# Moet Sonar controleren of de speler goed in een boot stapt?
enabled: true
timing: ALWAYS
# Minimaal aantal pakketten verzonden door de cliënt
minimum-packets: 2
@@ -124,6 +124,9 @@ verification:
# Tekens (letters en cijfers) die mogen voorkomen in het antwoord op de CAPTCHA
# Het wordt niet aanbevolen om cijfers of letters toe te voegen die op elkaar lijken
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Controleert of de speler een geldig Minecraft-klantmerk naar de server verzendt
client-brand:
@@ -151,12 +154,20 @@ verification:
# TransferTool voor Geyser, zodat Bedrock spelers worden doorgestuurd naar de juiste server.
# https://github.com/onebeastchris/TransferTool
enabled: false
# Wanneer u een proxy met forced hosts gebruikt, kan Sonar de hostnaam gebruiken
# waarmee de speler oorspronkelijk verbinding maakte (uit het handshake-pakket)
# als overdrachtsbestemming.
# Schakel dit uit als uw forced hosts alleen voor interne routering zijn en u
# wilt dat alle spelers worden overgebracht naar de geconfigureerde destination-host.
use-handshake-hostname: false
# Naar welke server moet Sonar de speler overbrengen wanneer de verificatie is geslaagd?
# Voer het server-IP in dat door spelers wordt gebruikt om normaal verbinding te maken met uw server.
# U kunt bijvoorbeeld "mc.hypixel.net" of een direct IP-adres zoals "1.1.1.1" invoeren
destination-host: "play.my-server.com"
# Welke poort moet Sonar gebruiken bij het overbrengen van de speler naar de oorspronkelijke server?
# Als uw server geen poort nodig heeft om verbinding mee te maken, kunt u dit op 25565 laten staan.
# Als u forced hosts gebruikt (use-handshake-hostname: true), stelt u dit in op
# de poort waarop de proxy luistert (de "bind"-poort in uw proxyconfiguratie).
destination-port: 25565
# De spelmodus van de speler tijdens verificatie
+13 -3
View File
@@ -79,7 +79,7 @@ verification:
# Wszystkie przewidywane ruchy są wstępnie obliczane w celu zachowania wydajności
gravity:
# Czy Sonar powinien sprawdzać poprawność grawitacji gracza? (Zalecane)
enabled: true
timing: ALWAYS
# Czy Sonar powinien zmusić gracza do rozwiązania CAPTCHA, jeśli nie uda mu się przejść testu grawitacji?
captcha-on-fail: false
# Maksymalna liczba tików, po których gracz musi spaść, aby móc uderzyć w platformę.
@@ -88,12 +88,12 @@ verification:
# Sprawdza, czy gracz zderza się z blokami, które pojawiły się pod nim
collision:
# Czy Sonar powinien sprawdzać, czy gracz zderza się z blokami? (Zalecane)
enabled: true
timing: ALWAYS
# Sprawdza, czy gracz wysyła odpowiednie pakiety podczas umieszczania na pojeździe.
vehicle:
# Czy Sonar powinien sprawdzać, czy gracz prawidłowo wsiada do łodzi?
enabled: true
timing: ALWAYS
# Minimalna liczba pakietów wysłanych przez klienta
minimum-packets: 2
@@ -124,6 +124,9 @@ verification:
# Znaki (litery i cyfry), które mogą pojawić się w CAPTCHA
# Nie zaleca się dodawania cyfr lub liter, które mogą być do siebie podobne
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Sprawdza, czy gracz wysyła prawidłowy client brand do serwera.
client-brand:
@@ -151,12 +154,19 @@ verification:
# TransferTool dla Geyser, aby gracze Bedrock byli przekierowywani na właściwy serwer.
# https://github.com/onebeastchris/TransferTool
enabled: false
# Gdy używasz proxy z forced hosts, Sonar może użyć nazwy hosta, z którą
# gracz pierwotnie się łączył (z pakietu handshake) jako celu transferu.
# Wyłącz tę opcję, jeśli twoje forced hosts są tylko do wewnętrznego routingu
# i chcesz, aby wszyscy gracze byli przenoszeni na skonfigurowany destination-host.
use-handshake-hostname: false
# Na który serwer Sonar powinien przenieść gracza po pomyślnym przejściu weryfikacji?
# Wprowadź adres IP serwera, który jest używany przez graczy do normalnego łączenia się z serwerem.
# Na przykład, możesz wpisać "mc.hypixel.net" lub bezpośredni adres IP, taki jak "1.1.1.1".
destination-host: "play.my-server.com"
# Jaki port powinien używać Sonar podczas przenoszenia gracza do serwera początkowego?
# Jeśli serwer nie potrzebuje portu do połączenia, można pozostawić 25565.
# Jeśli używasz forced hosts (use-handshake-hostname: true), ustaw to na port,
# na którym nasłuchuje proxy (port "bind" w konfiguracji twojego proxy).
destination-port: 25565
# Tryb gry gracza (gamemode) podczas weryfikacji
@@ -78,7 +78,7 @@ verification:
# Todos os movimentos previstos são pré-calculados para economizar desempenho
gravity:
# O Sonar deve verificar a gravidade do cliente? (Recomendado)
enabled: true
timing: ALWAYS
# O Sonar deve fazer o jogador resolver um CAPTCHA se falhar na verificação de gravidade?
captcha-on-fail: false
# O número de ticks que o jogador deve cair para ser permitido atingir a plataforma
@@ -87,12 +87,12 @@ verification:
# Verifica se o jogador está colidindo com blocos gerados abaixo dele
collision:
# O Sonar deve verificar se o jogador colide com blocos? (Recomendado)
enabled: true
timing: ALWAYS
# Verifica se o cliente envia pacotes adequados ao entrar em um barco
vehicle:
# O Sonar deve verificar se o jogador entra corretamente em um barco?
enabled: true
timing: ALWAYS
# Número mínimo de pacotes enviados pelo cliente
minimum-packets: 2
@@ -124,6 +124,9 @@ verification:
# Não é recomendável adicionar números ou letras que possam parecer semelhantes.
# Você deve editar isso apenas se souber o que está fazendo
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Verifica se os jogadores estão enviando uma marca de cliente válida para o servidor
client-brand:
@@ -151,12 +154,19 @@ verification:
# o TransferTool para Geyser, para que jogadores Bedrock sejam redirecionados para o servidor correto.
# https://github.com/onebeastchris/TransferTool
enabled: false
# Ao usar um proxy com forced hosts, o Sonar pode usar o hostname que o jogador
# usou originalmente para se conectar (do pacote handshake) como destino da transferência.
# Desative esta opção se seus forced hosts forem apenas para roteamento interno
# e você quiser que todos os jogadores sejam transferidos para o destination-host configurado.
use-handshake-hostname: false
# Para qual servidor o Sonar deve transferir o jogador quando a verificação for passada?
# Por favor, insira o IP do servidor usado pelos jogadores para se conectar normalmente ao seu servidor.
# Por exemplo, você pode colocar "mc.hypixel.net" ou um IP direto como "1.1.1.1"
destination-host: "play.my-server.com"
# Qual porta o Sonar deve usar ao transferir o jogador para o servidor de origem?
# Se seu servidor não precisar de uma porta para se conectar, você pode deixar isso como 25565.
# Se você estiver usando forced hosts (use-handshake-hostname: true), defina isto para
# a porta em que o proxy está ouvindo (a porta "bind" na configuração do seu proxy).
destination-port: 25565
# O modo de jogo do jogador durante a verificação
+15 -3
View File
@@ -79,7 +79,7 @@ verification:
# Все предсказанные движения предварительно просчитываются для экономии производительности
gravity:
# Должен ли Sonar проверять наличие действительной гравитации клиента? (Рекомендуется)
enabled: true
timing: ALWAYS
# Должен ли Sonar заставлять игрока решать CAPTCHA, если он не проходит проверку на гравитацию?
captcha-on-fail: false
# Максимальное количество тиков, на которое должен упасть игрок, чтобы ему было разрешено упасть на платформу
@@ -88,12 +88,12 @@ verification:
# Проверяет, сталкивается ли игрок с блоками, порожденными под ним
collision:
# Должен ли Sonar проверять, сталкивается ли игрок с блоками? (Рекомендуется)
enabled: true
timing: ALWAYS
# Проверяет, отправляет ли клиент правильные пакеты при садке на транспортное средство
vehicle:
# Должен ли сонар проверять, правильно ли игрок входит в лодку?
enabled: true
timing: ALWAYS
# Минимальное количество пакетов, отправляемых клиентом
minimum-packets: 2
@@ -123,6 +123,9 @@ verification:
# Символы (буквы и цифры), которые разрешено использовать в ответе на капчу
# Не рекомендуется добавлять цифры или буквы, которые могут быть похожи друг на друга
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# Проверяет, отправляет ли игрок на сервер действительный клиентский бренд.
client-brand:
@@ -150,12 +153,21 @@ verification:
# TransferTool для Geyser, чтобы игроки Bedrock перенаправлялись на правильный сервер.
# https://github.com/onebeastchris/TransferTool
enabled: false
# При использовании прокси с forced hosts Sonar может использовать имя хоста,
# с которого игрок изначально подключился (из handshake-пакета), в качестве
# адреса назначения при передаче.
# Отключите эту опцию, если ваши forced hosts используются только для внутренней
# маршрутизации и вы хотите, чтобы все игроки перенаправлялись на настроенный
# destination-host.
use-handshake-hostname: false
# На какой сервер должен Sonar переместить игрока после прохождения проверки?
# Введите IP-адрес сервера, который обычно используется игроками для подключения к вашему серверу.
# Например, вы можете указать "mc.hypixel.net" или прямой IP-адрес, например "1.1.1.1"
destination-host: "play.my-server.com"
# Какой порт должен использовать Sonar при перемещении игрока на исходный сервер?
# Если ваш сервер не требует порта для подключения, вы можете оставить это как 25565.
# Если вы используете forced hosts (use-handshake-hostname: true), укажите порт,
# на котором слушает прокси (порт "bind" в конфигурации вашего прокси).
destination-port: 25565
# Режим игрока во время проверки
+13 -3
View File
@@ -78,7 +78,7 @@ verification:
# 检查玩家的下落移动是否遵循原版客户端.
gravity:
# Sonar 是否应该检查玩家的下落移动? (推荐启用)
enabled: true
timing: ALWAYS
# 当玩家验证失败时 是否向他们发送地图验证码?
captcha-on-fail: false
# 玩家跌落在平台上多少tick后才能被算作站在平台上?
@@ -87,12 +87,12 @@ verification:
# 检查玩家是否可以正确地站在方块上
collision:
# Sonar 是否应该生成方块平台以检查玩家下落与方块之间的碰撞? (推荐启用)
enabled: true
timing: ALWAYS
# 检查客户端坐在实体上时是否发送了正确的数据包
vehicle:
# Sonar 是否应该让玩家坐在实体上, 以便检查他们的数据包是否合法?
enabled: true
timing: ALWAYS
# 客户端需要发送的所需的最小数据包数量
minimum-packets: 2
@@ -122,6 +122,9 @@ verification:
# 允许出现在验证码答案中的字符
# 不建议添加可能看起来彼此相似的数字或字母
alphabet: 'abcdefhjkmnoprstuxyz'
# Should Sonar place the map in the player's offhand?
# This only works on Minecraft 1.9 and above.
place-in-offhand: false
# 检查玩家是否正在向服务器发送有效的客户端标识符
client-brand:
@@ -147,12 +150,19 @@ verification:
# TransferTool 扩展, 以便将 Bedrock 玩家重定向到正确的服务器.
# https://github.com/onebeastchris/TransferTool
enabled: false
# 当代理处于 forced hosts 模式时, Sonar 可以使用玩家最初连接时使用的
# 主机名(来自握手包)作为传输目标地址。
# 如果您的 forced hosts 仅用于内部路由, 并且您希望所有玩家都传输到
# 配置的 destination-host, 请禁用此选项。
use-handshake-hostname: false
# 当玩家通过验证后, Sonar 应该将玩家转移到哪个服务器
# 请输入玩家正常连接服务器时使用的服务器IP或域名
# 例如使用域名("mc.hypixel.net") 或使用 IP 地址("1.1.1.1").
destination-host: "play.my-server.com"
# Sonar 应该告诉玩家通过以上域名的什么端口来连接到服务器?
# 如果服务器地址不包含端口 请保留25565.
# 如果您使用 forced hosts (use-handshake-hostname: true), 请将此设置为
# 代理服务器监听的端口 (代理配置中的 "bind" 端口)。
destination-port: 25565
# 玩家正在验证时所使用的游戏模式
@@ -169,7 +169,7 @@ commands:
- ' <dark_aqua>▪ <gray>Aktuální příchozí využitá šířka pásma: <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>Aktuální odchozí využitá šířka pásma: <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>Celková příchozí využitá šířka pásma: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Celková odchozí využitá šířka pásma: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Celková odchozí využitá šířka pásma: <white><outgoing-traffic-ttl>'
# Překlady pro '/sonar dump'
dump:
@@ -169,7 +169,7 @@ commands:
- ' <dark_aqua>▪ <gray>Current incoming used bandwidth: <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>Current outgoing used bandwidth: <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>Total incoming used bandwidth: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Total outgoing used bandwidth: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Total outgoing used bandwidth: <white><outgoing-traffic-ttl>'
# Translations for '/sonar dump'
dump:
@@ -169,7 +169,7 @@ commands:
- ' <dark_aqua>▪ <gray>Ancho de banda entrante utilizado actualmente: <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>Ancho de banda utilizado saliente actual: <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>Ancho de banda entrante total utilizado: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Ancho de banda total utilizado saliente: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Ancho de banda total utilizado saliente: <white><outgoing-traffic-ttl>'
# Translations for '/sonar dump'
dump:
@@ -88,9 +88,9 @@ commands:
# Description de cette sous-commande
description: "Activer ou désactiver les notifications d'attaque"
# Message affiché lorsqu'un joueur s'abonne aux notifications d'attaque de Sonar
subscribed: "<prefix>Vous visualisez maintenant les notifications d'attaque de Sonar."
subscribe: "<prefix>Vous visualisez maintenant les notifications d'attaque de Sonar."
# Message affiché lorsqu'un joueur se désabonne des notifications d'attaque de Sonar
unsubscribed: "<prefix>Vous ne visualisez plus les notifications d'attaque de Sonar."
unsubscribe: "<prefix>Vous ne visualisez plus les notifications d'attaque de Sonar."
# Traductions pour '/sonar blacklist'
blacklist:
@@ -107,7 +107,7 @@ commands:
# Message affiché lorsque quelqu'un supprime une adresse IP de la liste noire
remove: '<prefix>Adresse IP <ip> supprimée avec succès de la liste noire.'
# Message affiché lorsque quelqu'un ajoute une adresse IP à la liste noire, mais qu'elle est déjà en liste noire
duplicate-ip: "<prefix>L'adresse IP que vous avez fournie est déjà sur la liste noire."
ip-duplicate: "<prefix>L'adresse IP que vous avez fournie est déjà sur la liste noire."
# Message affiché lorsque quelqu'un supprime une adresse IP de la liste noire, mais qu'elle n'est pas en liste noire
ip-not-found: "<prefix>L'adresse IP que vous avez fournie ne figure pas sur la liste noire."
@@ -169,7 +169,7 @@ commands:
- ' <dark_aqua>▪ <gray>Banda in ingresso attualmente utilizzata: <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>Banda in uscita attualmente utilizzata: <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>Banda totale in ingresso utilizzata: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Banda totale in uscita utilizzata: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Banda totale in uscita utilizzata: <white><outgoing-traffic-ttl>'
# Traduzioni per '/sonar dump'
dump:
@@ -35,7 +35,7 @@ commands:
# მესიჯი, რომელიც იქნება ნაჩვენები, როდესაც მოთამაშე ცდის /sonar ს ამის უფლების გარეშე
no-permission: '<prefix><red>თქვენ არ გაქვთ უფლება ამ ბრძანების გასაცემად.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როდესაც ბრძანება არასწორად იქნება გაცემული.
incorrect-გამოყენება: '<prefix><red>გამოყენება: /sonar <subcommand-გამოყენება>'
incorrect-usage: '<prefix><red>გამოყენება: /sonar <subcommand-usage>'
# მესიჯი, რომელიც იქნება ნაჩვენები, როდესაც ვინმე გვაწვდის არასწორ IP მისამართს (არასწორი ფორმატით)
invalid-ip-address: '<prefix>თქვენი IP მისამართი, როგორც ჩანს არასწორია.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როდესაც კონსოლი ცდის იმ ბრძანების გაცემას რომლის გაცემაც მხოლოდ მოთამაშეს შეუძლია.
@@ -56,7 +56,7 @@ commands:
- <white><click:open_url:'https://sonar.top/discord/'><hover:show_text:'(დააჭირეთ რომ გახსნათ Discord)'>გახსენით ბილეთი Discord_ზე </hover></click><click:open_url:'https://github.com/jonesdevelopment/sonar/issues'><hover:show_text:'(დააჭირეთ რომ გახსნათ GitHub)'>ან შექმენით ახალი პრობლემის პოსტი GitHub_ზე.
- ''
# ქვე-ბრძანებების ფორმატი რომელიც არის ნაჩვენები მთავარი ბრძანების გაცემის დროს.
subcommands: '<suggest-subcommand><hover:show_text:''<gray>მხოლოდ მოთამაშეები: </gray><only-players><br><gray>აუცილებელია კონსოლი: </gray><only-console><br><gray>უფლება: </gray><white><permission><br><gray>სხვა-სახელი: </gray><aliases>''><dark_aqua> ▪ <gray>/sonar <ქვე-ბრძანება> <white><description></hover></suggest-subcommand>'
subcommands: '<suggest-subcommand><hover:show_text:''<gray>მხოლოდ მოთამაშეები: </gray><only-players><br><gray>აუცილებელია კონსოლი: </gray><only-console><br><gray>უფლება: </gray><white><permission><br><gray>სხვა-სახელი: </gray><aliases>''><dark_aqua> ▪ <gray>/sonar <subcommand> <white><description></hover></suggest-subcommand>'
# ფორმატი კი_სთვის (სტიჩკა) და არა_სთვის (ჯვარი) (გამოიყენება ქვე-ბრძანებებში)
tick: '<green>✔</green>'
cross: '<red>✗</red>'
@@ -169,7 +169,7 @@ commands:
- ' <dark_aqua>▪ <gray>ამჟამინდელი მომდინარე გამოყენებული ქსელის გამოყენება: <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>ამჟამინდელი გამდინარე გამოყენებული ქსელის გამოყენება: <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>ჯამში მომდინარე გამოყენებული ქსელის გამოყენება: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>ჯამში გამდინარე გამოყენებული ქსელის გამოყენება: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>ჯამში გამდინარე გამოყენებული ქსელის გამოყენება: <white><outgoing-traffic-ttl>'
# თარგმანი '/sonar dump' სთვის
dump:
@@ -172,7 +172,7 @@ commands:
- ' <dark_aqua>▪ <gray>Aktualnie używana przychodząca przepustowość: <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>Aktualnie używana przepustowość wychodząca: <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>Całkowita wykorzystana przepustowość przychodząca: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Całkowita wykorzystana przepustowość wychodząca: <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Całkowita wykorzystana przepustowość wychodząca: <white><outgoing-traffic-ttl>'
# Translations for '/sonar dump'
dump:
@@ -169,7 +169,7 @@ commands:
- ' <dark_aqua>▪ <gray>Largura de banda usada atualmente (entrada): <white><incoming-traffic>'
- ' <dark_aqua>▪ <gray>Largura de banda usada atualmente (saída): <white><outgoing-traffic>'
- ' <dark_aqua>▪ <gray>Largura de banda total usada (entrada): <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Largura de banda total usada (saída): <white><incoming-traffic-ttl>'
- ' <dark_aqua>▪ <gray>Largura de banda total usada (saída): <white><outgoing-traffic-ttl>'
# Traduções para '/sonar dump'
dump:
@@ -296,4 +296,4 @@ notifications:
- ' <dark_aqua>▪ <gray>Jogadores na fila: <white><queued>'
- ''
- <gray>Veja mais informações usando <white><click:run_command:'/sonar verbose'><hover:show_text:'(Clique para executar)'>/sonar verbose</hover></click><gray> ou <white><click:run_command:'/sonar stats'><hover:show_text:'(Clique para executar)'>/sonar stats</hover></click><gray>.
- ''
- ''
@@ -56,7 +56,7 @@ commands:
- <white><click:open_url:'https://sonar.top/discord/'><hover:show_text:'(Discord\'u açmak için tıklayın)'>Discord üzerinden bir bilet açın </hover></click><click:open_url:'https://github.com/jonesdevelopment/sonar/issues'><hover:show_text:'(GitHub\'ı açmak için tıklayın)'>veya GitHub üzerinde yeni bir sorun açın.
- ''
# Ana komutu çalıştırırken gösterilen alt komutların listesi için biçimlendirme
subcommands: '<suggest-subcommand><hover:show_text:''<gray>Sadece oyuncular: </gray><only-players><br><gray>Konsol gerekli: </gray><only-console><br><gray>İzin: </gray><white><permission><br><gray>Diğer isimler: </gray><aliases>''><dark_aqua> ▪ <gray>/sonar <suggest-subcommand><subcommand></suggest-subcommand> <white><description></hover></suggest-subcommand>'
subcommands: '<suggest-subcommand><hover:show_text:''<gray>Sadece oyuncular: </gray><only-players><br><gray>Konsol gerekli: </gray><only-console><br><gray>İzin: </gray><white><permission><br><gray>Diğer isimler: </gray><aliases>''><dark_aqua> ▪ <gray>/sonar <subcommand> <white><description></hover></suggest-subcommand>'
# Alt komutların üzerine gelinen metindeki evet (tick) ve hayır (cross) değerleri için biçimlendirme
tick: '<green>✔</green>'
cross: '<red>✗</red>'
@@ -138,7 +138,7 @@ commands:
# Bu alt komut için açıklama
description: "Bu sunucunun oturum istatistiklerini göster"
# İstatistikleri görüntülerken her şeyin üzerinde gösterilen bilgilendirme mesajı
header: 'Bu oturum için <statistics-type> istatistikleri gösteriliyor:'
header: '<prefix>Bu oturum için <statistics-type> istatistikleri gösteriliyor:'
# Message that is shown when a player tries viewing an unknown statistic
unknown-type: '<prefix><red>Bilinmeyen istatistik türü! Mevcut istatistikler: <gray><statistics>'
# Genel istatistik mesajının biçimi
+1 -1
View File
@@ -1,3 +1,3 @@
group=xyz.jonesdev
version=2.1.46
version=2.1.53
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
+6 -7
View File
@@ -1,6 +1,6 @@
[versions]
netty = "4.2.12.Final"
adventure = "4.24.0"
netty = "4.2.19.Final"
adventure = "5.2.0"
adventure-platform = "4.4.1"
bstats = "3.2.1"
libby = "2.0.0-SNAPSHOT"
@@ -8,8 +8,8 @@ pluginyml = "0.6.0"
[plugins]
indra-git = "net.kyori.indra.git:3.2.0"
shadow = "com.gradleup.shadow:9.4.1"
spotless = "com.diffplug.spotless:8.4.0"
shadow = "com.gradleup.shadow:9.6.1"
spotless = "com.diffplug.spotless:8.10.4"
pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" }
pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
pluginyml-paper = { id = "net.minecrell.plugin-yml.paper", version.ref = "pluginyml" }
@@ -20,7 +20,6 @@ adventure-minimessage = { module = "net.kyori:adventure-text-minimessage", versi
adventure-serializer = { module = "net.kyori:adventure-text-serializer-gson", version.ref = "adventure" }
adventure-nbt = { module = "net.kyori:adventure-nbt", version.ref = "adventure" }
adventure-platform-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform" }
adventure-platform-bungee = { module = "net.kyori:adventure-platform-bungeecord", version.ref = "adventure-platform" }
libby-core = { module = "com.alessiodp.libby:libby-core", version.ref = "libby" }
libby-bungee = { module = "com.alessiodp.libby:libby-bungee", version.ref = "libby" }
libby-bukkit = { module = "com.alessiodp.libby:libby-bukkit", version.ref = "libby" }
@@ -30,11 +29,11 @@ bstats-bungee = { module = "org.bstats:bstats-bungeecord", version.ref = "bstats
bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" }
bstats-velocity = { module = "org.bstats:bstats-velocity", version.ref = "bstats" }
imagefilters = "com.jhlabs:filters:2.0.235-1"
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3"
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.4"
annotations = "org.jetbrains:annotations:26.1.0"
simpleyaml = "com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4"
ormlite = "com.j256.ormlite:ormlite-jdbc:6.1"
lombok = "org.projectlombok:lombok:1.18.44"
lombok = "org.projectlombok:lombok:1.18.48"
bungeecord = "net.md-5:bungeecord-proxy:26.1-R0.1-SNAPSHOT"
velocity = "io.papermc.velocity:velocity-proxy:3.5.0-SNAPSHOT"
paper = "io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT"
Binary file not shown.
+3 -1
View File
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+3 -3
View File
@@ -20,7 +20,7 @@
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
# gradlew start up script for POSIX generated by Gradle.
#
# Important for running:
#
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
# ksh gradlew
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
Vendored Executable → Regular
+52 -33
View File
@@ -19,12 +19,39 @@
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
@rem Catch executions from older scripts and ensure they exit cleanly.
@rem This can be removed once we can be reasonably confident that few people
@rem will be migrating directly to this new wrapper.
goto afterSafetyNet
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
goto exitWithErrorLevel
:afterSafetyNet
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@@ -45,13 +72,14 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
1>&2 echo.
1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
1>&2 echo.
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
1>&2 echo location of your Java installation.
goto fail
"%COMSPEC%" /c exit 1
goto exitWithErrorLevel
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -59,35 +87,26 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
1>&2 echo.
1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
1>&2 echo.
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
1>&2 echo location of your Java installation.
goto fail
"%COMSPEC%" /c exit 1
goto exitWithErrorLevel
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
@rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem This label must not be changed. We rely on old scripts being able to jump to this point.
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%
-3
View File
@@ -22,6 +22,3 @@ tasks {
}
}
}
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17