Compare commits

..
106 Commits
Author SHA1 Message Date
Jones df049a7042 Release 2.1.41 (#528) 2025-10-27 13:53:35 +00:00
Jones 8df7874cab Don't invoke initChannel if the channel is closed (https://github.com/jonesdevelopment/sonar/pull/527) 2025-10-27 14:24:29 +01:00
Jones b132fe839e Disable max-online-per-ip if it's 0 or negative 2025-10-23 16:47:28 +02:00
Jones f0bdfa8ef1 Fix filled_map item type id on 1.21.9+ 2025-10-23 13:59:01 +02:00
dependabot[bot] 7899569970 Bump io.netty:netty-all from 4.2.6.Final to 4.2.7.Final (#526)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.6.Final to 4.2.7.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.2.6.Final...netty-4.2.7.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.7.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>
2025-10-20 15:24:04 +00:00
Jones 16d72fc682 Release 2.1.40 (#524) 2025-10-17 12:51:28 +00:00
Giuseppe PerrottaandJones 425a902ec8 Introduce PostgreSQL (#522)
* Introduce PostgreSQL

* update comment

* Mention `POSTGRESQL` in the configuration

---------

Co-authored-by: Jones <admin@jonesdev.xyz>
2025-10-07 13:05:35 +00:00
Jones fcb52fc6c6 Release 2.1.39 (#521) 2025-10-04 08:08:05 +00:00
Jones ac4d566627 Use radial gradient for CAPTCHA text 2025-10-03 11:32:05 +02:00
Jones 0944701797 1.21.9 Support (#520)
* [wip] 1.21.9 Support

* Implement missing BlockType mappings

* Implement missing EntityType mappings

* Implement less-precision vectors for SpawnEntityPacket

* Fix SpawnEntityPacket encoding the wrong values
2025-10-03 08:44:16 +00:00
Jones 9464bffd8e Use Spigot 1.16.5 for better compatibility 2025-10-03 10:26:53 +02:00
Jones 9299edc839 Include font license for kingthings fonts 2025-09-30 20:01:26 +02:00
dependabot[bot] 41eb6d9767 Bump org.projectlombok:lombok from 1.18.40 to 1.18.42 (#517)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.40 to 1.18.42.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.40...v1.18.42)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-version: 1.18.42
  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>
2025-09-22 19:15:17 +00:00
dependabot[bot] 4289b92ab6 Bump io.netty:netty-all from 4.2.5.Final to 4.2.6.Final (#516)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.5.Final to 4.2.6.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.2.5.Final...netty-4.2.6.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.6.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>
2025-09-15 10:55:41 +00:00
Jones b2dddfb0a4 Release 2.1.38 (#515) 2025-09-13 15:12:37 +00:00
Jones ce2fca72f0 Update Dutch translations 2025-09-13 17:05:39 +02:00
Greened 87da706508 Update ka.yml (#514)
* Update ka.yml

* Update ka.yml
2025-09-13 09:30:40 +00:00
Jones 3480bf9332 Make max packet count configurable 2025-09-12 16:59:46 +02:00
Jones 745d01b4d2 Disable expected position but got client tick end check 2025-09-12 16:23:11 +02:00
Jones 4f0d70650b Release 2.1.37 (#511) 2025-09-09 14:54:49 +00:00
AkkariinandJones 2ad0ce11c0 More strict client tick check for 1.21.2+ clients (#496)
* More strict client tick check for 1.21.2+ clients

* [ci skip] fix code style

* Recode `FallbackVehicleHandler`

* [ci skip] fix code style

* Revert "Recode `FallbackVehicleHandler`"

This reverts commit 7eb02ced

* Use ProtocolVersion#equals instead of `==`

* Force-reset `tickWithoutMove` after every move

---------

Co-authored-by: Jones <admin@jonesdev.xyz>
2025-09-09 12:23:58 +00:00
dependabot[bot] fd1e5c9d72 Bump org.projectlombok:lombok from 1.18.38 to 1.18.40 (#508)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.38 to 1.18.40.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.38...v1.18.40)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-version: 1.18.40
  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>
2025-09-08 05:09:27 +00:00
dependabot[bot] e036ce421d Bump io.netty:netty-all from 4.2.4.Final to 4.2.5.Final (#509)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.4.Final to 4.2.5.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.2.4.Final...netty-4.2.5.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.5.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>
2025-09-08 05:09:15 +00:00
Jones cf2628a41f Add notice about Sonar 3.0 to README 2025-09-07 23:03:48 +02:00
Jones fcea8e5f11 Make font loading error slightly more descriptive 2025-09-02 11:51:06 +02:00
dependabot[bot] ad5de38b1d Bump adventure from 4.21.0 to 4.24.0 (#500)
Bumps `adventure` from 4.21.0 to 4.24.0.

Updates `net.kyori:adventure-text-minimessage` from 4.21.0 to 4.24.0
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.21.0...v4.24.0)

Updates `net.kyori:adventure-text-serializer-gson` from 4.21.0 to 4.24.0
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.21.0...v4.24.0)

Updates `net.kyori:adventure-nbt` from 4.21.0 to 4.24.0
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.21.0...v4.24.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-version: 4.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: net.kyori:adventure-text-serializer-gson
  dependency-version: 4.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: net.kyori:adventure-nbt
  dependency-version: 4.24.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>
2025-08-31 18:52:33 +00:00
dependabot[bot] bc0661c10c Bump adventure-platform from 4.4.0 to 4.4.1 (#502)
Bumps `adventure-platform` from 4.4.0 to 4.4.1.

Updates `net.kyori:adventure-platform-bukkit` from 4.4.0 to 4.4.1
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.4.0...v4.4.1)

Updates `net.kyori:adventure-platform-bungeecord` from 4.4.0 to 4.4.1
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.4.0...v4.4.1)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-version: 4.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: net.kyori:adventure-platform-bungeecord
  dependency-version: 4.4.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>
2025-08-31 18:50:18 +00:00
Jones 5e233b4f73 Revert "Refactor vehicle check (#497)"
This reverts commit e7f816fcaa.
2025-08-31 15:43:57 +02:00
AkkariinandJones e7f816fcaa Refactor vehicle check (#497)
* Recode `FallbackVehicleHandler`

* Don't hard-fail in FallbackVehicleHandler#handleMovement

* Keep codestyle consistent with KeepAlive packet

---------

Co-authored-by: Jones <admin@jonesdev.xyz>
2025-08-26 10:29:49 +00:00
dependabot[bot] d87b775b76 Bump io.netty:netty-all from 4.2.2.Final to 4.2.4.Final (#506)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.2.Final to 4.2.4.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.2.2.Final...netty-4.2.4.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.4.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>
2025-08-18 07:52:26 +00:00
Jones b973f70441 Release 2.1.36 (#503) 2025-08-07 11:03:04 +00:00
dependabot[bot] 8d6a45c3b4 Bump net.kyori.indra.git from 3.1.3 to 3.2.0 (#501)
Bumps net.kyori.indra.git from 3.1.3 to 3.2.0.

---
updated-dependencies:
- dependency-name: net.kyori.indra.git
  dependency-version: 3.2.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>
2025-08-04 01:11:31 +00:00
jonesdevelopment 142ce80b9b Simplify max online per IP check 2025-07-31 20:10:39 +02:00
dependabot[bot] a8589e36e2 Bump com.diffplug.spotless from 7.2.0 to 7.2.1 (#498)
Bumps com.diffplug.spotless from 7.2.0 to 7.2.1.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 7.2.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>
2025-07-28 00:32:51 +00:00
Jones 26bee1ca0b 1.21.8 Support (server) 2025-07-22 01:19:23 +02:00
dependabot[bot] 9cfeb59604 Bump com.diffplug.spotless from 7.1.0 to 7.2.0 (#495)
Bumps com.diffplug.spotless from 7.1.0 to 7.2.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 7.2.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>
2025-07-21 07:15:11 +00:00
Jones 8464da8ef2 Update velocity-proxy dependency module 2025-07-14 21:58:35 +02:00
dependabot[bot] 5fa0814329 Bump com.diffplug.spotless from 7.0.4 to 7.1.0 (#493)
Bumps com.diffplug.spotless from 7.0.4 to 7.1.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 7.1.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>
2025-07-14 14:21:18 +00:00
dependabot[bot] 59332b8134 Bump com.github.ben-manes.caffeine:caffeine from 3.2.1 to 3.2.2 (#492)
Bumps [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.2.1...v3.2.2)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-version: 3.2.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>
2025-07-14 14:21:10 +00:00
Jones 3ca1852e03 Release 2.1.35 (#491) 2025-07-09 16:33:22 +00:00
Jones 625a3a1e8e Bump Gradle from 8.14.2 to 8.14.3 2025-07-07 12:01:45 +02:00
dependabot[bot] 646f8f08f6 Bump com.gradleup.shadow from 8.3.7 to 8.3.8 (#490)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 8.3.7 to 8.3.8.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/8.3.7...8.3.8)

---
updated-dependencies:
- dependency-name: com.gradleup.shadow
  dependency-version: 8.3.8
  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>
2025-07-07 09:56:30 +00:00
Jones 947eb7f6a1 Remove locale regex check due to a Minecraft bug
There's a bug in Minecraft where, when no language seems to be selected, the client may send invalid data to the server. As the length of the locale string is already capped in Sonar either way, we are not required to double-check the decoded string using a regex.
2025-07-06 20:10:20 +02:00
Jones 881f826692 Add missing translations for the new feature 2025-07-05 12:44:07 +02:00
Jones 4252362584 Make incorrect captcha message contain attempts left 2025-07-05 12:40:07 +02:00
Jones 7271a2a13f Allow "fell through" check to be skipped by a CAPTCHA 2025-07-03 22:02:28 +02:00
Jones 4343c0e0be Release 2.1.34 (#488) 2025-07-01 13:13:05 +00:00
Jones f42cade9cc 1.21.7 Support 2025-06-30 17:16:16 +02:00
Jones 009dd08cb4 Add missing server versions for 1.21.5-1.21.6 2025-06-30 17:15:53 +02:00
dependabot[bot] 2136da30fa Bump com.gradleup.shadow from 8.3.6 to 8.3.7 (#487)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 8.3.6 to 8.3.7.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/8.3.6...8.3.7)

---
updated-dependencies:
- dependency-name: com.gradleup.shadow
  dependency-version: 8.3.7
  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>
2025-06-30 11:51:27 +00:00
Jones c63b19f42b Release 2.1.33 (#485) 2025-06-20 13:37:58 +00:00
Akkariin 9943b611ad 1.21.6 Support (#484) 2025-06-19 11:52:41 +00:00
dependabot[bot] f151230f44 Bump com.github.ben-manes.caffeine:caffeine from 3.2.0 to 3.2.1 (#483)
Bumps [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.2.0...v3.2.1)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-version: 3.2.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>
2025-06-16 13:17:12 +00:00
Jones 797b6a6d27 Allow action bar to show CPU usage 2025-06-15 15:09:15 +02:00
Jones dc4b9f5be0 Don't allocate DEFAULT removal listener 2025-06-12 15:38:17 +02:00
Jones 2c9bc89b7d Fix possible exception with short brands 2025-06-11 12:54:42 +02:00
Jones 6c1a56d59f Fix client brand check debug 2025-06-11 12:54:16 +02:00
Jones aa986e2c01 Allow disabling of the duplicate brand check 2025-06-11 12:52:51 +02:00
Jones 3bcd5e5d34 Simplify client brand handling 2025-06-11 12:51:52 +02:00
dependabot[bot] 341e647526 Bump io.netty:netty-all from 4.2.1.Final to 4.2.2.Final (#482)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.1.Final to 4.2.2.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.2.1.Final...netty-4.2.2.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.2.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>
2025-06-09 00:51:06 +00:00
Jones d7f48ecdf0 Release 2.1.32 (#479) 2025-06-03 15:33:28 +00:00
dependabot[bot] 2c82047ac3 Bump com.diffplug.spotless from 7.0.3 to 7.0.4 (#478)
Bumps com.diffplug.spotless from 7.0.3 to 7.0.4.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 7.0.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>
2025-06-02 12:28:05 +00:00
Jones d03b8ff195 Bump Gradle from 8.14 to 8.14.1 2025-06-01 12:57:26 +02:00
Jones 183bbc0019 Remove unnecessary client brand check 2025-05-31 16:49:39 +02:00
Jones 31282d81c4 Fix false positives with bad cosmetics mods 2025-05-26 15:27:10 +02:00
Jones f0c143fadf Skip Geyser connections by default 2025-05-18 19:38:34 +02:00
Jones 6be001ede8 Release 2.1.31 (#475) 2025-05-16 18:10:07 +00:00
dependabot[bot] 8044b92fb8 Bump io.netty:netty-all from 4.1.119.Final to 4.2.1.Final (#474)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.1.119.Final to 4.2.1.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.119.Final...netty-4.2.1.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.1.Final
  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>
2025-05-13 14:30:37 +00:00
dependabot[bot] 81b83b5123 Bump adventure-platform from 4.3.4 to 4.4.0 (#473)
Bumps `adventure-platform` from 4.3.4 to 4.4.0.

Updates `net.kyori:adventure-platform-bukkit` from 4.3.4 to 4.4.0
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.3.4...v4.4.0)

Updates `net.kyori:adventure-platform-bungeecord` from 4.3.4 to 4.4.0
- [Release notes](https://github.com/KyoriPowered/adventure-platform/releases)
- [Commits](https://github.com/KyoriPowered/adventure-platform/compare/v4.3.4...v4.4.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-platform-bukkit
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: net.kyori:adventure-platform-bungeecord
  dependency-version: 4.4.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>
2025-05-12 12:25:27 +00:00
Jones a0c054e0a4 Release 2.1.30 (#472) 2025-05-11 10:45:14 +00:00
Jones a668073d17 Bump adventure from 4.20.0 to 4.21.0 2025-05-11 12:33:22 +02:00
Jones 2653754590 Fix Sodium world loading taking too long (#471)
* [wip] Fix Sodium world loading timeout

* Send more chunks because Sodium likes that

* Remove debug-related stuff

* Fix 0,0 chunk not being sent

* Send all chunks to 1.20.3+

* 9 chunks because Sodium is greedy
2025-05-11 10:32:11 +00:00
Jones 7a1d22d922 [ci skip] Update sponsors 2025-05-10 12:16:00 +02:00
Jones f04703405d Fix potential memory leaks on Bukkit (#463)
* Release ByteBuf on invalid handshake data

* Always process non-ByteBuf messages
2025-04-30 15:02:36 +10:00
Jones add066ea0e [ci skip] Update sponsors 2025-04-18 14:30:27 +02:00
Jones 6bc2b1cb82 Release 2.1.29 (#469) 2025-04-17 13:40:14 +02:00
Jones 41e43bcba6 Improve modern CAPTCHA gradient generation 2025-04-17 13:36:49 +02:00
dependabot[bot] d7f150bf6d Bump adventure from 4.18.0 to 4.20.0 (#464)
Bumps `adventure` from 4.18.0 to 4.20.0.

Updates `net.kyori:adventure-text-minimessage` from 4.18.0 to 4.20.0
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.18.0...v4.20.0)

Updates `net.kyori:adventure-text-serializer-gson` from 4.18.0 to 4.20.0
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.18.0...v4.20.0)

Updates `net.kyori:adventure-nbt` from 4.18.0 to 4.20.0
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.18.0...v4.20.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-version: 4.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: net.kyori:adventure-text-serializer-gson
  dependency-version: 4.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: net.kyori:adventure-nbt
  dependency-version: 4.20.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>
2025-04-15 14:40:38 +02:00
Jones 37101c665d Hotfix some kind of handler de-sync (#467) 2025-04-15 14:39:18 +02:00
dependabot[bot] 4b3e88fcda Bump com.diffplug.spotless from 7.0.2 to 7.0.3 (#468)
Bumps com.diffplug.spotless from 7.0.2 to 7.0.3.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 7.0.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>
2025-04-14 07:53:19 +02:00
Jones b10a04294d Allow extension of the action-bar handler 2025-04-13 01:18:09 +02:00
Jones 0b06b59f3a Fix CAPTCHA generator testing 2025-04-13 01:16:20 +02:00
dependabot[bot] a09beb9309 Bump org.projectlombok:lombok from 1.18.36 to 1.18.38 (#465)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.36 to 1.18.38.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.36...v1.18.38)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-version: 1.18.38
  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>
2025-04-07 17:12:56 +02:00
Jones d67b61fa35 Release 2.1.28 (#461) 2025-03-30 11:29:05 +02:00
JonesandAkkariin 57490a7740 1.21.5 Support (#457)
* Add 1.21.5-pre1 protocol version ID

* Add 1.21.5-pre2 protocol version ID

* Start implementing new packet IDs

* Bump setup-gradle from v3 to v4

* Support 1.21.5-rc1 protocol version ID

* [wip] Implement 1.21.5 registry

* Something must have gone wrong while merging

* Support 1.21.5 protocol version ID

* 1.21.5 Support (#459)

* Update registry codec for 1.21.5

* Update mapping id for 1.21.5

* Fix chunk encoding + why this is needed.

* Fix `SystemChatPacket` decoding on 1.21.5

* Clean up entries in 1.21.5 codec

---------

Co-authored-by: Akkariin <fallencrystal@outlook.com>
2025-03-30 11:22:14 +02:00
Jones 834fd2e609 Increase payload packet size limit 2025-03-29 13:08:15 +01:00
Jones 3c3eeb742c Revert "Don't send SetDefaultSpawnPositionPacket"
This reverts commit 445db48925.
2025-03-24 16:53:20 +01:00
Jones 445db48925 Don't send SetDefaultSpawnPositionPacket 2025-03-24 14:11:55 +01:00
Jones f2667390cc Remove unused clientbound VehicleMovePacket 2025-03-24 14:10:44 +01:00
Jones 2e849bf952 Use single instance for FinishConfigurationPacket 2025-03-24 14:07:24 +01:00
Jones 275e0009a4 Skip Carpet fake players (https://github.com/retrooper/packetevents/pull/1171) 2025-03-23 12:03:42 +01:00
Jones 16802e8002 Bump Gradle from 8.12.1 to 8.13 2025-03-14 18:45:39 +01:00
Jones c3d85a9c4a Release 2.1.27 (#456) 2025-03-12 09:57:32 -05:00
Jones 39686177a1 Automatically clean outdated database entries 2025-03-12 15:51:09 +01:00
Jones 3204f62be6 Automatically reconnect remote databases 2025-03-12 15:41:51 +01:00
Jones 73ddcc9f03 Add missing translations 2025-03-12 15:36:45 +01:00
Jones 13cbb5ae1d Implement legacy CAPTCHA design (configurable) 2025-03-12 15:30:22 +01:00
dependabot[bot] a953df33d9 Bump io.netty:netty-all from 4.1.118.Final to 4.1.119.Final (#455)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.1.118.Final to 4.1.119.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.118.Final...netty-4.1.119.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  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>
2025-03-03 09:31:51 +01:00
Jones af12ef535c Release 2.1.26 (#453) 2025-02-28 16:16:22 +01:00
Jones 7de08ffa98 Fix wrong condition in BungeeCord injector 2025-02-28 16:13:28 +01:00
dependabot[bot] c56d41cd77 Bump io.netty:netty-all from 4.1.117.Final to 4.1.118.Final (#451)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.1.117.Final to 4.1.118.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.117.Final...netty-4.1.118.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  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>
2025-02-17 07:20:44 +01:00
Jones 4b30729138 Release 2.1.25 (#449) 2025-02-16 15:45:44 +01:00
Jones 1254514ad2 Improve BungeeCord injection method 2025-02-15 21:23:15 +01:00
Jones b4673d8e9f Prioritize BungeeCord's channel acceptor 2025-02-15 20:47:16 +01:00
Jones 5eaaf88ec8 Tell BungeeCord users about Velocity 2025-02-15 20:15:22 +01:00
Jones 367ce07cb0 Fix incompatibility with latest BungeeCord 2025-02-15 20:13:14 +01:00
70 changed files with 1041 additions and 313 deletions

No files matched your search

+10
View File
@@ -26,6 +26,12 @@
[License](https://github.com/jonesdevelopment/sonar/?tab=readme-ov-file#license)
</div>
> ### 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!
## Design and Goal
* Effective, lightweight, and easy-to-use
* No unnecessary features and clean code
@@ -53,6 +59,10 @@ Massive thanks to the sponsors of Sonar who help keep this project running:
<a href="https://github.com/Hydoxl"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/107579333?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
### Past Sponsors
<a href="https://github.com/ItzErpandX"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/84748484?v=4?s=400?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
## Building
If you want to build your own version of Sonar, please take a look at the [Sonar building documentation](https://docs.jonesdev.xyz/development/building).
<br>
+4 -3
View File
@@ -29,10 +29,11 @@ jobs:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build with Gradle
uses: gradle/gradle-build-action@v3
with:
arguments: build-sonar
run: ./gradlew build-sonar
- name: Upload Bukkit Artifact
uses: actions/upload-artifact@v4
@@ -30,6 +30,7 @@ import xyz.jonesdev.sonar.api.command.SonarCommand;
import xyz.jonesdev.sonar.api.database.ormlite.H2DatabaseTypeAdapter;
import xyz.jonesdev.sonar.api.database.ormlite.MariaDbDatabaseTypeAdapter;
import xyz.jonesdev.sonar.api.database.ormlite.MysqlDatabaseTypeAdapter;
import xyz.jonesdev.sonar.api.database.ormlite.PostgresDatabaseTypeAdapter;
import xyz.jonesdev.sonar.api.webhook.DiscordWebhook;
import java.io.File;
@@ -139,7 +140,7 @@ public final class SonarConfiguration {
// General settings
logPlayerAddresses = generalConfig.getBoolean("general.log-player-addresses");
maxOnlinePerIp = clamp(generalConfig.getInt("general.max-online-per-ip"), 0, 99);
maxOnlinePerIp = clamp(generalConfig.getInt("general.max-online-per-ip"), -1, 99);
// Attack tracker
minPlayersForAttack = clamp(generalConfig.getInt("attack-tracker.min-players-for-attack"), 2, 1024);
@@ -177,7 +178,7 @@ public final class SonarConfiguration {
verification.map.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.map-captcha.timing"));
verification.map.precomputeAmount = clamp(generalConfig.getInt("verification.checks.map-captcha.precompute"), 10, 5000);
verification.map.maxDuration = clamp(generalConfig.getInt("verification.checks.map-captcha.max-duration"), 5000, 360000);
verification.map.maxTries = generalConfig.getInt("verification.checks.map-captcha.max-tries");
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;
@@ -198,7 +199,6 @@ public final class SonarConfiguration {
verification.timeOfDay = clamp(generalConfig.getInt("verification.time-of-day"), 0, 24000);
verification.gamemode = Verification.Gamemode.valueOf(generalConfig.getString("verification.gamemode"));
verification.validNameRegex = Pattern.compile(generalConfig.getString("verification.checks.valid-name-regex"));
verification.validLocaleRegex = Pattern.compile(generalConfig.getString("verification.checks.valid-locale-regex"));
verification.checkGeyser = generalConfig.getBoolean("verification.check-geyser-players");
verification.logConnections = generalConfig.getBoolean("verification.log-connections");
@@ -206,6 +206,7 @@ public final class SonarConfiguration {
verification.debugXYZPositions = generalConfig.getBoolean("verification.debug-xyz-positions");
verification.readTimeout = clamp(generalConfig.getInt("verification.read-timeout"), 1000, 30000);
verification.writeTimeout = clamp(generalConfig.getInt("verification.write-timeout"), 1000, 30000);
verification.maxPacketCount = clamp(generalConfig.getInt("verification.max-packets"), 200, 9999);
verification.reconnectDelay = clamp(generalConfig.getInt("verification.rejoin-delay"), 0, 100000);
verification.rememberTime = clamp(generalConfig.getInt("verification.remember-time"), 0, 86400000);
verification.blacklistTime = clamp(generalConfig.getInt("verification.blacklist-time"), 0, 86400000);
@@ -418,10 +419,10 @@ public final class SonarConfiguration {
private boolean logDuringAttack;
private boolean debugXYZPositions;
private Pattern validNameRegex;
private Pattern validLocaleRegex;
private int readTimeout;
private int writeTimeout;
private int maxPacketCount;
private int reconnectDelay;
private int rememberTime;
private int blacklistTime;
@@ -447,14 +448,14 @@ public final class SonarConfiguration {
@Getter
@RequiredArgsConstructor
public enum Type {
MYSQL("MySQL", "jdbc:mysql://%s:%d/%s", new MysqlDatabaseTypeAdapter(),
MYSQL("MySQL", "jdbc:mysql://%s:%d/%s%s", new MysqlDatabaseTypeAdapter(),
Library.builder()
.groupId("com{}mysql")
.artifactId("mysql-connector-j")
.version("9.0.0")
.relocate("com{}mysql", "xyz{}jonesdev{}sonar{}libs{}mysql")
.build()),
MARIADB("MariaDB", "jdbc:mariadb://%s:%d/%s", new MariaDbDatabaseTypeAdapter(),
MARIADB("MariaDB", "jdbc:mariadb://%s:%d/%s%s", new MariaDbDatabaseTypeAdapter(),
Library.builder()
.groupId("org{}mariadb{}jdbc")
.artifactId("mariadb-java-client")
@@ -468,6 +469,13 @@ public final class SonarConfiguration {
.version("2.2.220")
.relocate("org{}h2", "xyz{}jonesdev{}sonar{}libs{}h2")
.build()),
POSTGRESQL("PostgreSQL", "jdbc:postgresql://%s:%d/%s%s", new PostgresDatabaseTypeAdapter(),
Library.builder()
.groupId("org{}postgresql")
.artifactId("postgresql")
.version("42.7.8")
.relocate("org{}postgresql", "xyz{}jonesdev{}sonar{}libs{}postgresql")
.build()),
NONE("None", null, null, null);
private final String displayName;
@@ -54,6 +54,8 @@ public final class VerifiedPlayerController {
@Getter
private final @NotNull SonarConfiguration.Database.Type cachedDatabaseType;
private final ExecutorService updateService = Executors.newSingleThreadExecutor();
@Getter
private int maximumAge;
public VerifiedPlayerController(final @NotNull LibraryManager libraryManager) {
final SonarConfiguration.Database database = Sonar.get0().getConfig().getDatabase();
@@ -87,7 +89,8 @@ public final class VerifiedPlayerController {
jdbcURL = String.format(cachedDatabaseType.getConnectionString(),
Sonar.get0().getConfig().getGeneralConfig().getString("database.host"),
Sonar.get0().getConfig().getGeneralConfig().getInt("database.port"),
Sonar.get0().getConfig().getGeneralConfig().getString("database.name"));
Sonar.get0().getConfig().getGeneralConfig().getString("database.name"),
"?autoReconnect=true");
}
connectionSource = new JdbcConnectionSource(jdbcURL,
@@ -107,6 +110,7 @@ public final class VerifiedPlayerController {
dao = DaoManager.createDao(connectionSource, VerifiedPlayer.class);
queryBuilder = dao.queryBuilder();
maximumAge = database.getMaximumAge();
// Make sure to run the clean task and the caching task in the same thread
// https://github.com/jonesdevelopment/sonar/issues/150
@@ -114,7 +118,7 @@ public final class VerifiedPlayerController {
if (connectionSource != null) {
try {
// Make sure to clear all outdated entries first
clearOld(database.getMaximumAge());
clearOld(maximumAge, false);
// Add all entries from the database to the cache
dao.queryForAll().forEach(verifiedPlayer -> cache.add(verifiedPlayer.getFingerprint()));
} catch (SQLException exception) {
@@ -148,7 +152,8 @@ public final class VerifiedPlayerController {
/**
* Clear all old entries using the given timestamp
*/
private void clearOld(final @Range(from = 1, to = 365) int maximumAge) throws SQLException {
public void clearOld(final @Range(from = 1, to = 365) int maximumAge,
final boolean removeExisting) throws SQLException {
final long timestamp = Instant.now().minus(maximumAge, ChronoUnit.DAYS).getEpochSecond() * 1000L;
final List<VerifiedPlayer> oldEntries = queryBuilder.where()
@@ -158,6 +163,9 @@ public final class VerifiedPlayerController {
if (oldEntries != null && !oldEntries.isEmpty()) {
for (final VerifiedPlayer player : oldEntries) {
dao.delete(player);
if (removeExisting) {
cache.remove(player.getFingerprint());
}
}
Sonar.get0().getLogger().info("Removed {} database entries older than {} days.",
oldEntries.size(), maximumAge);
@@ -0,0 +1,14 @@
package xyz.jonesdev.sonar.api.database.ormlite;
import com.j256.ormlite.jdbc.db.PostgresDatabaseType;
import org.jetbrains.annotations.NotNull;
public final class PostgresDatabaseTypeAdapter extends PostgresDatabaseType {
// We need to override the default driver class name
// to use the custom relocated Postgres driver
@Override
protected String @NotNull [] getDriverClassNames() {
return new String[]{"xyz.jonesdev.sonar.libs.postgresql.Driver"};
}
}
@@ -70,7 +70,11 @@ public enum ProtocolVersion {
MINECRAFT_1_20_5(766, "1.20.5"),
MINECRAFT_1_21(767, "1.21"),
MINECRAFT_1_21_2(768, "1.21.2"),
MINECRAFT_1_21_4(769, "1.21.4");
MINECRAFT_1_21_4(769, "1.21.4"),
MINECRAFT_1_21_5(770, "1.21.5"),
MINECRAFT_1_21_6(771, "1.21.6"),
MINECRAFT_1_21_7(772, "1.21.7"),
MINECRAFT_1_21_9(773, "1.21.9");
private final int protocol;
private final String name;
@@ -33,8 +33,8 @@ import static xyz.jonesdev.sonar.api.profiler.SimpleProcessProfiler.*;
import static xyz.jonesdev.sonar.api.timer.SystemTimer.DATE_FORMATTER;
@Getter
public final class ActionBarNotificationHandler extends NotificationHandler {
private int animationIndex;
public class ActionBarNotificationHandler extends NotificationHandler {
protected int animationIndex;
@Override
public void handleNotification() {
@@ -54,6 +54,8 @@ public final class ActionBarNotificationHandler extends NotificationHandler {
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
Placeholder.unparsed("attack-duration", attackDuration),
Placeholder.unparsed("animation", nextAnimation()),
Placeholder.unparsed("process-cpu", Sonar.DECIMAL_FORMAT.format(getProcessCPUUsage())),
Placeholder.unparsed("system-cpu", Sonar.DECIMAL_FORMAT.format(getSystemCPUUsage())),
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getQueue().getPlayers().size())),
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getConnected().size())),
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getBlacklist().estimatedSize())),
+1
View File
@@ -62,6 +62,7 @@ allprojects {
relocate("org.mariadb", "xyz.jonesdev.sonar.libs.mariadb")
relocate("org.h2", "xyz.jonesdev.sonar.libs.h2")
relocate("com.jhlabs", "xyz.jonesdev.sonar.libs.jhlabs")
relocate("org.postgresql", "xyz.jonesdev.sonar.libs.postgresql")
// Exclude unnecessary metadata information
exclude("META-INF/*/**")
@@ -74,7 +74,11 @@ public enum BukkitServerVersion {
MINECRAFT_1_21_1,
MINECRAFT_1_21_2,
MINECRAFT_1_21_3,
MINECRAFT_1_21_4;
MINECRAFT_1_21_4,
MINECRAFT_1_21_5,
MINECRAFT_1_21_6,
MINECRAFT_1_21_7,
MINECRAFT_1_21_8;
static final BukkitServerVersion[] REVERSED_VALUES;
@@ -45,7 +45,7 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
FallbackBukkitInboundHandler() {
updateRegistry(FallbackPacketRegistry.HANDSHAKE, DEFAULT_PROTOCOL_VERSION);
channelRemovalListener = (pipeline, name, handler) -> {
super.channelRemovalListener = (pipeline, name, handler) -> {
final ChannelInactiveListener inactiveListener = pipeline.get(ChannelInactiveListener.class);
if (inactiveListener != null) {
@@ -122,6 +122,7 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
updateRegistry(FallbackPacketRegistry.LOGIN, Objects.requireNonNull(protocolVersion));
break;
default:
byteBuf.release();
throw ProtocolUtil.DEBUG ? new DecoderException("Bad handshake intent " + handshake.getIntent())
: QuietDecoderException.INSTANCE;
}
@@ -136,7 +137,7 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
ctx.fireChannelRead(byteBuf.retain());
// TODO: recode this?
final ChannelHandler inboundHandler = ctx.pipeline().remove(FALLBACK_INBOUND_HANDLER);
if (inboundHandler != null) {
if (inboundHandler != null && channelRemovalListener != null) {
channelRemovalListener.accept(ctx.pipeline(), FALLBACK_INBOUND_HANDLER, inboundHandler);
}
}, loginStart.getUsername(), socketAddress);
@@ -146,6 +147,8 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
byteBuf.readerIndex(originalReaderIndex);
ctx.fireChannelRead(byteBuf);
} else {
ctx.fireChannelRead(msg);
}
}
}
@@ -86,6 +86,10 @@ public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
@Override
public void enable() {
// Add warning because of questionable design choices that haunt me in my dreams.
logger.warn("The use of BungeeCord is supported but not condoned.");
logger.warn("Consider upgrading to Velocity (https://velocitypowered.com)");
// Initialize bStats.org metrics
metrics = new Metrics(getPlugin(), getPlatform().getMetricsId());
@@ -20,7 +20,11 @@ package xyz.jonesdev.sonar.bungee.fallback;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import lombok.experimental.UtilityClass;
import lombok.val;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
import org.jetbrains.annotations.NotNull;
import sun.misc.Unsafe;
import xyz.jonesdev.sonar.api.Sonar;
import xyz.jonesdev.sonar.common.fallback.netty.FallbackInjectedChannelInitializer;
@@ -34,26 +38,59 @@ import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_PACKET_
public class FallbackBungeeInjector {
public void inject() {
try {
final Field childField = PipelineUtils.class.getField("SERVER_CHILD");
final Field childField;
try {
// This field only exists on BungeeCord build 1908 and below.
// See https://github.com/SpigotMC/BungeeCord/pull/3776 for more info.
//noinspection all
childField = PipelineUtils.class.getField("SERVER_CHILD");
} catch (NoSuchFieldException exception) {
injectOnModernBungeeCord();
return;
}
childField.setAccessible(true);
// Make sure to store the original channel initializer
final ChannelInitializer<Channel> originalInitializer = PipelineUtils.SERVER_CHILD;
final ChannelInitializer<Channel> injectedInitializer = new FallbackInjectedChannelInitializer(
originalInitializer, pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
new FallbackBungeeInboundHandler()));
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
final Unsafe unsafe = (Unsafe) unsafeField.get(null);
final Object base = unsafe.staticFieldBase(childField);
final long offset = unsafe.staticFieldOffset(childField);
// Replace the original channel initializer with our new injected initializer
unsafe.putObject(base, offset, injectedInitializer);
injectOnOldBungeeCord(childField);
} catch (Exception exception) {
Sonar.get0().getLogger().error("An error occurred while injecting {}", exception);
}
}
private static void injectOnOldBungeeCord(final @NotNull Field childField) throws Exception {
// Make sure to store the original channel initializer
//noinspection unchecked
val originalInitializer = (ChannelInitializer<Channel>) childField.get(null);
final ChannelInitializer<Channel> injectedInitializer = new FallbackInjectedChannelInitializer(
originalInitializer, pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
new FallbackBungeeInboundHandler()));
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
final Unsafe unsafe = (Unsafe) unsafeField.get(null);
final Object base = unsafe.staticFieldBase(childField);
final long offset = unsafe.staticFieldOffset(childField);
// Replace the original channel initializer with our new injected initializer
unsafe.putObject(base, offset, injectedInitializer);
}
// See https://github.com/SpigotMC/BungeeCord/pull/3787
private static void injectOnModernBungeeCord() {
// The order is important...
final BungeeChannelInitializer original = ProxyServer.getInstance().unsafe().getFrontendChannelInitializer();
final BungeeChannelInitializer newInitializer = BungeeChannelInitializer.create(
channel -> {
// https://github.com/SpigotMC/BungeeCord/pull/3787#issuecomment-2661059876
if (!original.getChannelAcceptor().accept(channel)) {
return false;
}
FallbackInjectedChannelInitializer.inject(channel,
pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
new FallbackBungeeInboundHandler()));
return true;
});
ProxyServer.getInstance().unsafe().setFrontendChannelInitializer(newInitializer);
}
}
+2 -2
View File
@@ -2,6 +2,6 @@ dependencies {
compileOnly(project(":api"))
compileOnly(rootProject.libs.imagefilters)
testCompileOnly(project(":api"))
testCompileOnly(rootProject.libs.imagefilters)
testImplementation(project(":api"))
testImplementation(rootProject.libs.imagefilters)
}
@@ -109,11 +109,11 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
// Randomize the colors for the gradient effect
for (int i = 0; i < COLORS.length; i++) {
final float random = 0.9f + RANDOM.nextFloat() * 0.1f;
COLORS[i] = Color.getHSBColor(RANDOM.nextFloat(), random, random);
COLORS[i] = Color.getHSBColor(RANDOM.nextFloat(), random * 0.8f, random);
}
// Apply the random gradient effect
graphics.setPaint(new LinearGradientPaint(0, 0, width, height,
graphics.setPaint(new RadialGradientPaint(0, 0, width,
COLOR_FRACTIONS, COLORS, MultipleGradientPaint.CycleMethod.REFLECT));
}
@@ -43,7 +43,7 @@ class StandardTTFFontProvider {
// Set the font size and style
return customFont.deriveFont(Font.PLAIN, STANDARD_FONT_SIZE);
} catch (Exception exception) {
throw new IllegalStateException(exception);
throw new IllegalStateException("Error loading font. Does your environment support fonts?", exception);
}
}
}
@@ -0,0 +1,212 @@
/*
* Copyright (C) 2025 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.captcha.legacy;
import com.jhlabs.image.*;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator;
import xyz.jonesdev.sonar.captcha.filters.NoiseOverlayFilter;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.Random;
@Getter
@RequiredArgsConstructor
public final class LegacyCaptchaGenerator implements CaptchaGenerator {
private static final ScratchFilter SCRATCHES = new ScratchFilter(4);
private static final NoiseOverlayFilter NOISE = new NoiseOverlayFilter(1, 7);
private static final SmearFilter SMEAR = new SmearFilter();
private static final SaturationFilter SATURATION = new SaturationFilter();
private static final RippleFilter RIPPLE = new RippleFilter();
private static final Random RANDOM = new Random();
static {
RIPPLE.setXAmplitude(0);
float yAmplitude = 10 - RANDOM.nextInt(20);
if (Math.abs(yAmplitude) < 5) {
yAmplitude = yAmplitude >= 0 ? 5 : -5;
}
RIPPLE.setYAmplitude(yAmplitude);
SATURATION.setAmount(0.45f + RANDOM.nextFloat() * 0.15f);
SMEAR.setShape(SmearFilter.CIRCLES);
SMEAR.setMix(0.15f);
SMEAR.setDensity(0.1f);
SMEAR.setDistance(5);
}
private final int width = 128, height = 128;
private final @Nullable File background;
private @Nullable BufferedImage backgroundImage;
private GradientPaint gradient;
public BufferedImage createCachedBackgroundImage() {
// Create a new image buffer with a 3-byte color spectrum
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
if (background == null) {
if (backgroundImage != null) {
return backgroundImage;
}
// Don't use any special background image
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Fill the entire background image with a noise texture
image = new CausticsFilter().filter(image, null);
// Adjust the saturation of the randomly generated background noise
final SaturationFilter saturationFilter = new SaturationFilter();
saturationFilter.setAmount(0.4f + RANDOM.nextFloat() * 0.2f);
image = saturationFilter.filter(image, null);
// Un-sharpen the background a bit
image = new UnsharpFilter().filter(image, null);
return image;
}
// Try to load the image from a file if it doesn't exist yet
if (backgroundImage == null) {
try {
backgroundImage = ImageIO.read(background);
} catch (IOException exception) {
throw new IllegalStateException("Could not read background image", exception);
}
}
image.createGraphics().drawImage(backgroundImage, 0, 0, Color.WHITE, null);
return image;
}
private @NotNull BufferedImage mergeImages(final @NotNull BufferedImage background,
final @NotNull BufferedImage foreground) {
// Get the background image and create a new foreground image
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
// Create a new image with transparency for the merged result
final Graphics2D graphics = image.createGraphics();
// Draw the foreground image on top of the background at specified coordinates
graphics.drawImage(background, 0, 0, null);
// Set AlphaComposite to handle transparency for the foreground image
graphics.setComposite(AlphaComposite.SrcOver);
// Draw the foreground image on top of the background at specified coordinates
graphics.drawImage(foreground, 0, 0, null);
graphics.dispose();
return image;
}
@Override
public @NotNull BufferedImage createImage(final char @NotNull [] answer) {
final Color color0 = Color.getHSBColor(RANDOM.nextFloat(), 1, 1);
final Color color1 = Color.getHSBColor(RANDOM.nextFloat(), 1, 0.5f);
gradient = new GradientPaint(0, 0, color0, width, height, color1);
// Get the background image and create a new foreground image
BufferedImage foreground = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D graphics = foreground.createGraphics();
final FontRenderContext ctx = graphics.getFontRenderContext();
// Change some rendering hints for anti aliasing
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Draw characters
drawCharacters(graphics, ctx, answer);
// Make sure to dispose the graphics after using it
graphics.dispose();
// Apply any given filter to the foreground
new BumpFilter().filter(foreground, foreground);
SMEAR.filter(foreground, foreground);
RIPPLE.filter(foreground, foreground);
SCRATCHES.filter(foreground, foreground);
final BufferedImage merged = mergeImages(createCachedBackgroundImage(), foreground);
NOISE.transform(merged);
return merged;
}
private void drawCharacters(final @NotNull Graphics2D graphics,
final @NotNull FontRenderContext ctx,
final char[] answer) {
// Create font render context
final int fontSize = 62 - answer.length * 2;
final Font font = new Font(Font.MONOSPACED, Font.PLAIN, fontSize);
// Calculate string width
final double stringWidth = font.getStringBounds(answer, 0, answer.length, ctx).getWidth();
// Calculate character positions
int beginX = (int) ((width - stringWidth) / 2D + stringWidth / (answer.length * 2.5D));
final int beginY = (int) ((height + fontSize / 2D) / 2D);
double rotation = 0;
if (gradient != null) {
graphics.setPaint(gradient);
}
// Draw each character one by one
for (final char character : answer) {
// Create a glyph vector for the character
final GlyphVector glyphVector = font.createGlyphVector(ctx, String.valueOf(character));
final int visualBoundsWidth = (int) glyphVector.getVisualBounds().getWidth();
if (gradient == null) {
Objects.requireNonNull(backgroundImage);
// Use the inverse color by checking the background image
// Then, create a gradient for the text by using the colors
final int x0 = Math.min(Math.max(beginX + 5 /* small threshold */, 0), width);
final int x1 = Math.min(Math.max(beginX + (int) visualBoundsWidth, 0), width);
final int y = beginY + fontSize / 2;
final Color color0 = new Color(~backgroundImage.getRGB(x0, y));
final Color color1 = new Color(~backgroundImage.getRGB(x1, y));
final GradientPaint gradient = new GradientPaint(0, 0, color0, width, height, color1);
graphics.setPaint(gradient);
}
// Apply a transformation to the glyph vector using AffineTransform
final AffineTransform transformation = AffineTransform.getTranslateInstance(beginX, beginY);
// Add a bit of randomization to the rotation
rotation += Math.toRadians(6 - RANDOM.nextInt(12));
transformation.rotate(rotation);
transformation.scale(1, 1.25);
// Draw the glyph to the buffered image
final Shape transformedShape = transformation.createTransformedShape(glyphVector.getOutline());
graphics.fill(transformedShape);
// Add text outline/shadow to confuse an AI's edge detection
addTextOutline(graphics, transformedShape);
// Update next X position
beginX += visualBoundsWidth + 2;
}
}
private static void addTextOutline(final @NotNull Graphics2D graphics,
final @NotNull Shape transformedShape) {
// Create a stroked copy of the text and slightly offset/distort it
final Shape strokedShape = new BasicStroke().createStrokedShape(transformedShape);
final double tx = 0.5 + RANDOM.nextDouble();
final double ty = 0.5 + RANDOM.nextDouble();
// Draw the stroked shape
final AffineTransform transform = AffineTransform.getTranslateInstance(tx, ty);
graphics.fill(transform.createTransformedShape(strokedShape));
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2025 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.captcha.legacy;
import com.jhlabs.image.TransformFilter;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public final class RippleFilter extends TransformFilter {
private float xAmplitude, yAmplitude;
@Override
protected void transformInverse(final int x, final int y, final float @NotNull [] out) {
final float nx = (float) y / 13f;
final float ny = (float) x / 13f;
final float fx = (float) Math.sin(nx);
final float fy = (float) Math.sin(ny);
out[0] = (float) x + xAmplitude * fx;
out[1] = (float) y + yAmplitude * fy;
}
}
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2025 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.captcha.legacy;
import com.jhlabs.image.AbstractBufferedImageOp;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
@RequiredArgsConstructor
public final class ScratchFilter extends AbstractBufferedImageOp {
private static final Random RANDOM = new Random();
private final int amount;
@Override
public @NotNull BufferedImage filter(final @NotNull BufferedImage src, final BufferedImage dst) {
final Graphics2D graphics = src.createGraphics();
// Apply some gradient effect on them
final Color color0 = Color.getHSBColor(RANDOM.nextFloat(), RANDOM.nextFloat(), 1);
final Color color1 = new Color(~color0.getRGB());
final GradientPaint gradient = new GradientPaint(0, 0, color0, src.getWidth(), src.getHeight(), color1);
graphics.setPaint(gradient);
final float halfWidth = src.getWidth() * 0.5f;
for (int i = 0; i < amount; ++i) {
final float randomX = src.getWidth() * RANDOM.nextFloat();
final float randomY = src.getHeight() * RANDOM.nextFloat();
final float amplitude = 6.2831855f * (RANDOM.nextFloat() - 0.5f);
final float sin = (float) Math.sin(amplitude) * halfWidth;
final float cos = (float) Math.cos(amplitude) * halfWidth;
final float x1 = randomX - cos;
final float y1 = randomY - sin;
final float x2 = randomX + cos;
final float y2 = randomY + sin;
graphics.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
}
graphics.dispose();
return src;
}
}
@@ -0,0 +1,12 @@
Kingthings EULA - (End User License Agreement).
All the fonts currently published on my website (www.kingthingsfonts.co.uk) are free for you to use for any purpose you wish. Please do not change my original font files (.TTF).
There are some paid-for versions of my fonts (with much enhanced character sets) available from to buy from www.cheapprofonts.com, these contain their own EULA and are not included or implied in this notice.
Please enjoy all your creative work - and if you come up with anything you like, I would appreciate a picture.
Regards
Kevin King
Exeter, England - February 2009
@@ -47,7 +47,7 @@ import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.*;
public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandlerAdapter {
protected @Nullable String username;
protected ProtocolVersion protocolVersion;
protected RemovalListener channelRemovalListener = RemovalListener.EMPTY;
protected @Nullable RemovalListener channelRemovalListener;
/**
* Validates and handles incoming handshake packets
@@ -168,30 +168,23 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
protected final void initialLogin(final @NotNull Channel channel,
final @NotNull InetAddress inetAddress,
final @NotNull Runnable loginPacket) throws Exception {
Sonar.get0().getFallback().getOnline().compute(inetAddress, (__, count) -> {
final int maxOnlinePerIp = Sonar.get0().getConfig().getMaxOnlinePerIp();
// Skip the maximum online per IP check if it's disabled in the configuration
if (count != null && maxOnlinePerIp > 0) {
// Check if the number of online players using the same IP address as
// the connecting player is greater than the configured amount
if (count >= maxOnlinePerIp) {
customDisconnect(channel, tooManyOnlinePerIP, protocolVersion);
return count + 1;
}
final int maxOnlinePerIp = Sonar.get0().getConfig().getMaxOnlinePerIp();
if (maxOnlinePerIp > 0) {
final int newCount = Sonar.get0().getFallback().getOnline().compute(inetAddress,
(__, count) -> count == null ? 1 : count + 1);
if (newCount > maxOnlinePerIp) {
customDisconnect(channel, tooManyOnlinePerIP, protocolVersion);
return;
}
// Let the server know about the login packet
loginPacket.run();
// Increment the number of accounts with the same IP
return count == null ? 1 : count + 1;
});
}
loginPacket.run();
}
/**
* Removes all pipelines and rewrites them using our custom handlers
*/
private static void rewriteProtocol(final @NotNull ChannelHandlerContext ctx,
final @NotNull RemovalListener removalListener) {
final @Nullable RemovalListener removalListener) {
for (final Map.Entry<String, ChannelHandler> entry : ctx.pipeline()) {
// Don't accidentally remove Sonar's handlers
if (entry.getKey().startsWith("sonar")
@@ -202,7 +195,9 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
continue;
}
ctx.pipeline().remove(entry.getValue());
removalListener.accept(ctx.pipeline(), entry.getKey(), entry.getValue());
if (removalListener != null) {
removalListener.accept(ctx.pipeline(), entry.getKey(), entry.getValue());
}
}
// Add our read/write timeout handler
ctx.pipeline().addFirst(FALLBACK_TIMEOUT, new FallbackTimeoutHandler(
@@ -256,7 +251,5 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
void accept(final @NotNull ChannelPipeline pipeline,
final @NotNull String name,
final @NotNull ChannelHandler handler);
RemovalListener EMPTY = (pipeline, name, handler) -> {};
}
}
@@ -96,6 +96,12 @@ public final class FallbackUserWrapper implements FallbackUser {
return;
}
// How? Is there some kind of de-sync or race condition?
if (channel.pipeline().context(FALLBACK_FRAME_ENCODER) != null) {
channel.close(); // Nope ¯\_(ツ)_/¯
return;
}
// Mark the player as connected by caching them in a map of verifying players
Sonar.get0().getFallback().getConnected().compute(inetAddress, (__, v) -> true);
@@ -53,6 +53,10 @@ public final class FallbackInjectedChannelInitializer extends ChannelInitializer
@Override
protected void initChannel(final Channel channel) throws Exception {
if (!channel.isActive()) {
return;
}
// Invoke the original method
try {
INIT_CHANNEL_METHOD.invokeExact(originalChannelInitializer, channel);
@@ -60,6 +64,10 @@ public final class FallbackInjectedChannelInitializer extends ChannelInitializer
throw new ReflectiveOperationException(throwable);
}
inject(channel, sonarPipelineInjector);
}
public static void inject(final @NotNull Channel channel, final Consumer<ChannelPipeline> sonarPipelineInjector) {
// Inject Sonar's channel handler into the pipeline;
// Also make sure the player is not a fake player to avoid compatibility issues
if (channel.isActive() && !FakeChannelUtil.isFakeChannel(channel)) {
@@ -66,7 +66,7 @@ public enum FallbackPacketRegistry {
clientbound.register(DisconnectPacket.class, DisconnectPacket::new,
map(0x01, MINECRAFT_1_20_2, true),
map(0x02, MINECRAFT_1_20_5, true));
clientbound.register(FinishConfigurationPacket.class, FinishConfigurationPacket::new,
clientbound.register(FinishConfigurationPacket.class, () -> FinishConfigurationPacket.INSTANCE,
map(0x02, MINECRAFT_1_20_2, true),
map(0x03, MINECRAFT_1_20_5, true));
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
@@ -81,7 +81,7 @@ public enum FallbackPacketRegistry {
serverbound.register(PluginMessagePacket.class, PluginMessagePacket::new,
map(0x01, MINECRAFT_1_20_2, false),
map(0x02, MINECRAFT_1_20_5, false));
serverbound.register(FinishConfigurationPacket.class, FinishConfigurationPacket::new,
serverbound.register(FinishConfigurationPacket.class, () -> FinishConfigurationPacket.INSTANCE,
map(0x02, MINECRAFT_1_20_2, false),
map(0x03, MINECRAFT_1_20_5, false));
serverbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
@@ -91,6 +91,7 @@ public enum FallbackPacketRegistry {
},
GAME {
{
// minecraft:login
clientbound.register(JoinGamePacket.class, JoinGamePacket::new,
map(0x01, MINECRAFT_1_7_2, true),
map(0x23, MINECRAFT_1_9, true),
@@ -106,7 +107,10 @@ public enum FallbackPacketRegistry {
map(0x28, MINECRAFT_1_19_4, true),
map(0x29, MINECRAFT_1_20_2, true),
map(0x2B, MINECRAFT_1_20_5, true),
map(0x2C, MINECRAFT_1_21_2, true));
map(0x2C, MINECRAFT_1_21_2, true),
map(0x2B, MINECRAFT_1_21_5, true),
map(0x30, MINECRAFT_1_21_9, true));
// minecraft:keep_alive
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
map(0x00, MINECRAFT_1_7_2, true),
map(0x1F, MINECRAFT_1_9, true),
@@ -122,7 +126,10 @@ public enum FallbackPacketRegistry {
map(0x23, MINECRAFT_1_19_4, true),
map(0x24, MINECRAFT_1_20_2, true),
map(0x26, MINECRAFT_1_20_5, true),
map(0x27, MINECRAFT_1_21_2, true));
map(0x27, MINECRAFT_1_21_2, true),
map(0x26, MINECRAFT_1_21_5, true),
map(0x2B, MINECRAFT_1_21_9, true));
// minecraft:disconnect
clientbound.register(DisconnectPacket.class, DisconnectPacket::new,
map(0x40, MINECRAFT_1_7_2, true),
map(0x1A, MINECRAFT_1_9, true),
@@ -137,7 +144,10 @@ public enum FallbackPacketRegistry {
map(0x17, MINECRAFT_1_19_3, true),
map(0x1A, MINECRAFT_1_19_4, true),
map(0x1B, MINECRAFT_1_20_2, true),
map(0x1D, MINECRAFT_1_20_5, true));
map(0x1D, MINECRAFT_1_20_5, true),
map(0x1C, MINECRAFT_1_21_5, true),
map(0x20, MINECRAFT_1_21_9, true));
// minecraft:player_position
clientbound.register(SetPlayerPositionRotationPacket.class, SetPlayerPositionRotationPacket::new,
map(0x08, MINECRAFT_1_7_2, true),
map(0x2E, MINECRAFT_1_9, true),
@@ -154,7 +164,10 @@ public enum FallbackPacketRegistry {
map(0x3C, MINECRAFT_1_19_4, true),
map(0x3E, MINECRAFT_1_20_2, true),
map(0x40, MINECRAFT_1_20_5, true),
map(0x42, MINECRAFT_1_21_2, true));
map(0x42, MINECRAFT_1_21_2, true),
map(0x41, MINECRAFT_1_21_5, true),
map(0x46, MINECRAFT_1_21_9, true));
// minecraft:player_abilities
clientbound.register(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new,
map(0x39, MINECRAFT_1_7_2, true),
map(0x2B, MINECRAFT_1_9, true),
@@ -171,7 +184,10 @@ public enum FallbackPacketRegistry {
map(0x34, MINECRAFT_1_19_4, true),
map(0x36, MINECRAFT_1_20_2, true),
map(0x38, MINECRAFT_1_20_5, true),
map(0x3A, MINECRAFT_1_21_2, true));
map(0x3A, MINECRAFT_1_21_2, true),
map(0x39, MINECRAFT_1_21_5, true),
map(0x3E, MINECRAFT_1_21_9, true));
// minecraft:level_chunk_with_light
clientbound.register(ChunkDataPacket.class, ChunkDataPacket::new,
map(0x21, MINECRAFT_1_7_2, true),
map(0x20, MINECRAFT_1_9, true),
@@ -187,7 +203,10 @@ public enum FallbackPacketRegistry {
map(0x24, MINECRAFT_1_19_4, true),
map(0x25, MINECRAFT_1_20_2, true),
map(0x27, MINECRAFT_1_20_5, true),
map(0x28, MINECRAFT_1_21_2, true));
map(0x28, MINECRAFT_1_21_2, true),
map(0x27, MINECRAFT_1_21_5, true),
map(0x2C, MINECRAFT_1_21_9, true));
// minecraft:remove_entities
clientbound.register(RemoveEntitiesPacket.class, RemoveEntitiesPacket::new,
map(0x13, MINECRAFT_1_7_2, true),
map(0x30, MINECRAFT_1_9, true),
@@ -206,7 +225,10 @@ public enum FallbackPacketRegistry {
map(0x3E, MINECRAFT_1_19_4, true),
map(0x40, MINECRAFT_1_20_2, true),
map(0x42, MINECRAFT_1_20_5, true),
map(0x47, MINECRAFT_1_21_2, true));
map(0x47, MINECRAFT_1_21_2, true),
map(0x46, MINECRAFT_1_21_5, true),
map(0x4B, MINECRAFT_1_21_9, true));
// minecraft:set_passengers
clientbound.register(SetPassengersPacket.class, SetPassengersPacket::new,
map(0x1B, MINECRAFT_1_7_2, true),
map(0x40, MINECRAFT_1_9, true),
@@ -222,26 +244,15 @@ public enum FallbackPacketRegistry {
map(0x5B, MINECRAFT_1_20_2, true),
map(0x5D, MINECRAFT_1_20_3, true),
map(0x5F, MINECRAFT_1_20_5, true),
map(0x65, MINECRAFT_1_21_2, true));
clientbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
map(0x29, MINECRAFT_1_9, true),
map(0x2B, MINECRAFT_1_13, true),
map(0x2C, MINECRAFT_1_14, true),
map(0x2D, MINECRAFT_1_15, true),
map(0x2C, MINECRAFT_1_16, true),
map(0x2B, MINECRAFT_1_16_2, true),
map(0x2C, MINECRAFT_1_17, true),
map(0x29, MINECRAFT_1_19, true),
map(0x2B, MINECRAFT_1_19_1, true),
map(0x2A, MINECRAFT_1_19_3, true),
map(0x2E, MINECRAFT_1_19_4, true),
map(0x2F, MINECRAFT_1_20_2, true),
map(0x31, MINECRAFT_1_20_5, true),
map(0x33, MINECRAFT_1_21_2, true));
map(0x65, MINECRAFT_1_21_2, true),
map(0x64, MINECRAFT_1_21_5, true),
map(0x69, MINECRAFT_1_21_9, true));
// minecraft:add_entity
clientbound.register(SpawnEntityPacket.class, SpawnEntityPacket::new,
map(0x0E, MINECRAFT_1_7_2, true),
map(0x00, MINECRAFT_1_9, true),
map(0x01, MINECRAFT_1_19_4, true));
// minecraft:section_blocks_update
clientbound.register(UpdateSectionBlocksPacket.class, UpdateSectionBlocksPacket::new,
map(0x22, MINECRAFT_1_7_2, true),
map(0x10, MINECRAFT_1_9, true),
@@ -257,7 +268,10 @@ public enum FallbackPacketRegistry {
map(0x45, MINECRAFT_1_20_2, true),
map(0x47, MINECRAFT_1_20_3, true),
map(0x49, MINECRAFT_1_20_5, true),
map(0x4E, MINECRAFT_1_21_2, true));
map(0x4E, MINECRAFT_1_21_2, true),
map(0x4D, MINECRAFT_1_21_5, true),
map(0x52, MINECRAFT_1_21_9, true));
// minecraft:ping
clientbound.register(TransactionPacket.class, TransactionPacket::new,
map(0x32, MINECRAFT_1_7_2, true),
map(0x11, MINECRAFT_1_9, true),
@@ -272,7 +286,10 @@ public enum FallbackPacketRegistry {
map(0x32, MINECRAFT_1_19_4, true),
map(0x33, MINECRAFT_1_20_2, true),
map(0x35, MINECRAFT_1_20_5, true),
map(0x37, MINECRAFT_1_21_2, true));
map(0x37, MINECRAFT_1_21_2, true),
map(0x36, MINECRAFT_1_21_5, true),
map(0x3B, MINECRAFT_1_21_9, true));
// minecraft:set_default_spawn_position
clientbound.register(SetDefaultSpawnPositionPacket.class, SetDefaultSpawnPositionPacket::new,
map(0x05, MINECRAFT_1_7_2, true),
map(0x43, MINECRAFT_1_9, true),
@@ -290,7 +307,10 @@ public enum FallbackPacketRegistry {
map(0x52, MINECRAFT_1_20_2, true),
map(0x54, MINECRAFT_1_20_3, true),
map(0x56, MINECRAFT_1_20_5, true),
map(0x5B, MINECRAFT_1_21_2, true));
map(0x5B, MINECRAFT_1_21_2, true),
map(0x5A, MINECRAFT_1_21_5, true),
map(0x5F, MINECRAFT_1_21_9, true));
// minecraft:map_item_data
clientbound.register(MapDataPacket.class, MapDataPacket::new,
map(0x34, MINECRAFT_1_7_2, true),
map(0x24, MINECRAFT_1_9, true),
@@ -305,7 +325,10 @@ public enum FallbackPacketRegistry {
map(0x29, MINECRAFT_1_19_4, true),
map(0x2A, MINECRAFT_1_20_2, true),
map(0x2C, MINECRAFT_1_20_5, true),
map(0x2D, MINECRAFT_1_21_2, true));
map(0x2D, MINECRAFT_1_21_2, true),
map(0x2C, MINECRAFT_1_21_5, true),
map(0x31, MINECRAFT_1_21_9, true));
// minecraft:container_set_slot
clientbound.register(SetContainerSlotPacket.class, SetContainerSlotPacket::new,
map(0x2F, MINECRAFT_1_7_2, true),
map(0x16, MINECRAFT_1_9, true),
@@ -318,7 +341,9 @@ public enum FallbackPacketRegistry {
map(0x13, MINECRAFT_1_19, true),
map(0x12, MINECRAFT_1_19_3, true),
map(0x14, MINECRAFT_1_19_4, true),
map(0x15, MINECRAFT_1_20_2, true));
map(0x15, MINECRAFT_1_20_2, true),
map(0x14, MINECRAFT_1_21_5, true));
// minecraft:set_experience
clientbound.register(SetExperiencePacket.class, SetExperiencePacket::new,
map(0x1F, MINECRAFT_1_7_2, true),
map(0x3D, MINECRAFT_1_9, true),
@@ -334,7 +359,10 @@ public enum FallbackPacketRegistry {
map(0x58, MINECRAFT_1_20_2, true),
map(0x5A, MINECRAFT_1_20_3, true),
map(0x5C, MINECRAFT_1_20_5, true),
map(0x61, MINECRAFT_1_21_2, true));
map(0x61, MINECRAFT_1_21_2, true),
map(0x60, MINECRAFT_1_21_5, true),
map(0x65, MINECRAFT_1_21_9, true));
// minecraft:system_chat
clientbound.register(SystemChatPacket.class, SystemChatPacket::new,
map(0x02, MINECRAFT_1_7_2, true),
map(0x0F, MINECRAFT_1_9, true),
@@ -349,14 +377,22 @@ public enum FallbackPacketRegistry {
map(0x67, MINECRAFT_1_20_2, true),
map(0x69, MINECRAFT_1_20_3, true),
map(0x6C, MINECRAFT_1_20_5, true),
map(0x73, MINECRAFT_1_21_2, true));
map(0x73, MINECRAFT_1_21_2, true),
map(0x72, MINECRAFT_1_21_5, true),
map(0x77, MINECRAFT_1_21_9, 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(0x23, MINECRAFT_1_21_2, true),
map(0x22, MINECRAFT_1_21_5, true),
map(0x26, MINECRAFT_1_21_9, true));
// minecraft:transfer
clientbound.register(TransferPacket.class, TransferPacket::new,
map(0x73, MINECRAFT_1_20_5, true),
map(0x7A, MINECRAFT_1_21_2, true));
map(0x7A, MINECRAFT_1_21_2, true),
map(0x7F, MINECRAFT_1_21_9, true));
// minecraft:set_held_slot
clientbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
map(0x09, MINECRAFT_1_7_2, true),
map(0x37, MINECRAFT_1_9, true),
@@ -374,7 +410,10 @@ public enum FallbackPacketRegistry {
map(0x4F, MINECRAFT_1_20_2, true),
map(0x51, MINECRAFT_1_20_3, true),
map(0x53, MINECRAFT_1_20_5, true),
map(0x63, MINECRAFT_1_21_2, true));
map(0x63, MINECRAFT_1_21_2, true),
map(0x62, MINECRAFT_1_21_5, true),
map(0x67, MINECRAFT_1_21_9, true));
// minecraft:animate
clientbound.register(EntityAnimationPacket.class, EntityAnimationPacket::new,
map(0x0B, MINECRAFT_1_7_2, true),
map(0x06, MINECRAFT_1_9, true),
@@ -382,7 +421,9 @@ public enum FallbackPacketRegistry {
map(0x06, MINECRAFT_1_17, true),
map(0x03, MINECRAFT_1_19, true),
map(0x04, MINECRAFT_1_19_4, true),
map(0x03, MINECRAFT_1_20_2, true));
map(0x03, MINECRAFT_1_20_2, true),
map(0x02, MINECRAFT_1_21_5, true));
// minecraft:set_time
clientbound.register(UpdateTimePacket.class, UpdateTimePacket::new,
map(0x03, MINECRAFT_1_7_2, true),
map(0x44, MINECRAFT_1_9, true),
@@ -400,10 +441,15 @@ public enum FallbackPacketRegistry {
map(0x60, MINECRAFT_1_20_2, true),
map(0x62, MINECRAFT_1_20_3, true),
map(0x64, MINECRAFT_1_20_5, true),
map(0x6B, MINECRAFT_1_21_2, true));
map(0x6B, MINECRAFT_1_21_2, true),
map(0x6A, MINECRAFT_1_21_5, true),
map(0x6F, MINECRAFT_1_21_9, true));
// minecraft:client_tick_end
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
map(0x0B, MINECRAFT_1_21_2, false));
map(0x0B, MINECRAFT_1_21_2, false),
map(0x0C, MINECRAFT_1_21_6, false));
// minecraft:set_carried_item
serverbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
map(0x09, MINECRAFT_1_7_2, false),
map(0x17, MINECRAFT_1_9, false),
@@ -418,7 +464,9 @@ public enum FallbackPacketRegistry {
map(0x2C, MINECRAFT_1_20_3, false),
map(0x2F, MINECRAFT_1_20_5, false),
map(0x31, MINECRAFT_1_21_2, false),
map(0x33, MINECRAFT_1_21_4, false));
map(0x33, MINECRAFT_1_21_4, false),
map(0x34, MINECRAFT_1_21_6, false));
// minecraft:paddle_boat
serverbound.register(PaddleBoatPacket.class, PaddleBoatPacket::new,
map(0x11, MINECRAFT_1_9, false),
map(0x12, MINECRAFT_1_12, false),
@@ -434,7 +482,9 @@ public enum FallbackPacketRegistry {
map(0x1B, MINECRAFT_1_20_2, false),
map(0x1C, MINECRAFT_1_20_3, false),
map(0x1F, MINECRAFT_1_20_5, false),
map(0x21, MINECRAFT_1_21_2, false));
map(0x21, MINECRAFT_1_21_2, false),
map(0x22, MINECRAFT_1_21_6, false));
// minecraft:player_input
serverbound.register(PlayerInputPacket.class, PlayerInputPacket::new,
map(0x0C, MINECRAFT_1_7_2, false),
map(0x15, MINECRAFT_1_9, false),
@@ -451,7 +501,9 @@ public enum FallbackPacketRegistry {
map(0x23, MINECRAFT_1_20_3, false),
map(0x26, MINECRAFT_1_20_5, false),
map(0x28, MINECRAFT_1_21_2, false),
map(0x29, MINECRAFT_1_21_4, false));
map(0x29, MINECRAFT_1_21_4, false),
map(0x2A, MINECRAFT_1_21_6, false));
// minecraft:move_vehicle
serverbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
map(0x10, MINECRAFT_1_9, false),
map(0x11, MINECRAFT_1_12, false),
@@ -467,7 +519,9 @@ public enum FallbackPacketRegistry {
map(0x1A, MINECRAFT_1_20_2, false),
map(0x1B, MINECRAFT_1_20_3, false),
map(0x1E, MINECRAFT_1_20_5, false),
map(0x20, MINECRAFT_1_21_2, false));
map(0x20, MINECRAFT_1_21_2, false),
map(0x21, MINECRAFT_1_21_6, false));
// minecraft:chat
serverbound.register(SystemChatPacket.class, SystemChatPacket::new,
map(0x01, MINECRAFT_1_7_2, false),
map(0x02, MINECRAFT_1_9, false),
@@ -478,7 +532,9 @@ public enum FallbackPacketRegistry {
map(0x05, MINECRAFT_1_19_1, false),
map(0x05, MINECRAFT_1_19_3, false),
map(0x06, MINECRAFT_1_20_5, false),
map(0x07, MINECRAFT_1_21_2, false));
map(0x07, MINECRAFT_1_21_2, false),
map(0x08, MINECRAFT_1_21_6, false));
// minecraft:keep_alive
serverbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
map(0x00, MINECRAFT_1_7_2, false),
map(0x0B, MINECRAFT_1_9, false),
@@ -495,7 +551,9 @@ public enum FallbackPacketRegistry {
map(0x14, MINECRAFT_1_20_2, false),
map(0x15, MINECRAFT_1_20_3, false),
map(0x18, MINECRAFT_1_20_5, false),
map(0x1A, MINECRAFT_1_21_2, false));
map(0x1A, MINECRAFT_1_21_2, false),
map(0x1B, MINECRAFT_1_21_6, false));
// minecraft:client_information
serverbound.register(ClientInformationPacket.class, ClientInformationPacket::new,
map(0x15, MINECRAFT_1_7_2, false),
map(0x04, MINECRAFT_1_9, false),
@@ -508,7 +566,9 @@ public enum FallbackPacketRegistry {
map(0x08, MINECRAFT_1_19_4, false),
map(0x09, MINECRAFT_1_20_2, false),
map(0x0A, MINECRAFT_1_20_5, false),
map(0x0C, MINECRAFT_1_21_2, false));
map(0x0C, MINECRAFT_1_21_2, false),
map(0x0D, MINECRAFT_1_21_6, false));
// minecraft:custom_payload
serverbound.register(PluginMessagePacket.class, PluginMessagePacket::new,
map(0x17, MINECRAFT_1_7_2, false),
map(0x09, MINECRAFT_1_9, false),
@@ -523,7 +583,9 @@ public enum FallbackPacketRegistry {
map(0x0D, MINECRAFT_1_19_4, false),
map(0x0F, MINECRAFT_1_20_2, false),
map(0x12, MINECRAFT_1_21, false),
map(0x14, MINECRAFT_1_21_2, false));
map(0x14, MINECRAFT_1_21_2, false),
map(0x15, MINECRAFT_1_21_6, false));
// minecraft:move_player_status_only
serverbound.register(SetPlayerOnGround.class, SetPlayerOnGround::new,
map(0x03, MINECRAFT_1_7_2, false),
map(0x0F, MINECRAFT_1_9, false),
@@ -540,7 +602,9 @@ public enum FallbackPacketRegistry {
map(0x19, MINECRAFT_1_20_2, false),
map(0x1A, MINECRAFT_1_20_3, false),
map(0x1D, MINECRAFT_1_20_5, false),
map(0x1F, MINECRAFT_1_21_2, false));
map(0x1F, MINECRAFT_1_21_2, false),
map(0x20, MINECRAFT_1_21_6, false));
// minecraft:move_player_pos
serverbound.register(SetPlayerPositionPacket.class, SetPlayerPositionPacket::new,
map(0x04, MINECRAFT_1_7_2, false),
map(0x0C, MINECRAFT_1_9, false),
@@ -557,7 +621,9 @@ public enum FallbackPacketRegistry {
map(0x16, MINECRAFT_1_20_2, false),
map(0x17, MINECRAFT_1_20_3, false),
map(0x1A, MINECRAFT_1_20_5, false),
map(0x1C, MINECRAFT_1_21_2, false));
map(0x1C, MINECRAFT_1_21_2, false),
map(0x1D, MINECRAFT_1_21_6, false));
// minecraft:move_player_rot
serverbound.register(SetPlayerRotationPacket.class, SetPlayerRotationPacket::new,
map(0x05, MINECRAFT_1_7_2, false),
map(0x0E, MINECRAFT_1_9, false),
@@ -574,7 +640,9 @@ public enum FallbackPacketRegistry {
map(0x18, MINECRAFT_1_20_2, false),
map(0x19, MINECRAFT_1_20_3, false),
map(0x1C, MINECRAFT_1_20_5, false),
map(0x1E, MINECRAFT_1_21_2, false));
map(0x1E, MINECRAFT_1_21_2, false),
map(0x1F, MINECRAFT_1_21_6, false));
// minecraft:move_player_pos_rot
serverbound.register(SetPlayerPositionRotationPacket.class, SetPlayerPositionRotationPacket::new,
map(0x06, MINECRAFT_1_7_2, false),
map(0x0D, MINECRAFT_1_9, false),
@@ -591,9 +659,12 @@ public enum FallbackPacketRegistry {
map(0x17, MINECRAFT_1_20_2, false),
map(0x18, MINECRAFT_1_20_3, false),
map(0x1B, MINECRAFT_1_20_5, false),
map(0x1D, MINECRAFT_1_21_2, false));
map(0x1D, MINECRAFT_1_21_2, false),
map(0x1E, MINECRAFT_1_21_6, false));
// minecraft:accept_teleportation
serverbound.register(ConfirmTeleportationPacket.class, ConfirmTeleportationPacket::new,
map(0x00, MINECRAFT_1_9, false));
// minecraft:pong
serverbound.register(TransactionPacket.class, TransactionPacket::new,
map(0x0F, MINECRAFT_1_7_2, false),
map(0x05, MINECRAFT_1_9, false),
@@ -610,7 +681,9 @@ public enum FallbackPacketRegistry {
map(0x24, MINECRAFT_1_20_3, false),
map(0x27, MINECRAFT_1_20_5, false),
map(0x29, MINECRAFT_1_21_2, false),
map(0x2B, MINECRAFT_1_21_4, false));
map(0x2B, MINECRAFT_1_21_4, false),
map(0x2C, MINECRAFT_1_21_6, false));
// minecraft:swing
serverbound.register(AnimationPacket.class, AnimationPacket::new,
map(0x0A, MINECRAFT_1_7_2, false),
map(0x1A, MINECRAFT_1_9, false),
@@ -625,7 +698,9 @@ public enum FallbackPacketRegistry {
map(0x33, MINECRAFT_1_20_3, false),
map(0x36, MINECRAFT_1_20_5, false),
map(0x38, MINECRAFT_1_21_2, false),
map(0x3A, MINECRAFT_1_21_4, false));
map(0x3A, MINECRAFT_1_21_4, false),
map(0x3B, MINECRAFT_1_21_5, false),
map(0x3C, MINECRAFT_1_21_6, false));
}
};
@@ -28,18 +28,19 @@ import xyz.jonesdev.sonar.api.config.SonarConfiguration;
import xyz.jonesdev.sonar.api.event.impl.CaptchaGenerationStartEvent;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator;
import xyz.jonesdev.sonar.captcha.legacy.LegacyCaptchaGenerator;
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockType;
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockUpdate;
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionRegistry;
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionType;
import xyz.jonesdev.sonar.common.fallback.protocol.entity.EntityType;
import xyz.jonesdev.sonar.common.fallback.protocol.item.ItemType;
import xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration.FinishConfigurationPacket;
import xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration.RegistryDataPacket;
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginSuccessPacket;
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.*;
import xyz.jonesdev.sonar.common.util.ComponentHolder;
import java.io.File;
import java.util.Random;
import java.util.UUID;
@@ -75,8 +76,18 @@ public class FallbackPreparer {
public final FallbackPacket NO_MOVE_ABILITIES_BEDROCK = new PlayerAbilitiesPacket(0x06, 0, 0);
public final FallbackPacket CAPTCHA_POSITION = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
SPAWN_X_POSITION, 10000, SPAWN_Z_POSITION, 0, 90, 0, 0, false, false, true));
public final FallbackPacket EMPTY_CHUNK_DATA = new FallbackPacketSnapshot(new ChunkDataPacket(0, 0));
public final FallbackPacket FINISH_CONFIGURATION = new FinishConfigurationPacket();
// I think the people working at Microsoft are actually the *real* ultimate trolls of the internet!
public final FallbackPacket[] EMPTY_CHUNK_DATA = new FallbackPacket[]{
new FallbackPacketSnapshot(new ChunkDataPacket(0, 0)),
new FallbackPacketSnapshot(new ChunkDataPacket(0, 1)),
new FallbackPacketSnapshot(new ChunkDataPacket(0, -1)),
new FallbackPacketSnapshot(new ChunkDataPacket(1, 0)),
new FallbackPacketSnapshot(new ChunkDataPacket(1, 1)),
new FallbackPacketSnapshot(new ChunkDataPacket(1, -1)),
new FallbackPacketSnapshot(new ChunkDataPacket(-1, 0)),
new FallbackPacketSnapshot(new ChunkDataPacket(-1, 1)),
new FallbackPacketSnapshot(new ChunkDataPacket(-1, -1))
};
public final FallbackPacket PRE_JOIN_KEEP_ALIVE = new FallbackPacketSnapshot(new KeepAlivePacket(PRE_JOIN_KEEP_ALIVE_ID));
public final FallbackPacket[] REGISTRY_SYNC_1_20 = new FallbackPacket[] {
new FallbackPacketSnapshot(new RegistryDataPacket(DimensionRegistry.CODEC_1_20, null, null))};
@@ -84,6 +95,7 @@ public class FallbackPreparer {
public final FallbackPacket[] REGISTRY_SYNC_1_21 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21);
public final FallbackPacket[] REGISTRY_SYNC_1_21_2 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_2);
public final FallbackPacket[] REGISTRY_SYNC_1_21_4 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_4);
public final FallbackPacket[] REGISTRY_SYNC_1_21_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_5);
public final FallbackPacket START_WRITING_CHUNKS = new GameEventPacket(13, 0);
public final static FallbackPacket INVALID_HELD_ITEM_SLOT = new SetHeldItemPacket(-1);
public final FallbackPacket RANDOM_KEEP_ALIVE = new FallbackPacketSnapshot(new KeepAlivePacket(RANDOM.nextInt()));
@@ -96,11 +108,11 @@ public class FallbackPreparer {
public static final FallbackPacket REMOVE_VEHICLE = new RemoveEntitiesPacket(VEHICLE_ENTITY_ID);
public static final FallbackPacket SET_VEHICLE_PASSENGERS = new FallbackPacketSnapshot(
new SetPassengersPacket(VEHICLE_ENTITY_ID, PLAYER_ENTITY_ID));
public FallbackPacket[] incorrectCaptcha;
public FallbackPacket loginSuccess;
public FallbackPacket welcomeMessage;
public FallbackPacket enterCodeMessage;
public FallbackPacket incorrectCaptcha;
public static FallbackPacket joinGame;
public FallbackPacket defaultSpawnPosition;
public FallbackPacket spawnPosition;
@@ -156,6 +168,7 @@ public class FallbackPreparer {
// Set the dynamic block and collide Y position based on the maximum fall distance
dynamicSpawnYPosition = PLATFORM_Y_POSITION + (int) Math.ceil(fallDistance);
defaultSpawnPosition = new FallbackPacketSnapshot(new SetDefaultSpawnPositionPacket(
"minecraft:overworld",
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION));
spawnPosition = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
@@ -226,11 +239,14 @@ public class FallbackPreparer {
MiniMessage.miniMessage().deserialize(
Sonar.get0().getConfig().getMessagesConfig().getString("verification.captcha.enter"),
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
incorrectCaptcha = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
MiniMessage.miniMessage().deserialize(
Sonar.get0().getConfig().getMessagesConfig().getString("verification.captcha.incorrect"),
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
incorrectCaptcha = new FallbackPacket[Sonar.get0().getConfig().getVerification().getMap().getMaxTries()];
for (int i = 0; i < incorrectCaptcha.length; i++) {
incorrectCaptcha[i] = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
MiniMessage.miniMessage().deserialize(
Sonar.get0().getConfig().getMessagesConfig().getString("verification.captcha.incorrect"),
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
Placeholder.unparsed("attempts-left", String.valueOf(i + 1))))));
}
// Prepare countdown
xpCountdown = new FallbackPacket[Sonar.get0().getConfig().getVerification().getMap().getMaxDuration() / 1000];
@@ -245,9 +261,13 @@ public class FallbackPreparer {
Sonar.get0().getEventManager().publish(generationStartEvent);
if (generationStartEvent.getCaptchaGenerator() == null
|| generationStartEvent.getCaptchaGenerator() instanceof StandardCaptchaGenerator) {
Sonar.get0().getFallback().setCaptchaGenerator(new StandardCaptchaGenerator(
Sonar.get0().getConfig().getVerification().getMap().getBackgroundImage()));
|| generationStartEvent.getCaptchaGenerator() instanceof StandardCaptchaGenerator
|| generationStartEvent.getCaptchaGenerator() instanceof LegacyCaptchaGenerator) {
final File backgroundImage = Sonar.get0().getConfig().getVerification().getMap().getBackgroundImage();
final boolean useLegacyCaptchaGenerator = Sonar.get0().getConfig().getGeneralConfig()
.getString("verification.checks.map-captcha.style").equalsIgnoreCase("legacy");
Sonar.get0().getFallback().setCaptchaGenerator(useLegacyCaptchaGenerator
? new LegacyCaptchaGenerator(backgroundImage) : new StandardCaptchaGenerator(backgroundImage));
} else {
Sonar.get0().getLogger().info("Custom CAPTCHA generator detected, skipping reinitialization.");
}
@@ -266,11 +286,13 @@ public class FallbackPreparer {
+ (xpCountdown == null ? 0 : xpCountdown.length) * 20 + 5
+ Sonar.get0().getConfig().getVerification().getVehicle().getMinimumPackets() * 4
+ Sonar.get0().getConfig().getVerification().getMap().getMaxTries()
+ 150 /* some arbitrary leeway */;
+ Sonar.get0().getConfig().getVerification().getMaxPacketCount();
}
public static FallbackPacket[] getRegistryPackets(final @NotNull ProtocolVersion protocolVersion) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_4)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_5)) {
return REGISTRY_SYNC_1_21_5;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_4)) {
return REGISTRY_SYNC_1_21_4;
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
return REGISTRY_SYNC_1_21_2;
@@ -34,7 +34,6 @@ public enum BlockType {
// - https://github.com/PrismarineJS/minecraft-data/blob/master/data/pc/
// - https://pokechu22.github.io/Burger/
// - https://github.com/ViaVersion/Mappings/tree/main/mappings
//STONE(protocolVersion -> 1, 1),
ENCHANTMENT_TABLE(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
return 116;
@@ -72,7 +71,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 7619;
}
return 8163;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 8163;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 8173;
}
return 9250;
}, protocolVersion -> (double) 0.75f),
TRAPDOOR(protocolVersion -> {
// We have to use wooden trapdoors for 1.7 since 1.7 doesn't have iron trapdoors
@@ -118,7 +123,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 10749;
}
return 11293;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 11293;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 11303;
}
return 12380;
}, protocolVersion -> 0.1875),
END_PORTAL_FRAME(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -157,7 +168,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 7644;
}
return 8185;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 8185;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 8195;
}
return 9272;
}, protocolVersion -> 0.8125),
DAYLIGHT_SENSOR(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -199,7 +216,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 9462;
}
return 10006;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 10006;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 10016;
}
return 11093;
}, protocolVersion -> 0.375),
COBBLESTONE_WALL(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -238,7 +261,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 8152;
}
return 8696;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 8696;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 8706;
}
return 9783;
}, protocolVersion -> 1.5),
STONE_SLABS(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -280,7 +309,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 11566;
}
return 12110;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 12110;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 12120;
}
return 13197;
}, protocolVersion -> 0.5),
WHITE_CARPET(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
@@ -322,7 +357,13 @@ public enum BlockType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 11063;
}
return 11607;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 11607;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 11617;
}
return 12694;
}, protocolVersion -> protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 0 : 0.0625);
private final Function<ProtocolVersion, Integer> id;
@@ -39,6 +39,7 @@ public final class DimensionRegistry {
public final CompoundBinaryTag CODEC_1_21;
public final CompoundBinaryTag CODEC_1_21_2;
public final CompoundBinaryTag CODEC_1_21_4;
public final CompoundBinaryTag CODEC_1_21_5;
static {
CODEC_1_16 = getCodec("codec_1_16.nbt");
@@ -52,6 +53,7 @@ public final class DimensionRegistry {
CODEC_1_21 = getCodec("codec_1_21.nbt");
CODEC_1_21_2 = getCodec("codec_1_21_2.nbt");
CODEC_1_21_4 = getCodec("codec_1_21_4.nbt");
CODEC_1_21_5 = getCodec("codec_1_21_5.nbt");
}
private @NotNull CompoundBinaryTag getCodec(final @NotNull String fileName) {
@@ -58,7 +58,13 @@ public enum EntityType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 85;
}
return 84;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_5)) {
return 84;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 85;
}
return 87;
}),
MINECART(protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
@@ -94,7 +100,13 @@ public enum EntityType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 82;
}
return 81;
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_5)) {
return 81;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 82;
}
return 84;
});
private final Function<ProtocolVersion, Integer> id;
@@ -73,8 +73,25 @@ public enum ItemType {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
return 1022;
}
return 1031;
}, protocolVersion -> protocolVersion.greaterThanOrEquals(MINECRAFT_1_21_2) ? 36 : 26);
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 1031;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_5)) {
return 1042;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
return 1059;
}
return 1104;
}, protocolVersion -> {
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
return 26;
}
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
return 36;
}
return 37;
});
private final Function<ProtocolVersion, Integer> id;
private final Function<ProtocolVersion, Integer> components;
@@ -18,10 +18,14 @@
package xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration;
import io.netty.buffer.ByteBuf;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class FinishConfigurationPacket implements FallbackPacket {
public static final FinishConfigurationPacket INSTANCE = new FinishConfigurationPacket();
@Override
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
@@ -60,15 +60,26 @@ public final class ChunkDataPacket implements FallbackPacket {
}
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_14)) {
final long[] motionBlockingData = new long[protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18) ? 36 : 37];
final CompoundBinaryTag motionBlockingTag = CompoundBinaryTag.builder()
.put("MOTION_BLOCKING", LongArrayBinaryTag.longArrayBinaryTag(motionBlockingData))
.build();
final CompoundBinaryTag rootTag = CompoundBinaryTag.builder()
.put("root", motionBlockingTag)
.build();
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_5)) {
// In 1.21.5. They changed to List<EnumMap<Heightmap.Type, long[]>>
ProtocolUtil.writeVarInt(byteBuf, 1); // List size
ProtocolUtil.writeVarInt(byteBuf, 4); // Ordinal of MOTION_BLOCKING
// Write long array
ProtocolUtil.writeVarInt(byteBuf, 37);
for (int i = 0; i < 37; i++) {
byteBuf.writeLong(0);
}
} else { // Nbt for older version
final long[] motionBlockingData = new long[protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18) ? 36 : 37];
final CompoundBinaryTag motionBlockingTag = CompoundBinaryTag.builder()
.put("MOTION_BLOCKING", LongArrayBinaryTag.longArrayBinaryTag(motionBlockingData))
.build();
final CompoundBinaryTag rootTag = CompoundBinaryTag.builder()
.put("root", motionBlockingTag)
.build();
ProtocolUtil.writeBinaryTag(byteBuf, protocolVersion, rootTag);
ProtocolUtil.writeBinaryTag(byteBuf, protocolVersion, rootTag);
}
if (protocolVersion.inBetween(ProtocolVersion.MINECRAFT_1_15, ProtocolVersion.MINECRAFT_1_17_1)) {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_16_2)) {
@@ -95,7 +106,12 @@ public final class ChunkDataPacket implements FallbackPacket {
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18)) {
ProtocolUtil.writeVarInt(byteBuf, 0);
} else {
final byte[] sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0};
// nonEmptyBlockCount. short occupies 2 bytes.
// SingularPalette (byte) + id (varint) + long array with size (older)
// Since 1.21.5. The length of the long array of PaletteStorage no longer depends on the VarInt in the packet
// SingularPalette doesn't need to read any additional long array.
// So we'll remove suffix 0 as array length here. The cost of writing a palette has been reduced from 3 to 2 bytes.
final byte[] sectionData = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_21_5) ? new byte[]{0, 0, 0, 0, 0, 0, 1, 0} : new byte[]{0, 0, 0, 0, 0, 1};
int count = 24;
ProtocolUtil.writeVarInt(byteBuf, sectionData.length * count);
@@ -67,6 +67,6 @@ public final class PluginMessagePacket implements FallbackPacket {
@Override
public int expectedMaxLength(final ProtocolVersion protocolVersion) {
return 0xFFF; // strict size limit
return Short.MAX_VALUE; // vanilla size limit
}
}
@@ -25,12 +25,14 @@ import lombok.ToString;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public final class SetDefaultSpawnPositionPacket implements FallbackPacket {
private String dimensionName;
private int x, y, z;
@Override
@@ -40,6 +42,10 @@ public final class SetDefaultSpawnPositionPacket implements FallbackPacket {
byteBuf.writeInt(y);
byteBuf.writeInt(z);
} else {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_9)) {
ProtocolUtil.writeString(byteBuf, dimensionName);
}
final long encoded = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_14)
? ((x & 0x3FFFFFFL) << 38) | ((y & 0xFFFL) << 26) | (z & 0x3FFFFFFL)
: ((x & 0x3FFFFFFL) << 38) | ((y & 0x3FFFFFFL) << 12) | (z & 0xFFFL);
@@ -48,6 +54,10 @@ public final class SetDefaultSpawnPositionPacket implements FallbackPacket {
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_17)) {
byteBuf.writeFloat(0f);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_9)) {
byteBuf.writeFloat(0f); // pitch
}
}
}
}
@@ -59,6 +59,10 @@ public final class SpawnEntityPacket implements FallbackPacket {
byteBuf.writeDouble(x);
byteBuf.writeDouble(y);
byteBuf.writeDouble(z);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_9)) {
encodeVelocity(byteBuf, velocityX, velocityY, velocityZ);
}
} else {
byteBuf.writeInt((int) (x * 32D));
byteBuf.writeInt((int) (y * 32D));
@@ -75,13 +79,43 @@ public final class SpawnEntityPacket implements FallbackPacket {
byteBuf.writeInt(data); // data
}
if (data > 0 || protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_9)) {
byteBuf.writeShort((int) (velocityX * 8000D));
byteBuf.writeShort((int) (velocityY * 8000D));
byteBuf.writeShort((int) (velocityZ * 8000D));
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_21_9)) {
if (data > 0 || protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_9)) {
byteBuf.writeShort((int) (velocityX * 8000D));
byteBuf.writeShort((int) (velocityY * 8000D));
byteBuf.writeShort((int) (velocityZ * 8000D));
}
}
}
private static void encodeVelocity(final ByteBuf byteBuf, final double x, final double y, final double z) {
final double maxVal = Math.max(Math.abs(x), Math.max(Math.abs(y), Math.abs(z)));
if (maxVal < 3.051944088384301E-5) {
byteBuf.writeByte(0);
return;
}
final long scale = (long) Math.ceil(maxVal);
final boolean scaleTooLargeForBits = (scale & 3L) != scale;
final long scaleBits = scaleTooLargeForBits ? scale & 3L | 4L : scale;
final long encodedX = packLpVec3Component(x / scale) << 3;
final long encodedY = packLpVec3Component(y / scale) << 18;
final long encodedZ = packLpVec3Component(z / scale) << 33;
final long packed = scaleBits | encodedX | encodedY | encodedZ;
byteBuf.writeByte((byte) packed);
byteBuf.writeByte((byte) (packed >> 8));
byteBuf.writeInt((int) (packed >> 16));
if (scaleTooLargeForBits) {
ProtocolUtil.writeVarInt(byteBuf, (int) (scale >> 2));
}
}
private static long packLpVec3Component(double d) {
return Math.round((d * 0.5 + 0.5) * 32766.0);
}
@Override
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException();
@@ -118,6 +118,10 @@ public final class SystemChatPacket implements FallbackPacket {
ProtocolUtil.readVarInt(byteBuf);
final byte[] bytes = new byte[DIV_FLOOR];
byteBuf.readBytes(bytes);
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_5)) {
byteBuf.readByte(); // Check sum
}
}
}
}
@@ -37,11 +37,7 @@ public final class VehicleMovePacket implements FallbackPacket {
@Override
public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
byteBuf.writeDouble(x);
byteBuf.writeDouble(y);
byteBuf.writeDouble(z);
byteBuf.writeFloat(yaw);
byteBuf.writeFloat(pitch);
throw new UnsupportedOperationException();
}
@Override
@@ -79,7 +79,7 @@ public final class FallbackCaptchaHandler extends FallbackVerificationHandler {
// Decrement the number of tries left
checkState(tries-- > 0, "failed CAPTCHA too often");
// Send the player a chat message to let them know that the code they entered is incorrect
user.write(incorrectCaptcha);
user.write(incorrectCaptcha[tries]);
} else if (packet instanceof SetPlayerPositionPacket
|| packet instanceof SetPlayerPositionRotationPacket) {
// A position packet is sent approximately every second
@@ -64,9 +64,13 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
// Make sure the client knows that we're sending chunks next
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_3)) {
user.delayedWrite(START_WRITING_CHUNKS);
for (final FallbackPacket section : EMPTY_CHUNK_DATA) {
user.delayedWrite(section);
}
} else {
user.delayedWrite(EMPTY_CHUNK_DATA[0]);
}
// Teleport player into an empty world by sending an empty chunk packet
user.delayedWrite(EMPTY_CHUNK_DATA);
// Spawn the invisible platform below the player
if (enableCollisionsCheck) {
final int index = RANDOM.nextInt(BLOCKS_PACKETS.length);
@@ -89,9 +93,9 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
private final FallbackPreJoinHandler preJoinHandler;
private final boolean enableGravityCheck, enableCollisionsCheck;
private boolean teleported, canFall, checkMovement;
private boolean teleported, canFall, checkMovement, expectClientTick, expectTeleportPosRot;
private double y, deltaY, blockHeight;
private int movementTick, clientTick, expectedTeleportId = FIRST_TELEPORT_ID;
private int movementTick, tickWithoutMove, expectedTeleportId = FIRST_TELEPORT_ID;
private SetPlayerPositionRotationPacket lastPositionPacket;
@Override
@@ -101,8 +105,14 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
final SetPlayerPositionRotationPacket position = (SetPlayerPositionRotationPacket) packet;
if (teleported) {
handleMovement(position.getX(), position.getY(), position.getZ(), position.isOnGround(), true);
} else if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
} else if (user.getProtocolVersion().equals(ProtocolVersion.MINECRAFT_1_21_2)) {
lastPositionPacket = position;
return;
}
if (expectTeleportPosRot) {
expectTeleportPosRot = false;
} else {
checkClientTick();
}
} else if (packet instanceof SetPlayerPositionPacket) {
// Make sure the player has teleported before checking for position packets
@@ -110,6 +120,7 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
final SetPlayerPositionPacket position = (SetPlayerPositionPacket) packet;
handleMovement(position.getX(), position.getY(), position.getZ(), position.isOnGround(), false);
}
checkClientTick();
} else if (packet instanceof ConfirmTeleportationPacket) {
final ConfirmTeleportationPacket confirmTeleport = (ConfirmTeleportationPacket) packet;
@@ -119,31 +130,58 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
checkState(confirmTeleport.getTeleportId() == expectedTeleportId,
"expected TP ID " + expectedTeleportId + ", but got " + confirmTeleport.getTeleportId());
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;
}
// The first teleport ID is not useful for us in this context, skip it
if (expectedTeleportId == FIRST_TELEPORT_ID) {
lastPositionPacket = null;
expectedTeleportId = SECOND_TELEPORT_ID;
} else {
// Enable the movement checks
teleported = true;
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
checkState(lastPositionPacket != null, "excepted position rotation but got teleport confirm.");
if (sendPosRotBefore) {
handleMovement(
lastPositionPacket.getX(), lastPositionPacket.getY(), lastPositionPacket.getZ(),
lastPositionPacket.isOnGround(), true);
}
}
lastPositionPacket = null;
} else if (packet instanceof ClientInformationPacket
|| packet instanceof PluginMessagePacket) {
// Pass these packets back to the login handler
// TODO: recode this
preJoinHandler.handle(packet);
} else if (packet instanceof ClientTickEndPacket) {
clientTick++;
lastPositionPacket = null;
if (!expectClientTick) {
// Is it impossible for the client to not move during the gravity check?
if (++tickWithoutMove >= 20) {
//failOrShowCaptcha("expected position but got client tick end.");
}
} else {
tickWithoutMove = 0;
expectClientTick = false;
}
}
}
private void checkClientTick() {
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_2)) {
return;
}
if (expectClientTick) {
failOrShowCaptcha("expected client tick end but got position.");
} else {
expectClientTick = true;
}
tickWithoutMove = 0; // lag may cause some problems :(
}
private void markSuccess() {
// Force-stop the movement checks
teleported = false;
@@ -194,19 +232,15 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
}
// Ensure that the player's Y coordinate is above the collision platform
checkState(y >= PLATFORM_Y_POSITION,
"fell through blocks: " + y + "/" + deltaY + "/" + movementTick);
if (y < PLATFORM_Y_POSITION) {
failOrShowCaptcha("fell through blocks: " + y + "/" + deltaY + "/" + movementTick);
}
// The player is not allowed to move away from the collision platform.
// This should not happen unless the max movement tick is configured to a high number.
checkState(Math.abs(Math.abs(x) - BLOCKS_PER_ROW) < BLOCKS_PER_ROW, "illegal x offset: " + x);
checkState(Math.abs(Math.abs(z) - BLOCKS_PER_ROW) < BLOCKS_PER_ROW, "illegal z offset: " + z);
// Check if the client is ticking correctly
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
checkState(clientTick >= movementTick, "invalid ticking: " + clientTick + "/" + movementTick);
}
if (!onGround) {
// 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.
@@ -80,11 +80,11 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
} else {
markAcknowledged();
}
}
// 1.8 clients send KeepAlive packets with the ID 0 every second
// while the player is in the "Downloading terrain" screen.
expectedKeepAliveId = 0;
// Disable the check for any further packets the client might send
// while loading the world (or similar).
expectedKeepAliveId = 0;
}
} else if (packet instanceof LoginAcknowledgedPacket) {
// Prevent users from sending multiple LoginAcknowledged packets
checkState(!acknowledgedLogin, "sent duplicate login ack");
@@ -106,17 +106,12 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
checkState(clientInformation.getViewDistance() >= 2,
"view distance: " + clientInformation.getViewDistance());
}
// Ensure that the client locale is correct
validateClientLocale(clientInformation.getLocale());
// Check if the player sent an unused bit flag in the skin section
// TODO: check if this causes issues with cosmetics in pvp clients
checkState((clientInformation.getSkinParts() & 0x80) == 0,
"sent unused bit flag: " + clientInformation.getSkinParts());
receivedClientInfo = true;
} else if (packet instanceof PluginMessagePacket) {
final PluginMessagePacket pluginMessage = (PluginMessagePacket) packet;
// TODO: Resolve as namespace (?)
final boolean usingModernChannel = pluginMessage.getChannel().equals("minecraft:brand");
final boolean usingLegacyChannel = pluginMessage.getChannel().equals("MC|Brand");
@@ -125,17 +120,11 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
return;
}
// Make sure the player isn't sending the client brand multiple times
checkState(!receivedClientBrand, "sent duplicate plugin message");
// Check if the channel is correct - 1.13 uses the new namespace
// system ('minecraft:' + channel) and anything below 1.13 uses
// the legacy namespace system ('MC|' + channel).
checkState(usingLegacyChannel
|| user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_13),
"illegal PluginMessage channel: " + pluginMessage.getChannel());
// Validate the client branding using a regex to filter unwanted characters.
if (Sonar.get0().getConfig().getVerification().getBrand().isEnabled()) {
// Make sure the player isn't sending the client brand multiple times
checkState(!receivedClientBrand, "sent duplicate client brand");
validateClientBrand(pluginMessage.getData());
}
@@ -150,7 +139,7 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
user.delayedWrite(packet);
}
// Write the FinishConfiguration packet to the buffer
user.delayedWrite(FINISH_CONFIGURATION);
user.delayedWrite(FinishConfigurationPacket.INSTANCE);
// Send all packets in one flush
user.channel().flush();
}
@@ -170,7 +159,7 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
void validateClientInformation() {
checkState(receivedClientInfo, "didn't send client settings");
checkState(receivedClientBrand, "didn't send plugin message");
checkState(receivedClientBrand, "didn't send client brand");
}
private void updateEncoderDecoderState(final @NotNull FallbackPacketRegistry registry) {
@@ -188,20 +177,11 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
// https://discord.com/channels/923308209769426994/1116066363887321199/1256929441053933608
String brand = new String(data, StandardCharsets.UTF_8);
// Remove the invalid character at the beginning of the client brand
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_8)) {
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_8) && brand.length() > 1) {
brand = brand.substring(1);
}
// Check for illegal client brands
checkState(!brand.equals("Vanilla"), "illegal client brand: " + brand);
// Regex pattern for validating client brands
final Pattern pattern = Sonar.get0().getConfig().getVerification().getBrand().getValidRegex();
checkState(pattern.matcher(brand).matches(), "client brand does not match pattern: " + brand);
}
private void validateClientLocale(final @NotNull String locale) {
// Check the client locale by performing a simple regex check
// that disallows non-ascii characters by default.
final Pattern pattern = Sonar.get0().getConfig().getVerification().getValidLocaleRegex();
checkState(pattern.matcher(locale).matches(), "client locale does not match pattern: " + locale);
}
}
@@ -20,9 +20,11 @@ package xyz.jonesdev.sonar.common.service;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.Sonar;
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
import xyz.jonesdev.sonar.api.update.UpdateChecker;
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
import java.sql.SQLException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -30,6 +32,7 @@ import java.util.concurrent.TimeUnit;
@UtilityClass
public final class ScheduledServiceManager {
private final ScheduledExecutorService VERBOSE = createScheduledExecutor("sonar-verbose-thread");
private final ScheduledExecutorService DB_CLEANUP = createScheduledExecutor("sonar-db-cleanup-thread");
private final ScheduledExecutorService FALLBACK_QUEUE = createScheduledExecutor("sonar-queue-thread");
private final ScheduledExecutorService STATISTICS = createScheduledExecutor("sonar-statistics-thread");
private final ScheduledExecutorService UPDATE_NOTIFIER = createScheduledExecutor("sonar-update-notifier");
@@ -44,6 +47,18 @@ public final class ScheduledServiceManager {
}
public void start() {
if (Sonar.get0().getVerifiedPlayerController().getCachedDatabaseType() != SonarConfiguration.Database.Type.NONE) {
DB_CLEANUP.scheduleAtFixedRate(() -> {
try {
Sonar.get0().getVerifiedPlayerController().clearOld(
Sonar.get0().getVerifiedPlayerController().getMaximumAge(), true);
} catch (SQLException exception) {
Sonar.get0().getLogger().error("Error cleaning database entries!");
exception.printStackTrace(System.err);
}
}, Sonar.get0().getVerifiedPlayerController().getMaximumAge(), 1L, TimeUnit.DAYS);
}
VERBOSE.scheduleAtFixedRate(() -> {
// Make sure to clean up the cached statistics since we don't want to display wrong values
GlobalSonarStatistics.cleanUpCaches();
@@ -68,6 +83,7 @@ public final class ScheduledServiceManager {
}
public void stop() {
DB_CLEANUP.shutdown();
VERBOSE.shutdown();
FALLBACK_QUEUE.shutdown();
STATISTICS.shutdown();
@@ -34,6 +34,8 @@ public class FakeChannelUtil {
public boolean isFakeChannel(final @NotNull Channel channel) {
final String simpleClassName = channel.getClass().getSimpleName();
// Player spoof plugins use fake channels (e.g., Spoof Engine uses "FakeChannel")
return "FakeChannel".equals(simpleClassName) || "SpoofedChannel".equals(simpleClassName);
return "FakeChannel".equals(simpleClassName)
|| "SpoofedChannel".equals(simpleClassName)
|| "EmbeddedChannel".equals(simpleClassName);
}
}
@@ -44,7 +44,7 @@ attack-tracker:
# Nicméně, IP adresy nemůžou být vystopovány zpátky k hráči, protože Sonar používá UUID na ukládní místo jmeno hráčů
database:
# Typy datábázi se kterýma Sonar bude pracovat
# Typy: NONE, MYSQL, MARIADB, H2
# Typy: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Soubor v adresáři zásuvných modulů Sonaru použitý pro databázi H2
filename: verified_players
@@ -110,6 +110,9 @@ verification:
# Pokud není obrázek nalezen, bude jako výchozí pozadí použit šum
# Zde můžete jednoduše zadat název souboru, pokud je soubor v adresáři pluginu
background: ''
# Styl mapy CAPTCHA (Výchozí: 'modern').
# Chcete-li použít starý design, nastavte tuto hodnotu na 'legacy'.
style: 'modern'
# Kolik odpovědí by měl Sonar předgenerovat?
# Tento úkol běží souběžně v pozadí
precompute: 500
@@ -133,8 +136,6 @@ verification:
# Regex pro validování jmen při verifikaci
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex pro validaci "client locale" při verifikaci
valid-locale-regex: ^[a-zA-Z_]+$
# Je-li povoleno, hráč bude přenesen zpět na původní server
# po úspěšném absolvování ověření bota.
@@ -184,13 +185,15 @@ verification:
# Měl by Sonar také kontrolovat hráče Geyser (Bedrock)?
# Tato funkce je experimentální a může způsobit problémy
# Pokud je toto zakázáno, hráči Bedrock budou přeskočeni
check-geyser-players: true
check-geyser-players: false
# Doba, za kterou hráč přestal odesílat pakety před odpojením
# (Hodnota udávaná v milisekundách: 1 sekunda = 1000 milisekund)
read-timeout: 8000
# Doba od okamžiku, kdy server přestal posílat pakety před odpojením hráče
# (Hodnota udávaná v milisekundách: 1 sekunda = 1000 milisekund)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# Jak dlouho by měl hráč čekat, než se při ověřování znovu připojí
# (Hodnota udávaná v milisekundách: 1 sekunda = 1000 milisekund)
rejoin-delay: 5000
@@ -41,7 +41,7 @@ attack-tracker:
# Beachte: IP adressen werden im Klartext gespeichert. Du bist für die Sicherheit der Datenbank verantwortlich
database:
# Typ von Datenbank die Sonar verwenden soll, um verifizierte Spielerdaten zu speichern
# Mögliche Typen: NONE, MYSQL, MARIADB, H2
# Mögliche Typen: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Datei im Plugin-Verzeichnis von Sonar, die für die H2-Datenbank verwendet wird
filename: verified_players
@@ -107,6 +107,9 @@ verification:
# Wenn das Bild nicht gefunden wird, wird ein Rauschen als Standardhintergrund verwendet
# Sie können hier einfach den Namen der Datei eingeben, wenn sich die Datei im Plugin-Verzeichnis befindet
background: ''
# Stil der Karte CAPTCHA (Standard: 'modern').
# Um das alte Design zu verwenden, setzen Sie dies auf 'legacy'.
style: 'modern'
# Wie viele Antworten soll Sonar vorbereiten?
# Dieser Vorgang erfolgt asynchron im Hintergrund
precompute: 500
@@ -130,8 +133,6 @@ verification:
# Regex zur Validierung von Benutzernamen während der Überprüfung
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex zur Validierung der Client-Spracheinstellung während der Überprüfung
valid-locale-regex: ^[a-zA-Z_]+$
# Wenn aktiviert, wird der Player zurück zum Ursprungsserver gesendet,
# falls dieser die der Bot-Verifizierung erfolgreich besteht.
@@ -181,13 +182,15 @@ verification:
# Sollte Sonar auch Geyser (Bedrock)-Spieler überprüfen?
# Diese Funktion ist experimentell und kann Probleme verursachen
# Wenn dies deaktiviert ist, werden Bedrock-Spieler übersprungen
check-geyser-players: true
check-geyser-players: false
# Die Zeit, seit der der Spieler keine Pakete mehr sendet, bevor er die Verbindung trennt
# (Dieser Wert stellt die Zeit in Millisekunden dar: 1 Sekunde = 1000 Millisekunden)
read-timeout: 8000
# Die Zeit, seit der der Server keine Pakete mehr sendet, bevor er die Verbindung zum Spieler trennt
# (Dieser Wert stellt die Zeit in Millisekunden dar: 1 Sekunde = 1000 Millisekunden)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# Wie lange sollte ein Spieler warten, bevor er während der Überprüfung erneut verbinden kann
# (Dieser Wert stellt die Zeit in Millisekunden dar: 1 Sekunde = 1000 Millisekunden)
rejoin-delay: 5000
@@ -43,7 +43,7 @@ attack-tracker:
# Note: IP addresses are saved in plain text. You are responsible for keeping your database safe!
database:
# Type of database Sonar uses to store verified players
# Possible types: NONE, MYSQL, MARIADB, H2
# Possible types: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# File in Sonar's plugin directory used for the H2 database
filename: verified_players
@@ -109,6 +109,9 @@ verification:
# If the image isn't found, a noise will be used as the default background.
# You can put the name of the file here if the file is in Sonar's plugin directory
background: ''
# Style of the map CAPTCHA (Default: 'modern').
# To use the old design, set this to 'legacy'.
style: 'modern'
# How many CAPTCHA answers should Sonar prepare?
# This task happens asynchronously in the background
precompute: 500
@@ -133,8 +136,6 @@ verification:
# Regex for validating usernames during verification
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex for validating client locale during verification
valid-locale-regex: ^[a-zA-Z_]+$
# If enabled, the player will be transferred back to the origin server
# after successfully passing the bot verification.
@@ -184,13 +185,15 @@ verification:
# Should Sonar also check Geyser (Bedrock) players?
# This feature is experimental and might cause issues
# If this is disabled, Bedrock players will be skipped
check-geyser-players: true
check-geyser-players: false
# The time since the player stopped sending packets before disconnecting
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
read-timeout: 8000
# The time since the server stopped sending packets before disconnecting the player
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# How long should a player wait before reconnecting during verification
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
rejoin-delay: 5000
@@ -43,7 +43,7 @@ attack-tracker:
# Remarque : Les adresses IP sont enregistrées en texte brut. Vous êtes responsable de la sécurité de votre base de données !
database:
# Type de base de données utilisé par Sonar pour stocker les joueurs vérifiés
# Types possibles : NONE, MYSQL, MARIADB, H2
# Types possibles : NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Fichier dans le répertoire des plugins de Sonar utilisé pour la base de données H2
filename: verified_players
@@ -109,6 +109,9 @@ verification:
# Si l'image n'est pas trouvée, un bruit sera utilisé comme arrière-plan par défaut
# Vous pouvez simplement mettre le nom du fichier ici si le fichier est dans le répertoire du plugin
background: ''
# Style de la carte CAPTCHA (par défaut : 'moderne').
# Pour utiliser l'ancien design, mettez ce paramètre à 'legacy'.
style: 'modern'
# Combien de réponses Sonar devrait-il préparer ?
# Cette tâche se déroule de manière asynchrone en arrière-plan
precompute: 500
@@ -132,8 +135,6 @@ verification:
# Regex pour valider les noms d'utilisateur lors de la vérification
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex pour valider la locale client lors de la vérification
valid-locale-regex: ^[a-zA-Z_]+$
# S'il est activé, le joueur sera renvoyé au serveur d'origine
# après avoir passé avec succès la vérification du bot.
@@ -183,13 +184,15 @@ verification:
# Sonar devrait-il également vérifier les joueurs Geyser (Bedrock) ?
# Cette fonctionnalité est expérimentale et peut causer des problèmes
# Si cela est désactivé, les joueurs Bedrock seront ignorés
check-geyser-players: true
check-geyser-players: false
# Temps écoulé depuis que le joueur a cessé d'envoyer des paquets avant de se déconnecter
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
read-timeout: 8000
# Temps écoulé depuis que le serveur a cessé d'envoyer des paquets avant de se déconnecter
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# Combien de temps un joueur doit-il attendre avant de se reconnecter pendant la vérification
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
rejoin-delay: 5000
+19 -16
View File
@@ -43,7 +43,7 @@ attack-tracker:
# შენიშვნა: IP მისამართები ინახება უბრალო ტექსტში. თქვენ ხართ პასუხისმგებელი თქვენი მონაცემთა ბაზის უსაფრთხოებაზე!
database:
# მონაცემთა ბაზის ტიპები, რომლებიც Sonar-ს შეუძლია გამოიყენოს უკვე შემოწმებული მოთამაშეების შესანახად
# შესაძლო ტიპები: NONE, MYSQL, MARIADB, H2
# შესაძლო ტიპები: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# ფაილი სონარ_ის ფოლდერში რომელიც ინახავს H2 database_ს
filename: verified_players
@@ -85,16 +85,16 @@ verification:
# ტიკების მაქსიმალური რაოდენობა რომელითაც მოთამაშე უნდა დაეცეს, რათა პლატფორმაზე დაცემა შეეძლოს. (20 ტიკი = 1 წამი)
max-movement-ticks: 8
# Checks if the player is colliding with blocks spawned below them
# ამოწმებს, ეჯახება თუ არა მოთამაშე მათ ქვემოთ წარმოქმნილ ბლოკებს
collision:
# უნდა შეამოწმოს თუ არა Sonar-მა, ეტაკება თუ არა მოთამაშე ბლოკებს? (რეკომენდებულია)
enabled: true
# ამოწმებს, აგზავნის თუ არა კლიენტი შესაბამის პაკეტებს სატრანსპორტო საშუალებაზე დაჯდომის დროს
vehicle:
# Should Sonar check if the player properly enters a boat?
# უნდა შეამოწმოს თუ არა სონარმა მოთამაშე სწორად შესული თუ არა ნავში?
enabled: true
# Minimum number of packets sent by the client
# კლიენტის მიერ გაგზავნილი პაკეტების მინიმალური რაოდენობა
minimum-packets: 2
# დააწერინეთ მოთამაშეს კოდი ჩატში, რომელიც იქნება ნაჩვენები ვირტუალურ მაპზე, რომელიც ხელში ეჭირებათ
@@ -109,6 +109,9 @@ verification:
# თუ გამოსახულება არ მოიძებნა, ფონად გამოყენებული იქნება noise ი
# შეგიძლიათ უბრალოდ ჩაწეროთ ფაილის სახელი, თუ ის პლაგინის დირექტორიაშია
background: ''
# რუკის სტილი CAPTCHA (ნაგულისხმევი: 'modern').
# ძველი დიზაინის გამოსაყენებლად დააყენეთ ეს 'legacy'.
style: 'modern'
# რამდენი პასუხი უნდა მოამზადოს Sonar-მა?
# ეს ხდება ასინქრონულად (ანუ ამის გამოთვლას სერვერი არ დაელოდება) უკანა ფონზე
precompute: 500
@@ -132,8 +135,6 @@ verification:
# Regex-ი მომხმარებლის სახელების ვერიფიკაციისთვის
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex-ი კლიენტის ადგილის დასადასტურებლად ვერიფიკაციის დროს
valid-locale-regex: ^[a-zA-Z_]+$
# თუ ჩართულია, მოთამაშე გადავა საწყის სერვერში ვერიფიკაციის წარმატებით გავლის შემდეგ
# ეს ფუნქცია დაემატა Mojang-ის მიერ Minecraft-ის 1.20.5 ვერსიაში
@@ -144,8 +145,8 @@ verification:
# დამატებით, შეიძლება გინდოდეთ შეამციროთ შესვლის სიხშირის ლიმიტი
# რომელსაც ახორციელებს Velocity ან სხვა პროქსიები/პლაგინები, რადგან ეს შეიძლება ხელს უშლიდეს
# მოთამაშის სწორად გადაყვანას
# If your server allows Bedrock players to join via Geyser, make sure to set up
# TransferTool for Geyser, so Bedrock players are redirected to the correct server.
# თუ თქვენი სერვერი საშუალებას აძლევს Bedrock მოთამაშეებს შეუერთდნენ Geyser-ის საშუალებით, დარწმუნდით, რომ დააყენეთ
# TransferTool Geyser-ისთვის, ასე რომ Bedrock მოთამაშეები გადამისამართდებიან სწორ სერვერზე.
# https://github.com/onebeastchris/TransferTool
enabled: false
# რომელ სერვერზე უნდა გადაიყვანოს Sonar-მა მოთამაშე ვერიფიკაციის გავლის შემდეგ?
@@ -162,15 +163,15 @@ verification:
# - CREATIVE: სიცოცხლის და საჭმლის მაჩვენებლები იშლება
# - ADVENTURE: ყველა UI კომპონენტი ჩანს
gamemode: ADVENTURE
# Daylight time in the verification world
# You can find all daylight times here:
# დღის განათება გადამოწმების სამყაროში
# აქ შეგიძლიათ იპოვოთ მთელი დღის დრო:
# https://minecraft.wiki/w/Daylight_cycle
# This is only a visual setting and does not change the verification process!
# If this value is set to 1000, the packet will not be sent.
# ეს მხოლოდ ვიზუალური პარამეტრია და არ ცვლის გადამოწმების პროცესს!
# თუ ეს მნიშვნელობა დაყენებულია 1000-ზე, პაკეტი არ გაიგზავნება.
time-of-day: 1000
# Sonar caches most packets it sends to the client, including the LoginSuccess packet.
# Which username should Sonar use for the LoginSuccess packet?
# The username will not be visible to the player without client modifications
# Sonar ინახავს პაკეტების უმეტესობას, რომლებსაც ის უგზავნის კლიენტს, მათ შორის LoginSuccess პაკეტს.
# რომელი მომხმარებლის სახელი უნდა გამოიყენოს Sonar-მა LoginSuccess პაკეტისთვის?
# მომხმარებლის სახელი არ იქნება ხილული მოთამაშისთვის კლიენტის ცვლილებების გარეშე
cached-username: "Sonar"
# ჩაიწეროს თუ არა Sonar-მა ახალი ვერიფიკაციის მცდელობები?
log-connections: true
@@ -182,13 +183,15 @@ verification:
# უნდა შეამოწმოს თუ არა Sonar-მა Geyser (Bedrock) მოთამაშეები?
# ეს ფუნქცია ექსპერიმენტულია და შეიძლება გამოიწვიოს პრობლემები
# თუ ეს გამორთულია, Bedrock მოთამაშეები გამოვლენილი იქნება
check-geyser-players: true
check-geyser-players: false
# დროის ოდენობა, რომელიც უნდა გავიდეს, სერვერთან კავშირის გარეშე, სანამ მოთამაშე დროებით გავარდება სერვერიდან.
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
read-timeout: 8000
# დრო როდიდანაც სერვერმა შეწყვიტა პაკეტების გაგზავნა სანამ გააგდებს მოთამაშეს.
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
write-timeout: 10000
# პაკეტების მაქსიმალური ოდენობა, რომელიც შეუძლია მოთამაშებ გაგზავნოს (შემოწმების დროს).
max-packets: 325
# რამდენ ხანს უნდა დაელოდოს მოთამაშე ვერიფიკაციის დროს ხელახლა დაკავშირებამდე?
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
rejoin-delay: 5000
+10 -7
View File
@@ -43,7 +43,7 @@ attack-tracker:
# Let op: IP-adressen worden opgeslagen in platte tekst. U bent verantwoordelijk voor het veilig houden van uw database!
database:
# Type database dat Sonar gebruikt om geverifieerde spelers op te slaan
# Mogelijke typen: NONE, MYSQL, MARIADB, H2
# Mogelijke typen: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Bestand in de plugin-directory van Sonar dat wordt gebruikt voor de H2-database
filename: verified_players
@@ -109,6 +109,9 @@ verification:
# Als de afbeelding niet wordt gevonden, wordt er een ruis gebruikt als standaardachtergrond
# U kunt eenvoudig de naam van het bestand hier plaatsen als het bestand zich in de plugin map bevindt
background: ''
# Stijl van de CAPTCHA kaart (Standaard: 'modern').
# Om het oude ontwerp te gebruiken, stel je dit in op 'legacy'.
style: 'modern'
# Hoeveel antwoorden moet Sonar voorbereiden?
# Deze taak gebeurt asynchroon op de achtergrond
precompute: 500
@@ -132,8 +135,6 @@ verification:
# Regex voor het valideren van gebruikersnamen tijdens verificatie
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex voor het valideren van de landinstelling van de client tijdens verificatie
valid-locale-regex: ^[a-zA-Z_]+$
# Indien ingeschakeld, wordt de speler teruggestuurd naar de oorspronkelijke server
# nadat u de bot-verificatie met succes heeft doorstaan.
@@ -183,16 +184,18 @@ verification:
# Moet Sonar ook Geyser (Bedrock) spelers controleren?
# Deze functie is experimenteel en kan problemen veroorzaken
# Als dit is uitgeschakeld, worden Bedrock-spelers overgeslagen
check-geyser-players: true
check-geyser-players: false
# De hoeveelheid tijd die moet verstrijken voordat een speler een time-out krijgt
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
read-timeout: 8000
# De tijd sinds de speler stopte met het verzenden van pakketten voordat de verbinding werd verbroken
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
rejoin-delay: 5000
# De tijd sinds de server stopte met het versturen van pakketten voordat de verbinding met de speler werd verbroken
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
write-timeout: 10000
# Het maximale aantal pakketten dat de client in totaal mag verzenden (tijdens verificatie).
max-packets: 325
# De tijd sinds de speler stopte met het verzenden van pakketten voordat de verbinding werd verbroken
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
rejoin-delay: 5000
# Hoe lang moet Sonar het aantal mislukte verificaties voor een speler onthouden?
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
remember-time: 120000
@@ -43,7 +43,7 @@ attack-tracker:
# Uwaga: Adresy IP są zapisywane w postaci zwykłego tekstu. Jesteś odpowiedzialny za bezpieczeństwo swojej bazy danych!
database:
# Typ bazy danych używanej przez Sonar.
# Dostępne rodzaje: NONE, MYSQL, MARIADB, H2
# Dostępne rodzaje: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Plik w folderze pluginu używany dla bazy danych H2
filename: verified_players
@@ -109,6 +109,9 @@ verification:
# Jeśli obraz nie zostanie znaleziony, jako domyślne tło zostanie użyty szum
# Możesz umieścić nazwę pliku tutaj, jeśli plik znajduje się w katalogu pluginu
background: ''
# Styl mapy CAPTCHA (domyślnie: 'nowoczesny').
# Aby użyć starego projektu, ustaw to na 'legacy'.
style: 'modern'
# Ile możliwych odpowiedzi powinien przygotować Sonar?
# Zadanie to wykonywane jest asynchronicznie w tle
precompute: 500
@@ -132,8 +135,6 @@ verification:
# Regex do sprawdzania poprawności nazw użytkowników podczas weryfikacji
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex do sprawdzania ustawień regionalnych klienta podczas weryfikacji
valid-locale-regex: ^[a-zA-Z_]+$
# Jeśli opcja ta jest włączona, gracz zostanie przeniesiony z powrotem
# na serwer początkowy po pomyślnym przejściu weryfikacji antybotowej.
@@ -183,13 +184,15 @@ verification:
# Czy Sonar powinien również sprawdzać graczy Geyser (Bedrock)?
# Ta funkcja jest eksperymentalna i może powodować problemy
# Jeśli ta opcja jest wyłączona, gracze Bedrock będą pomijani
check-geyser-players: true
check-geyser-players: false
# Czas, jaki ma upłynąć od zatrzymania wysyłania pakietów przez gracza do wyrzucenia.
# (Wartość ta reprezentuje czas w milisekundach: 1 sekunda = 1000 milisekund)
read-timeout: 8000
# Czas, jaki ma upłynąć od zatrzymania wysyłania pakietów przez serwer do wyrzucenia.
# (Wartość ta reprezentuje czas w milisekundach: 1 sekunda = 1000 milisekund)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# Jak długo niezweryfikowany gracz powinien czekać przed ponownym połączeniem do serwera?
# (Wartość ta reprezentuje czas w milisekundach: 1 sekunda = 1000 milisekund)
rejoin-delay: 5000
@@ -42,7 +42,7 @@ attack-tracker:
# Nota: Endereços IP são salvos em texto simples. Você é responsável por manter seu banco de dados seguro!
database:
# Tipo de banco de dados que o Sonar usa para armazenar jogadores verificados
# Tipos possíveis: NONE, MYSQL, MARIADB, H2
# Tipos possíveis: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Arquivo no diretório de plugins do Sonar usado para o banco de dados H2
filename: verified_players
@@ -108,6 +108,9 @@ verification:
# Se a imagem não for encontrada, um ruído será usado como fundo padrão.
# Você pode colocar o nome do arquivo aqui se o arquivo estiver no diretório de plugins do Sonar
background: ''
# Estilo do CAPTCHA do mapa (Padrão: 'modern').
# Para usar o design antigo, defina-o como 'legacy'.
style: 'modern'
# Quantas respostas de CAPTCHA o Sonar deve preparar?
# Esta tarefa acontece de forma assíncrona em segundo plano
precompute: 500
@@ -132,8 +135,6 @@ verification:
# Regex para validar nomes de usuário durante a verificação
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex para validar o local do cliente durante a verificação
valid-locale-regex: ^[a-zA-Z_]+$
# Se habilitado, o jogador será transferido de volta para o servidor de origem
# após passar com sucesso pela verificação do bot.
@@ -183,13 +184,15 @@ verification:
# O Sonar também deve verificar jogadores Geyser (Bedrock)?
# Este recurso é experimental e pode causar problemas
# Se isso estiver desativado, jogadores Bedrock serão ignorados
check-geyser-players: true
check-geyser-players: false
# O tempo desde que o jogador parou de enviar pacotes antes de desconectar
# (Este valor representa o tempo em milissegundos: 1 segundo = 1000 milissegundos)
read-timeout: 8000
# O tempo desde que o servidor parou de enviar pacotes antes de desconectar o jogador
# (Este valor representa o tempo em milissegundos: 1 segundo = 1000 milissegundos)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# Quanto tempo um jogador deve esperar antes de se reconectar durante a verificação
# (Este valor representa o tempo em milissegundos: 1 segundo = 1000 milissegundos)
rejoin-delay: 5000
@@ -43,7 +43,7 @@ attack-tracker:
# Примечание: IP-адреса сохраняются в виде обычного текста. Вы сами отвечаете за сохранность своей базы данных!
database:
# Тип базы данных, которую Sonar использует для хранения проверенных игроков.
# Возможные типы: NONE, MYSQL, MARIADB, H2
# Возможные типы: NONE, MYSQL, MARIADB, POSTGRESQL, H2
type: NONE
# Файл в каталоге плагинов Sonar, используемый для базы данных H2
filename: verified_players
@@ -108,6 +108,9 @@ verification:
# Путь к фоновому изображению, которое использует Sonar для CAPTCHA
# Если изображение не найдено, будет использован шум как фон по умолчанию
background: ''
# Стиль капч (по умолчанию: 'modern').
# Чтобы использовать старый дизайн, установите значение 'legacy'.
style: 'modern'
# Сколько капч должен подготовить Sonar?
# Эта задача выполняется асинхронно в фоновом режиме
precompute: 500
@@ -131,8 +134,6 @@ verification:
# Regex для проверки ников при верификации
valid-name-regex: ^[a-zA-Z0-9_]+$
# Regex для проверки локализации клиента при верификации
valid-locale-regex: ^[a-zA-Z_]+$
# Если включено, игрок будет возвращен на исходный сервер
# после успешного прохождения проверки на бота.
@@ -182,13 +183,15 @@ verification:
# Следует ли Sonar также проверять игроков Geyser (Bedrock)?
# Эта функция экспериментальна и может вызывать проблемы
# Если это отключено, игроки Bedrock будут пропущены
check-geyser-players: true
check-geyser-players: false
# Время, прошедшее с момента прекращения отправки пакетов игроком до отключения.
# (Это значение представляет время в миллисекундах: 1 секунда = 1000 миллисекунд)
read-timeout: 8000
# Время, прошедшее с момента прекращения отправки сервером пакетов до отключения игрока
# (Это значение представляет время в миллисекундах: 1 секунда = 1000 миллисекунд)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# Сколько времени игрок должен ждать перед повторным подключением во время проверки
# (Это значение представляет время в миллисекундах: 1 секунда = 1000 миллисекунд)
rejoin-delay: 5000
@@ -108,6 +108,9 @@ verification:
# 如果未找到指定的图片, 则自动通过噪音生成一个随机的背景图片.
# 如果图片在该插件的配置文件夹下, 则可以简单地输入图片的文件名.
background: ''
# 地图验证码的风格(默认:'modern').
# 要使用旧设计, 请将其设置为 'legacy'.
style: 'modern'
# Sonar 应该一次准备多少个验证码?
precompute: 500
# Sonar 应该给玩家多少时间完成验证码?
@@ -130,8 +133,6 @@ verification:
# 用于检查用户名是否有效的正则表达式
valid-name-regex: ^[a-zA-Z0-9_]+$
# 用于检查客户端语言(例如 zh_CN)的正则表达式
valid-locale-regex: ^[a-zA-Z_]+$
# 开启后 玩家将在验证成功后被重定向到指定的服务器
# 该功能由 Mojang 在 Minecraft 1.20.5 版本中引入
@@ -179,13 +180,15 @@ verification:
# Sonar 是否应该检查来自 Geyser 的(基岩版)玩家?
# 此功能是实验性的. 请报告任何因为误判而导致无法通过检查的问题
# 如果关闭该选项 Sonar 将不检查这些玩家以便直接连接到服务器.
check-geyser-players: true
check-geyser-players: false
# 播放器断开连接前停止发送数据包的时间
# (该值为毫秒. 1秒等于1000毫秒.)
read-timeout: 8000
# 服务器在断开玩家连接前停止发送数据包的时间
# (该值为毫秒. 1秒等于1000毫秒.)
write-timeout: 10000
# The maximum number of packets the client is allowed to send in total (during verification).
max-packets: 325
# 当玩家在还未通过检查的情况下断开连接后需要等待多少毫秒才可以重新连接?
# (该值为毫秒. 1秒等于1000毫秒.)
rejoin-delay: 5000
@@ -196,7 +196,7 @@ verification:
# Zpráva zobrazená hráči, když má zadat odpověď na captchu
enter: '<prefix><green>Prosím, zadejte text do chatu, který se zobrazí na mapě.'
# Zpráva zobrazená hráči, když zadá špatnou odpověď do chatu
incorrect: '<prefix><red>Zadali jste špatnou odpověď! Zkuste to prosím znovu.'
incorrect: '<prefix><red>Zadali jste špatnou odpověď! Zbývají vám <attempts-left> pokus(y).'
# Zpráva zobrazená hráči při ověřování
# Nastavením této hodnoty na '' uvítací zprávu zcela vypnete
@@ -197,7 +197,7 @@ verification:
# Nachricht, die dem Spieler angezeigt wird, wenn er den CAPTCHA-Code im Chat eingeben muss
enter: '<prefix><green>Bitte gib den Text im Chat ein, der auf der Karte angezeigt wird.'
# Nachricht, die dem Spieler angezeigt wird, wenn er den falschen Code im Chat eingibt
incorrect: '<prefix><red>Du hast eine falsche Antwort eingegeben! Bitte versuche es erneut.'
incorrect: '<prefix><red>Du hast eine falsche Antwort eingegeben! Sie haben noch <attempts-left> Versuch(e) übrig.'
# Nachricht, die dem Spieler angezeigt wird, wenn er überprüft wird
# Setzen Sie dies auf '', um die Willkommensnachricht vollständig zu deaktivieren
@@ -196,7 +196,7 @@ verification:
# Message shown to the player when they have to enter the answer to the CAPTCHA
enter: '<prefix><green>Please enter the text in chat that is displayed on the map.'
# Message shown to the player when they enter the wrong answer in chat
incorrect: '<prefix><red>You have entered a wrong answer! Please try again.'
incorrect: '<prefix><red>You have entered a wrong answer! You have <attempts-left> attempt(s) left.'
# Message shown to the player when they are being verified
# Set this to '' to disable the welcome message entirely
@@ -196,7 +196,7 @@ verification:
# Message shown to the player when they have to enter the answer to the captcha
enter: '<prefix><green>Por favor, introduce en el chat el texto que se muestra en el mapa.'
# Message shown to the player when they enter the wrong answer in chat
incorrect: '<prefix><red>¡Has introducido una respuesta incorrecta! Por favor, inténtalo de nuevo.'
incorrect: '<prefix><red>¡Has introducido una respuesta incorrecta! Te quedan <attempts-left> intento(s).'
# Mensaje que se muestra al jugador cuando está siendo verificado
# Ajústalo a '' para desactivar por completo el mensaje de bienvenida
@@ -196,7 +196,7 @@ verification:
# Message affiché au joueur lorsqu'il doit entrer la réponse au CAPTCHA
enter: '<prefix><green>Veuillez saisir le texte en chat qui s''affiche sur la carte.'
# Message affiché au joueur lorsqu'il entre la mauvaise réponse dans le chat
incorrect: '<prefix><red>Vous avez saisi une mauvaise réponse ! Veuillez réessayer.'
incorrect: '<prefix><red>Vous avez saisi une mauvaise réponse ! Il vous reste <attempts-left> tentative(s).'
# Message affiché au joueur lorsqu'il est en cours de vérification
# Réglez ce paramètre sur '' pour désactiver complètement le message de bienvenue
@@ -196,7 +196,7 @@ verification:
# Pesan yang ditampilkan kepada pemain saat mereka harus memasukkan jawaban untuk CAPTCHA
enter: '<prefix><green>Masukkan teks dalam obrolan yang ditampilkan di peta.'
# Pesan yang ditampilkan kepada pemain saat mereka memasukkan jawaban yang salah di chat
incorrect: '<prefix><red>Anda telah memasukkan jawaban yang salah! Silakan coba lagi.'
incorrect: '<prefix><red>Anda telah memasukkan jawaban yang salah! Anda memiliki <attempts-left> percobaan yang tersisa.'
# Pesan yang ditampilkan kepada pemain ketika mereka sedang diverifikasi
# Atur ini ke '' untuk menonaktifkan pesan selamat datang sepenuhnya
@@ -61,9 +61,9 @@ commands:
tick: '<green>✔</green>'
cross: '<red>✗</red>'
# Formatting for the version information
outdated-version: ' <red><click:open_url:''https://github.com/jonesdevelopment/sonar/releases/latest''><hover:show_text:''(Click to download the latest version of Sonar)''>(Outdated)</hover></click></red>'
unstable-version: ' <gold>(Unstable)</gold>'
api-error: ' <dark_red><hover:show_text:''Check the server logs for more information''>(API error)</hover></dark_red>'
outdated-version: ' <red><click:open_url:''https://github.com/jonesdevelopment/sonar/releases/latest''><hover:show_text:''(დააჭირე, რომ გადმოწერო Sonar_ის უახლესი ვერსია)''>(Outdated)</hover></click></red>'
unstable-version: ' <gold>(არასტაბილური)</gold>'
api-error: ' <dark_red><hover:show_text:''შეამოწმე სერვერის Log_ები მეტი ინფორმაციისთვის''>(API error)</hover></dark_red>'
# თარგმანი '/sonar reload' სთვის
reload:
@@ -97,7 +97,7 @@ commands:
# აღწერა ამ ქვე-ბრძანებისთვის
description: "შეცვალე აკრძალული (დაბლოკილი) IP მისამართები"
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე ცდის შავი ნუსხის გასუფთავებას თუმცა იგი ცარიელია.
empty: '<prefix>შავი ნუსხა ამჟამად ცარიელია. ასე რომ არცერთი IP მისამართი არ მოშორებულა.'
empty: '<prefix>შავი ნუსხა ამჟამად ცარიელია. ასე რომ, არცერთი IP მისამართი არ მოშორებულა.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე გაასუფთავებს შავ ნუსხას.
clear: '<prefix>თქვენ წარმატებით გაასუფთავეთ <amount> IP მისამართ(ებ)ი შავი ნუსხიდან.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე შეამოწმებს შავი ნუსხის ზომას.
@@ -114,9 +114,9 @@ commands:
# თარგმანი '/sonar verified' სთვის
verified:
# აღწერა ამ ქვე-ბრძანებისთვის
description: "Manage verified IP მისამართები"
description: "განაგე შემოწმებული IP მისამართები"
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე ცდის გაასუფთავოს ნუსხა შემოწმებული მოთამაშეებისა თუმცა იგი ისედაც ცარიელია.
empty: '<prefix>ნუსხა შემოწმებული მოთამაშეებისა ისედაც ცარიელია. ასე რომ არ მოშორებულა არცერთი IP მისამართი იქიდან.'
empty: '<prefix>ნუსხა შემოწმებული მოთამაშეებისა ისედაც ცარიელია. ასე რომ, არ მოშორებულა არცერთი IP მისამართი იქიდან.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე გაასუფთავებს ნუსხას შემოწმებული მოთამაშეებისა.
clear: '<prefix>თქვენ წარმატებით გაასუფთავეთ <amount> მოთამაშე შემოწმებულების ნუსხიდან.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე შეამოწმებს სიდიდეს შემოწმებული მოთამაშეების ნუსხისა.
@@ -124,7 +124,7 @@ commands:
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე მოშლის IP მისამართს შემოწმებულების სიიდან.
remove: '<prefix>წარმატებით მოშორდა <ip>.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე დაამატებს IP მისამართს შემოწმებულების ნუსხაში.
add: '<prefix>Successfully verified <ip>.'
add: '<prefix>წარმატებით შემოწმდა <ip>.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე ცდის რომ დაამატოს IP/UUID შემოწმებულების ნუსხაში რაც უკვე დამატებულია.
already: '<prefix>IP მისამართი/UUID რაც მოგვაწოდეთ ისედაც დამატებულია.'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა ვინმე მოშლის IP მისამართს შემოწმებულების ნუსხიდან მაგრამ ის იქ არ არის.
@@ -136,7 +136,7 @@ commands:
# თარგმანი '/sonar statistics' სთვის
statistics:
# აღწერა ამ ქვე-ბრძანებისთვის
description: "აჩვენე სერვერის ამჟამინდელი სტატისტიკები"
description: "აჩვენე სერვერის ამჟამინდელი სტატისტიკა"
# ინფორმაციული მესიჯი რაც არის ნაჩვენები ყველაფრის ზემოთ როცა ნახულობთ სტატისტიკებს.
header: '<prefix>ვაჩვენებთ <statistics-type> სტატისტიკას:'
# მესიჯი, რომელიც იქნება ნაჩვენები, როცა მოთამაშე ცდის იხილოს უცნობი სტატისტიკა.
@@ -174,7 +174,7 @@ commands:
# თარგმანი '/sonar dump' სთვის
dump:
# აღწერა ამ ქვე-ბრძანებისთვის
description: "Print developer information"
description: "აჩვენებს დეველოპერის ინფორმაციას"
# ფორმატი ინფორმაციისთვის რაც კონსოლს ეგზავნება
log: "გენერირდა: <dumped-json-data>"
@@ -194,48 +194,48 @@ verification:
# მესიჯი რომელიც გაეგზავნება მოთამაშეს როცა მათ უნდა დაწერონ CAPTCHA
captcha:
# მესიჯი რომელიც გაეგზავნება მოთამაშეს როცა მათ უნდა მიუთითონ CAPTCHA ს პასუხი
enter: '<prefix><green>გთხოვთ დაწეროთ ჩატში ის კოდი რომელიც არის ნაჩვენები რუკაზე.'
enter: '<prefix><green>გთხოვთ დაწეროთ ჩატში კოდი, რომელიც არის ნაჩვენები რუკაზე.'
# მესიჯი რომელიც გაეგზავნება მოთამაშეს როცა ისინი ჩაწერენ არასწორ პასუხს ჩატში
incorrect: '<prefix><red>თქვენ მიუთითეთ არასწორი კოდი. გთხოვთ ხელახლა ცადოთ.'
incorrect: '<prefix><red>კოდი არასწორია. დაგრჩათ <attempts-left> მცდელობა(ები).'
# Message shown to the player when they are being verified
# Set this to '' to disable the welcome message entirely
welcome: '<prefix><green>You are being verified. Please do not move; this is an automatic process.'
welcome: '<prefix><green>მოწმდებით. გთხოვთ არ გაინძრეთ; ეს ავტომატური პროცესია.'
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე შემოვა მაგრამ CAPTCHA არ არის მზად
currently-preparing:
- <header>
- <yellow>ანტიბოტი ჯერ არ მომზადებულა.
- <gray>გთხოვთ დაიცადოთ რამოდენიმე წამი სანამ ხელახლა შემოხვალთ.
- <gray>გთხოვთ დაიცადოთ რამდენიმე წამი სანამ ხელახლა შემოხვალთ.
- <footer>
# Disconnect message that is shown when someone joins with an unsupported Minecraft version
unsupported-version:
- <header>
- <red>This server does not support your version of Minecraft.
- <red>თქვენი Minecraft_ის ვერსია არ არის მხარდაჭერილი.
- <footer>
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე ხელახლა შემოდის ძალიან სწრაფად შემოწმების დროს.
too-fast-reconnect:
- <header>
- <gold>თქვენ კავშირდებით ხელახლა ძალიან სწრაფად.
- <gray>გთხოვთ დაიცადოთ რამოდენიმე წამი სანამ ხელახლა ცდით შემოსვლას.
- <gray>გთხოვთ დაიცადოთ რამდენიმე წამი სანამ ხელახლა ცდით შემოსვლას.
- <footer>
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე ცდის შემოსვლას თუმცა იგი უკვე მოწმდება
already-verifying:
- <header>
- <red>თქვენი IP მისამართი ამჟამად უკვე მოწმდება.
- <red>გთხოვთ დაიცადოთ რამოდენიმე წამი სანამ ხელახლა ცდით შემოსვლას.
- <red>გთხოვთ დაიცადოთ რამდენიმე წამი სანამ ხელახლა ცდით შემოსვლას.
- <footer>
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე შემოვა თუმცა იგი უკვე არის შემოწმების რიგში
already-queued:
- <header>
- <red>თქვენი IP მისამართი უკვე არის რიგში შემოწმებისთვის.
- <red>გთხოვთ დაიცადოთ რამოდენიმე წუთი სანამ ხელახლა ცდით შემოსვლას.
- <red>გთხოვთ დაიცადოთ რამდენიმე წუთი სანამ ხელახლა ცდით შემოსვლას.
- <footer>
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე შემოვა თუმცა დროებით დაბლოკილია
blacklisted:
- <header>
- <red>თქვენ ამჟამად დაბლოკილი ხართ სერვერიდან.
- <red>გთხოვთ დაიცადოთ რამოდენიმე წუთი რომ ისევ შეგეძლოტ სერვერზე შემოსვლა.
- <red>გთხოვთ დაიცადოთ რამდენიმე წუთი, რომ ისევ შეგეძლოთ სერვერზე შემოსვლა.
- <gold>შეცდომა? <gray><support-url>
- <footer>
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე შემოვა არასწორი სახელით
@@ -253,12 +253,12 @@ verification:
success:
- <header>
- <green>თქვენ წარმატებით გაიარეთ შემოწმება.
- <white>თქვენ უკვე შეგიძლიათ შეხვიდეთ სერვერზე.
- <white>უკვე შეგიძლიათ შეხვიდეთ სერვერზე.
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე წარუმატებლად გაივლის შემოწმებას
failed:
- <header>
- <red>თქვენ ვერ გაიარეთ შემოწმება.
- <gray>გთხოვთ დაიცადოთ რამოდენიმე წამი სანამ ხელახლა ცდით შემოსვლას.
- <gray>გთხოვთ დაიცადოთ რამდენიმე წამი სანამ ხელახლა ცდით შემოსვლას.
- <gold>გჭირდებათ დახმარება შესვლაში? <gray><support-url>
- <footer>
@@ -266,9 +266,9 @@ verification:
verbose:
layout:
# ჩვენება Sonar_ის actionbar დეტალური ინფორმაციისთვის
normal: '<prefix><gray>კთწ <white><connections-per-second> <dark_aqua>╺ <gray>შემოსვლა/წ <white><logins-per-second> <dark_aqua>╺ <gray>მოწმდება <white><verifying> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
normal: '<prefix><gray>კ/წ <white><connections-per-second> <dark_aqua>╺ <gray>შემოსვლა/წ <white><logins-per-second> <dark_aqua>╺ <gray>მოწმდება <white><verifying> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
# Layout for Sonar's actionbar verbose during an attack
attack: '<prefix><gray>კთწ <white><connections-per-second> <dark_aqua>╺ <gray>შემოსვლა/წ <white><logins-per-second> <dark_aqua>╺ <gray>რიგი <white><queued> <dark_aqua>╺ <gray>მოწმდება <white><verifying> <dark_aqua>╺ <gray>ხანგრძლივობა <white><attack-duration> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
attack: '<prefix><gray>კ/წ <white><connections-per-second> <dark_aqua>╺ <gray>შემოსვლა/წ <white><logins-per-second> <dark_aqua>╺ <gray>რიგი <white><queued> <dark_aqua>╺ <gray>მოწმდება <white><verifying> <dark_aqua>╺ <gray>ხანგრძლივობა <white><attack-duration> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
# Animation for the action bar
# Alternatives:
# - ▙, ▛, ▜, ▟
@@ -196,7 +196,7 @@ verification:
# Bericht dat aan de speler wordt getoond wanneer hij het antwoord op de CAPTCHA moet invoeren
enter: '<prefix><green>Voer in de chat de tekst in die op de kaart wordt weergegeven.'
# Bericht dat aan de speler wordt getoond wanneer hij of zij het verkeerde antwoord invoert in de chat
incorrect: '<prefix><red>Je hebt een verkeerd antwoord ingevoerd! Probeer het opnieuw.'
incorrect: '<prefix><red>Je hebt een verkeerd antwoord ingevoerd! Je hebt <attempts-left> poging(en) over.'
# Bericht dat aan de speler wordt getoond als hij wordt geverifieerd
# Stel dit in op '' om het welkomstbericht volledig uit te schakelen
@@ -199,7 +199,7 @@ verification:
# Message shown to the player when they have to enter the answer to the captcha
enter: '<prefix><green>Wprowadź na czacie tekst wyświetlany na mapie.'
# Message shown to the player when they enter the wrong answer in chat
incorrect: '<prefix><red>Wprowadzono nieprawidłowy kod. Spróbuj ponownie.'
incorrect: '<prefix><red>Wprowadzono nieprawidłowy kod. Zostało <attempts-left> prób.'
# Wiadomość wyświetlana graczowi podczas weryfikacji
# Ustaw wartość '', aby całkowicie wyłączyć wiadomość powitalną
@@ -196,7 +196,7 @@ verification:
# Mensagem mostrada ao jogador quando ele deve inserir a resposta ao CAPTCHA
enter: '<prefix><green>Por favor, insira o texto no chat que é exibido no mapa.'
# Mensagem mostrada ao jogador quando ele insere a resposta errada no chat
incorrect: '<prefix><red>Você inseriu uma resposta errada! Por favor, tente novamente.'
incorrect: '<prefix><red>Você inseriu uma resposta errada! Você tem <attempts-left> tentativa(s) restante(s).'
# Mensagem mostrada ao jogador quando ele está sendo verificado
# Defina isso como '' para desativar a mensagem de boas-vindas completamente
@@ -196,7 +196,7 @@ verification:
# Сообщение, которое показывается игроку, когда он должен ввести ответ на капчу
enter: '<prefix><green>Пожалуйста, введите в чат текст, который будет отображаться на карте.'
# Сообщение, которое показывается игроку, когда он вводит неправильную капчу в чат
incorrect: '<prefix><red>Вы ввели неправильный ответ! Пожалуйста, попробуйте еще раз.'
incorrect: '<prefix><red>Вы ввели неверный код! У вас осталось <attempts-left> попыток.'
# Сообщение, показываемое игроку при прохождении верификации
# Установите значение '', чтобы полностью отключить приветственное сообщение
@@ -196,7 +196,7 @@ verification:
# CAPTCHA'nın cevabını girmeleri gerektiğinde oyuncuya gösterilen mesaj
enter: '<prefix><green>Lütfen haritada görüntülenen sohbet metnini girin.'
# Message that is shown to the player when they enter the wrong answer in chat
incorrect: '<prefix><red>Yanlış bir cevap girdiniz! Lütfen tekrar deneyin.'
incorrect: '<prefix><red>Yanlış bir cevap girdiniz! <attempts-left> deneme(ler)iniz kaldı.'
# Doğrulandıklarında oyuncuya gösterilen mesaj
# Karşılama mesajını tamamen devre dışı bırakmak için bunu '' olarak ayarlayın
@@ -196,7 +196,7 @@ verification:
# 玩家需要输入验证码答案时显示的消息
enter: '<prefix><green>请输入地图上显示的聊天文本.'
# 当玩家输入错误的验证码时显示的消息
incorrect: '<prefix><red>您输入了错误的答案! 请重试.'
incorrect: '<prefix><red>您输入了错误的答案! 您还剩 <attempts-left> 次尝试。'
# 当玩家正在接受验证时显示的信息
# 将此项设置为''可完全禁用加入时发送的消息
+1 -1
View File
@@ -1,3 +1,3 @@
group=xyz.jonesdev
version=2.1.24
version=2.1.41
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
+11 -11
View File
@@ -1,15 +1,15 @@
[versions]
netty = "4.1.117.Final"
adventure = "4.18.0"
adventure-platform = "4.3.4"
netty = "4.2.7.Final"
adventure = "4.24.0"
adventure-platform = "4.4.1"
bstats = "3.1.0"
libby = "2.0.0-SNAPSHOT"
pluginyml = "0.6.0"
[plugins]
indra-git = "net.kyori.indra.git:3.1.3"
shadow = "com.gradleup.shadow:8.3.6"
spotless = "com.diffplug.spotless:7.0.2"
indra-git = "net.kyori.indra.git:3.2.0"
shadow = "com.gradleup.shadow:8.3.8"
spotless = "com.diffplug.spotless:7.2.1"
pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" }
pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
@@ -28,12 +28,12 @@ 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.0"
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.2"
annotations = "org.jetbrains:annotations:26.0.2"
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.36"
lombok = "org.projectlombok:lombok:1.18.42"
bungeecord = "net.md-5:bungeecord-proxy:1.21-SNAPSHOT"
velocity = "com.velocitypowered:velocity-proxy:3.4.0-SNAPSHOT"
# We have to use 1.8.8 for backwards compatibility
spigot = "org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT"
velocity = "io.papermc.velocity:velocity-proxy:3.4.0-SNAPSHOT"
# We have to use 1.16.5 for backwards compatibility
spigot = "org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT"
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+3 -3
View File
@@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -205,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
Vendored
+2 -2
View File
@@ -70,11 +70,11 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell