Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a63a50f1cf
|
||
|
|
b34161bb49
|
||
|
|
3dbc108b8d | ||
|
|
781d30eb43 | ||
|
|
518e602bf3 | ||
|
|
d62f0440ad | ||
|
|
bf29fa5ca7 | ||
|
|
104691b816 | ||
|
|
097816760f | ||
|
|
5f1b040c99 | ||
|
|
911a655aaf | ||
|
|
82133e7ac7 | ||
|
|
d85f2bc2d5 | ||
|
|
877e3630b7 | ||
|
|
0c4495e502 | ||
|
|
8cb92bb074 | ||
|
|
89a07cd06e | ||
|
|
698a611511 | ||
|
|
0f598bb1da | ||
|
|
1a8c1caa39 | ||
|
|
c24fe4a4d9 | ||
|
|
2da0cc6761 | ||
|
|
80b7726f18 | ||
|
|
9bab457d58 | ||
|
|
37d294afe3 | ||
|
|
6ea9c1dcba | ||
|
|
1f98050abb | ||
|
|
cea1ac00f0 | ||
|
|
620aaa3ff2 | ||
|
|
381ad66339 | ||
|
|
de70d23c54 | ||
|
|
b49474a56f | ||
|
|
058f034245 | ||
|
|
d94333eed7 | ||
|
|
2550dc9fbf | ||
|
|
8be3d974e4 | ||
|
|
cab082cdd5 | ||
|
|
5a65dbcdb9 | ||
|
|
0ca1ecd421 | ||
|
|
c6ec0da14c | ||
|
|
76bcfc8b9a | ||
|
|
70506aaf64 | ||
|
|
873d9f8c10 | ||
|
|
8f40552dc5 | ||
|
|
6302888a33 | ||
|
|
ea7cc9a9f3 | ||
|
|
ea928ce6db | ||
|
|
d19ee78c41 | ||
|
|
924f4e7344 | ||
|
|
6e4c938767 | ||
|
|
e534738336 | ||
|
|
92d40ca4cf | ||
|
|
0fd7f0c173 | ||
|
|
f197260426 | ||
|
|
cbae477982 | ||
|
|
878789b2c1 | ||
|
|
2a98d4bdb0 | ||
|
|
790d233870 | ||
|
|
e732da6af2 | ||
|
|
e72e064dcc | ||
|
|
4dcafc9c91 | ||
|
|
7f2e910c2d | ||
|
|
b391ce38fb | ||
|
|
261f8e20e8 | ||
|
|
4c1c509bfa | ||
|
|
a5948bc494 | ||
|
|
de5750e4eb | ||
|
|
71b4bad41c | ||
|
|
05d2e55d69 | ||
|
|
41fe39cf0f | ||
|
|
fa2e68be20 | ||
|
|
2139147952 | ||
|
|
df049a7042 | ||
|
|
8df7874cab | ||
|
|
b132fe839e | ||
|
|
f0bdfa8ef1 | ||
|
|
7899569970 | ||
|
|
16d72fc682 | ||
|
|
425a902ec8 | ||
|
|
fcb52fc6c6 | ||
|
|
ac4d566627 | ||
|
|
0944701797 | ||
|
|
9464bffd8e | ||
|
|
9299edc839 | ||
|
|
41eb6d9767 | ||
|
|
4289b92ab6 | ||
|
|
b2dddfb0a4 | ||
|
|
ce2fca72f0 | ||
|
|
87da706508 | ||
|
|
3480bf9332 | ||
|
|
745d01b4d2 | ||
|
|
4f0d70650b | ||
|
|
2ad0ce11c0 | ||
|
|
fd1e5c9d72 | ||
|
|
e036ce421d | ||
|
|
cf2628a41f | ||
|
|
fcea8e5f11 | ||
|
|
ad5de38b1d | ||
|
|
bc0661c10c | ||
|
|
5e233b4f73 | ||
|
|
e7f816fcaa | ||
|
|
d87b775b76 |
No files matched your search
@@ -22,3 +22,4 @@
|
||||
|
||||
# Common build-tool wrapper scripts ('.cmd' versions are handled by 'Common.gitattributes')
|
||||
gradlew text eol=lf
|
||||
.gitea/CODEOWNERS linguist-detectable=false
|
||||
@@ -0,0 +1,3 @@
|
||||
# Pull requests request review from the eligible staff team(s).
|
||||
# One approval from either an Admin or Developer satisfies branch protection.
|
||||
* @trueog/Admins @trueog/Developers
|
||||
+13
-2
@@ -1,11 +1,11 @@
|
||||
Before you start contributing, please take a moment to review our contributing guidelines.
|
||||
If you can't contribute but like the project, feel free to show your support by starring the project on GitHub or
|
||||
joining the [Discord](https://jonesdev.xyz/discord).
|
||||
joining the [Discord](https://sonar.top/discord).
|
||||
|
||||
## Contributing Guidelines:
|
||||
|
||||
1. Fork the repository and create a new branch for your contribution.
|
||||
2. Follow the coding guidelines for your code.
|
||||
2. Adhere to the Coding Guidelines and LLM Guidelines.
|
||||
3. Test your code before committing and pushing it.
|
||||
4. Use [semantic](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) commit messages for your commits.
|
||||
|
||||
@@ -17,6 +17,17 @@ joining the [Discord](https://jonesdev.xyz/discord).
|
||||
- Write clear comments to explain complex parts of your code.
|
||||
- Ensure your code is easy to read and maintain.
|
||||
|
||||
## LLM Guidelines
|
||||
|
||||
Keep the use of AI (including LLMs) for code generation to an absolute minimum. If possible, avoid using AI entirely due to potential complications regarding authorship, intellectual property, and copyright.
|
||||
|
||||
If AI was utilized during the development of a Pull Request, you must disclose its exact use in the PR description. This includes:
|
||||
- The specific tool and model used (e.g., GPT 5.4, Claude 4.7 Sonnet, Gemini 3.1 Pro)
|
||||
- The nature of its use (e.g., optimization)
|
||||
- The exact prompts used, where relevant
|
||||
|
||||
Please note that submissions will be rejected if AI usage raises concerns regarding code quality, licensing, or integrity.
|
||||
|
||||
## Bug Reports:
|
||||
|
||||
1. Check if someone has already reported the bug.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
patreon: jonesdev
|
||||
@@ -4,5 +4,5 @@ contact_links:
|
||||
url: https://docs.jonesdev.xyz/
|
||||
about: Need help configuring Sonar or have questions regarding the installation and usage?
|
||||
- name: Discord
|
||||
url: https://jonesdev.xyz/discord/
|
||||
url: https://sonar.top/discord/
|
||||
about: If you have any further questions, please feel free to join the Discord server and open a ticket.
|
||||
+13
-6
@@ -11,7 +11,7 @@
|
||||
[](https://www.codefactor.io/repository/github/jonesdevelopment/sonar/overview/main)
|
||||
[](https://github.com/jonesdevelopment/sonar/releases)
|
||||
[](https://github.com/jonesdevelopment/sonar/issues)
|
||||
[](https://jonesdev.xyz/discord)
|
||||
[](https://sonar.top/discord)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
<br>
|
||||
<!-- Quick navigation -->
|
||||
@@ -21,11 +21,18 @@
|
||||
|
|
||||
[Pull Requests](https://github.com/jonesdevelopment/sonar/pulls)
|
||||
|
|
||||
[Discord](https://jonesdev.xyz/discord)
|
||||
[Discord](https://sonar.top/discord)
|
||||
|
|
||||
[License](https://github.com/jonesdevelopment/sonar/?tab=readme-ov-file#license)
|
||||
|
|
||||
[Documentation](https://docs.jonesdev.xyz/)
|
||||
</div>
|
||||
|
||||
> ### Notice about Sonar 3.0
|
||||
>
|
||||
> If you want more robust protection, better performance, and awesome new features, check out Sonar 3.0 at https://sonar.top/!
|
||||
> You can read more about what sets Sonar 3.0 apart from Sonar 2.0 [here](<https://sonar.top/docs/features>).
|
||||
|
||||
## Design and Goal
|
||||
* Effective, lightweight, and easy-to-use
|
||||
* No unnecessary features and clean code
|
||||
@@ -46,15 +53,15 @@ Sonar also protects against spambot attacks since it queues the incoming connect
|
||||
|
||||
### False positives
|
||||
Sonar is unlikely to ever falsely prevent a player from joining the server since Minecraft uses the TCP protocol, which means that packets are always sent in the correct order. Therefore, lag or ping should not affect the bot check.
|
||||
If you or one of your players experiences a false positive, make sure to report it by opening a [GitHub issue](https://github.com/jonesdevelopment/sonar/issues/new/choose) or a ticket on the [Discord server](https://jonesdev.xyz/discord/).
|
||||
If you or one of your players experiences a false positive, make sure to report it by opening a [GitHub issue](https://github.com/jonesdevelopment/sonar/issues/new/choose) or a ticket on the [Discord server](https://sonar.top/discord/).
|
||||
|
||||
## Sponsors
|
||||
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>
|
||||
If you are interested in sponsoring this project, please contact me via [Discord](https://sonar.top/discord/).
|
||||
|
||||
### Past Sponsors
|
||||
|
||||
<a href="https://github.com/Chumb3x"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/79834154?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
|
||||
<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>
|
||||
<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
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ If you discover a security vulnerability within Sonar, please follow these steps
|
||||
|
||||
## Contact
|
||||
|
||||
If you have any questions or concerns regarding the security of this project, please open a ticket on Discord or contact me via email at contact@jonesdev.xyz.
|
||||
If you have any questions or concerns regarding the security of this project, please open a ticket on Discord or contact me via email at support@sonar.top.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
@@ -42,6 +42,13 @@ jobs:
|
||||
path: bukkit/build/libs/Sonar-Bukkit.jar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Paper Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Sonar-Paper
|
||||
path: paper/build/libs/Sonar-Paper.jar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload BungeeCord Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
* Copyright (C) 2026 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -21,11 +21,11 @@ import net.kyori.adventure.audience.Audience;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.antibot.AntiBot;
|
||||
import xyz.jonesdev.sonar.api.command.subcommand.SubcommandRegistry;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.api.database.controller.VerifiedPlayerController;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEventManager;
|
||||
import xyz.jonesdev.sonar.api.fallback.Fallback;
|
||||
import xyz.jonesdev.sonar.api.logger.LoggerWrapper;
|
||||
import xyz.jonesdev.sonar.api.notification.ActionBarNotificationHandler;
|
||||
import xyz.jonesdev.sonar.api.notification.ChatNotificationHandler;
|
||||
@@ -152,12 +152,12 @@ public interface Sonar {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the anti-bot handler (called "Fallback") for Sonar.
|
||||
* Gets the anti-bot handler for Sonar.
|
||||
*
|
||||
* @return The {@link Fallback} instance.
|
||||
* @return The {@link AntiBot} instance.
|
||||
*/
|
||||
@NotNull default Fallback getFallback() {
|
||||
return Fallback.INSTANCE;
|
||||
@NotNull default AntiBot getAntiBot() {
|
||||
return AntiBot.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,8 @@ public enum SonarPlatform {
|
||||
pipeline -> pipeline.context("outbound_config") != null ? "outbound_config" : "encoder"),
|
||||
BUNGEE("BungeeCord", 19109, "inbound-boss",
|
||||
pipeline -> "packet-encoder"),
|
||||
PAPER("Paper", 19110, "packet_handler",
|
||||
pipeline -> pipeline.context("outbound_config") != null ? "outbound_config" : "encoder"),
|
||||
VELOCITY("Velocity", 19107, "handler",
|
||||
pipeline -> "minecraft-encoder");
|
||||
|
||||
|
||||
+7
-7
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.fallback;
|
||||
package xyz.jonesdev.sonar.api.antibot;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import lombok.AccessLevel;
|
||||
@@ -23,9 +23,9 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.antibot.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.api.antibot.ratelimit.Ratelimiter;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.api.fallback.ratelimit.Ratelimiter;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -33,12 +33,12 @@ import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class Fallback {
|
||||
public static final Fallback INSTANCE = new Fallback();
|
||||
public final class AntiBot {
|
||||
public static final AntiBot INSTANCE = new AntiBot();
|
||||
|
||||
private final ConcurrentMap<InetAddress, Integer> online = new ConcurrentHashMap<>(128);
|
||||
private final ConcurrentMap<InetAddress, Boolean> connected = new ConcurrentHashMap<>(256);
|
||||
private final FallbackLoginQueue queue = new FallbackLoginQueue();
|
||||
private final LoginQueue queue = new LoginQueue();
|
||||
@Setter
|
||||
private Cache<String, Integer> blacklist;
|
||||
@Setter
|
||||
@@ -56,7 +56,7 @@ public final class Fallback {
|
||||
return shouldPerform(Sonar.get0().getConfig().getVerification().getMap().getTiming());
|
||||
}
|
||||
|
||||
private static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) {
|
||||
public static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) {
|
||||
return timing == SonarConfiguration.Verification.Timing.ALWAYS
|
||||
|| (timing == SonarConfiguration.Verification.Timing.DURING_ATTACK
|
||||
&& Sonar.get0().getAttackTracker().getCurrentAttack() != null);
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.api.antibot;
|
||||
|
||||
public interface ChannelPipelines {
|
||||
String SONAR_INACTIVE_LISTENER = "sonar-inactive-listener";
|
||||
String SONAR_INBOUND_HANDLER = "sonar-inbound-handler";
|
||||
String SONAR_FRAME_DECODER = "sonar-frame-decoder";
|
||||
String SONAR_FRAME_ENCODER = "sonar-frame-encoder";
|
||||
String SONAR_TIMEOUT = "sonar-timeout";
|
||||
String SONAR_PACKET_HANDLER = "sonar-packet-handler";
|
||||
String SONAR_PACKET_ENCODER = "sonar-packet-encoder";
|
||||
String SONAR_PACKET_DECODER = "sonar-packet-decoder";
|
||||
String SONAR_TAIL_EXCEPTIONS = "sonar-exception-tail";
|
||||
String SONAR_BANDWIDTH = "sonar-bandwidth-counter";
|
||||
}
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.fallback;
|
||||
package xyz.jonesdev.sonar.api.antibot;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
@@ -30,7 +30,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public final class FallbackLoginQueue {
|
||||
public final class LoginQueue {
|
||||
// Fixed thread pool executor for all new verifications
|
||||
private static final int THREAD_POOL_SIZE = Math.min(0x7fff, Runtime.getRuntime().availableProcessors() * 2);
|
||||
private static final ExecutorService QUEUE_EXECUTOR = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
|
||||
+7
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
* Copyright (C) 2026 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -15,18 +15,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.fallback;
|
||||
package xyz.jonesdev.sonar.api.antibot;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public interface FallbackUser {
|
||||
public interface SonarUser {
|
||||
@NotNull Channel channel();
|
||||
|
||||
@NotNull InetAddress getInetAddress();
|
||||
@@ -45,6 +46,8 @@ public interface FallbackUser {
|
||||
|
||||
boolean isGeyser();
|
||||
|
||||
@Nullable String getHostname();
|
||||
|
||||
/**
|
||||
* Disconnect the player during/after verification
|
||||
* using our custom Disconnect packet.
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.fallback.captcha;
|
||||
package xyz.jonesdev.sonar.api.antibot.captcha;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
+5
-2
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.api.antibot.protocol;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -73,7 +73,10 @@ public enum ProtocolVersion {
|
||||
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_7(772, "1.21.7"),
|
||||
MINECRAFT_1_21_9(773, "1.21.9"),
|
||||
MINECRAFT_1_21_11(774, "1.21.11"),
|
||||
MINECRAFT_26_1(775, "26.1");
|
||||
|
||||
private final int protocol;
|
||||
private final String name;
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.fallback.ratelimit;
|
||||
package xyz.jonesdev.sonar.api.antibot.ratelimit;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -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);
|
||||
@@ -166,12 +167,12 @@ public final class SonarConfiguration {
|
||||
Sonar.get0().getLogger().warn(" ");
|
||||
}
|
||||
|
||||
verification.gravity.enabled = generalConfig.getBoolean("verification.checks.gravity.enabled");
|
||||
verification.gravity.checkCollisions = generalConfig.getBoolean("verification.checks.collision.enabled");
|
||||
verification.gravity.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.gravity.timing"));
|
||||
verification.gravity.collisionTiming = Verification.Timing.valueOf(generalConfig.getString("verification.checks.collision.timing"));
|
||||
verification.gravity.captchaOnFail = generalConfig.getBoolean("verification.checks.gravity.captcha-on-fail");
|
||||
verification.gravity.maxMovementTicks = clamp(generalConfig.getInt("verification.checks.gravity.max-movement-ticks"), 2, 100);
|
||||
|
||||
verification.vehicle.enabled = generalConfig.getBoolean("verification.checks.vehicle.enabled");
|
||||
verification.vehicle.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.vehicle.timing"));
|
||||
verification.vehicle.minimumPackets = clamp(generalConfig.getInt("verification.checks.vehicle.minimum-packets"), 0, 20);
|
||||
|
||||
verification.map.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.map-captcha.timing"));
|
||||
@@ -180,6 +181,7 @@ public final class SonarConfiguration {
|
||||
verification.map.maxTries = clamp(generalConfig.getInt("verification.checks.map-captcha.max-tries"), 1, 100);
|
||||
verification.map.alphabet = generalConfig.getString("verification.checks.map-captcha.alphabet");
|
||||
verification.map.backgroundImage = null;
|
||||
verification.map.placeInOffhand = generalConfig.getBoolean("verification.checks.map-captcha.place-in-offhand");
|
||||
|
||||
final String backgroundPath = generalConfig.getString("verification.checks.map-captcha.background");
|
||||
if (!backgroundPath.isEmpty()) {
|
||||
@@ -200,11 +202,13 @@ public final class SonarConfiguration {
|
||||
verification.validNameRegex = Pattern.compile(generalConfig.getString("verification.checks.valid-name-regex"));
|
||||
|
||||
verification.checkGeyser = generalConfig.getBoolean("verification.check-geyser-players");
|
||||
verification.checkEagler = generalConfig.getBoolean("verification.check-eagler-players");
|
||||
verification.logConnections = generalConfig.getBoolean("verification.log-connections");
|
||||
verification.logDuringAttack = generalConfig.getBoolean("verification.log-during-attack");
|
||||
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);
|
||||
@@ -249,7 +253,12 @@ public final class SonarConfiguration {
|
||||
|
||||
SonarCommand.prepareCachedTabSuggestions();
|
||||
|
||||
supportUrl = messagesConfig.getString("support-url");
|
||||
supportUrl = messagesConfig.getString("support-url")
|
||||
.replace("jonesdev.xyz", "sonar.top") // Migration: Replace legacy URL
|
||||
.trim();
|
||||
if (supportUrl.contains("://sonar.top/")) {
|
||||
Sonar.get0().getLogger().warn("Consider entering a custom support URL (if applicable).");
|
||||
}
|
||||
header = MiniMessage.miniMessage().deserialize(
|
||||
String.join("<newline>", messagesConfig.getStringList("header")),
|
||||
Placeholder.unparsed("support-url", supportUrl),
|
||||
@@ -371,19 +380,20 @@ public final class SonarConfiguration {
|
||||
private int maxTries;
|
||||
private String alphabet;
|
||||
private File backgroundImage;
|
||||
private boolean placeInOffhand;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static final class Gravity {
|
||||
private boolean enabled;
|
||||
private boolean checkCollisions;
|
||||
private Timing timing;
|
||||
private Timing collisionTiming;
|
||||
private boolean captchaOnFail;
|
||||
private int maxMovementTicks;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static final class Vehicle {
|
||||
private boolean enabled;
|
||||
private Timing timing;
|
||||
private int minimumPackets;
|
||||
}
|
||||
|
||||
@@ -413,6 +423,7 @@ public final class SonarConfiguration {
|
||||
|
||||
private int timeOfDay;
|
||||
private boolean checkGeyser;
|
||||
private boolean checkEagler;
|
||||
private boolean logConnections;
|
||||
private boolean logDuringAttack;
|
||||
private boolean debugXYZPositions;
|
||||
@@ -420,6 +431,7 @@ public final class SonarConfiguration {
|
||||
|
||||
private int readTimeout;
|
||||
private int writeTimeout;
|
||||
private int maxPacketCount;
|
||||
private int reconnectDelay;
|
||||
private int rememberTime;
|
||||
private int blacklistTime;
|
||||
@@ -466,6 +478,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;
|
||||
|
||||
+6
-4
@@ -21,6 +21,7 @@ import com.alessiodp.libby.LibraryManager;
|
||||
import com.j256.ormlite.dao.Dao;
|
||||
import com.j256.ormlite.dao.DaoManager;
|
||||
import com.j256.ormlite.jdbc.JdbcConnectionSource;
|
||||
import com.j256.ormlite.jdbc.JdbcPooledConnectionSource;
|
||||
import com.j256.ormlite.stmt.QueryBuilder;
|
||||
import com.j256.ormlite.support.ConnectionSource;
|
||||
import com.j256.ormlite.table.TableUtils;
|
||||
@@ -93,10 +94,11 @@ public final class VerifiedPlayerController {
|
||||
"?autoReconnect=true");
|
||||
}
|
||||
|
||||
connectionSource = new JdbcConnectionSource(jdbcURL,
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.username"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.password"),
|
||||
cachedDatabaseType.getDatabaseType());
|
||||
final String user = Sonar.get0().getConfig().getGeneralConfig().getString("database.username");
|
||||
final String pass = Sonar.get0().getConfig().getGeneralConfig().getString("database.password");
|
||||
connectionSource = cachedDatabaseType == SonarConfiguration.Database.Type.H2
|
||||
? new JdbcConnectionSource(jdbcURL, user, pass, cachedDatabaseType.getDatabaseType())
|
||||
: new JdbcPooledConnectionSource(jdbcURL, user, pass, cachedDatabaseType.getDatabaseType());
|
||||
|
||||
try {
|
||||
TableUtils.createTableIfNotExists(connectionSource, VerifiedPlayer.class);
|
||||
|
||||
+14
@@ -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"};
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -20,8 +20,8 @@ package xyz.jonesdev.sonar.api.event.impl;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import xyz.jonesdev.sonar.api.antibot.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.captcha.CaptchaGenerator;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
||||
@@ -20,12 +20,12 @@ package xyz.jonesdev.sonar.api.event.impl;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.antibot.SonarUser;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserBlacklistedEvent implements SonarEvent {
|
||||
private final FallbackUser user;
|
||||
private final SonarUser user;
|
||||
}
|
||||
@@ -21,13 +21,13 @@ import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.antibot.SonarUser;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserVerifyFailedEvent implements SonarEvent {
|
||||
private final @NotNull FallbackUser user;
|
||||
private final @NotNull SonarUser user;
|
||||
private final @NotNull String reason;
|
||||
}
|
||||
@@ -20,12 +20,12 @@ package xyz.jonesdev.sonar.api.event.impl;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.antibot.SonarUser;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserVerifyJoinEvent implements SonarEvent {
|
||||
private final FallbackUser user;
|
||||
private final SonarUser user;
|
||||
}
|
||||
@@ -20,12 +20,12 @@ package xyz.jonesdev.sonar.api.event.impl;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.antibot.SonarUser;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserVerifySuccessEvent implements SonarEvent {
|
||||
private final FallbackUser user;
|
||||
private final SonarUser user;
|
||||
}
|
||||
+3
-3
@@ -56,9 +56,9 @@ public class ActionBarNotificationHandler extends NotificationHandler {
|
||||
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())),
|
||||
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get0().getAntiBot().getQueue().getPlayers().size())),
|
||||
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get0().getAntiBot().getConnected().size())),
|
||||
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get0().getAntiBot().getBlacklist().estimatedSize())),
|
||||
Placeholder.unparsed("total-joins", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalPlayersJoined())),
|
||||
Placeholder.unparsed("logins-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getLoginsPerSecond())),
|
||||
Placeholder.unparsed("connections-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getConnectionsPerSecond())),
|
||||
|
||||
@@ -54,9 +54,9 @@ public final class ChatNotificationHandler extends NotificationHandler {
|
||||
for (int i = 0; i < chatNotificationComponents.length; i++) {
|
||||
chatNotificationComponents[i] = MiniMessage.miniMessage().deserialize(chatNotification.get(i),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
|
||||
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())),
|
||||
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get0().getAntiBot().getQueue().getPlayers().size())),
|
||||
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get0().getAntiBot().getConnected().size())),
|
||||
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get0().getAntiBot().getBlacklist().estimatedSize())),
|
||||
Placeholder.unparsed("total-joins", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalPlayersJoined())),
|
||||
Placeholder.unparsed("logins-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getLoginsPerSecond())),
|
||||
Placeholder.unparsed("connections-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getConnectionsPerSecond())),
|
||||
|
||||
@@ -53,8 +53,8 @@ public final class AttackTracker {
|
||||
|
||||
public void checkIfUnderAttack() {
|
||||
final long joinsPerSecond = Sonar.get0().getStatistics().getLoginsPerSecond();
|
||||
final int verifyingPlayers = Sonar.get0().getFallback().getConnected().size();
|
||||
final int queuedPlayers = Sonar.get0().getFallback().getQueue().getPlayers().size();
|
||||
final int verifyingPlayers = Sonar.get0().getAntiBot().getConnected().size();
|
||||
final int queuedPlayers = Sonar.get0().getAntiBot().getQueue().getPlayers().size();
|
||||
final int minPlayers = Sonar.get0().getConfig().getMinPlayersForAttack();
|
||||
|
||||
if (joinsPerSecond > minPlayers // Check the number of bots/joins per second.
|
||||
@@ -116,7 +116,7 @@ public final class AttackTracker {
|
||||
final String formattedDuration = String.format("%d minutes, %.0f seconds", minutes, seconds);
|
||||
final String startTimestamp = String.valueOf(currentAttack.duration.getStart() / 1000L);
|
||||
final String endTimestamp = String.valueOf(System.currentTimeMillis() / 1000L);
|
||||
final long blacklisted = Sonar.get0().getFallback().getBlacklist().estimatedSize();
|
||||
final long blacklisted = Sonar.get0().getAntiBot().getBlacklist().estimatedSize();
|
||||
// Calculate during-attack-statistics using their deltas
|
||||
final long totalVerified = Sonar.get0().getVerifiedPlayerController().getCache().size();
|
||||
final long verified = Math.max(totalVerified - currentAttack.successfulVerifications, 0);
|
||||
|
||||
@@ -64,7 +64,8 @@ public class UpdateChecker {
|
||||
lastCheckResult = CheckResult.LATEST_VERSION;
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get0().getLogger().warn("Unable to retrieve version information: {}", throwable);
|
||||
Sonar.get0().getLogger().warn("Failed to check for updates (is your firewall set up properly?): {}",
|
||||
throwable);
|
||||
lastCheckResult = CheckResult.API_ERROR;
|
||||
}
|
||||
});
|
||||
|
||||
+3
-2
@@ -11,7 +11,7 @@ allprojects {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven(url = "https://repo.jonesdev.xyz/releases/") // Bungee & Velocity proxy module
|
||||
maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") // libby
|
||||
maven(url = "https://repo.alessiodp.com/snapshots/") // libby
|
||||
}
|
||||
|
||||
apply(plugin = "java")
|
||||
@@ -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/*/**")
|
||||
@@ -101,7 +102,7 @@ allprojects {
|
||||
tasks {
|
||||
// This is a small wrapper tasks to simplify the building process
|
||||
register("build-sonar") {
|
||||
val subprojects = listOf("api", "captcha", "common", "bukkit", "bungeecord", "velocity")
|
||||
val subprojects = listOf("api", "captcha", "common", "bukkit", "bungeecord", "paper", "velocity")
|
||||
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:spotlessApply", "$it:shadowJar") }
|
||||
dependsOn(buildTasks)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ bukkit {
|
||||
name = rootProject.name
|
||||
main = "xyz.jonesdev.sonar.bukkit.SonarBukkitPlugin"
|
||||
authors = listOf("Jones Development", "Sonar Contributors")
|
||||
website = "https://jonesdev.xyz/discord/"
|
||||
website = "https://sonar.top/discord/"
|
||||
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
|
||||
softDepend = listOf("Geyser-Spigot", "floodgate", "Protocolize", "ProtocolSupport",
|
||||
"ViaVersion", "packetevents", "ProtocolLib", "FastLogin")
|
||||
@@ -32,7 +32,6 @@ dependencies {
|
||||
implementation(project(":common"))
|
||||
|
||||
compileOnly(rootProject.libs.spigot)
|
||||
testCompileOnly(rootProject.libs.spigot)
|
||||
|
||||
implementation(rootProject.libs.adventure.platform.bukkit) {
|
||||
exclude(module = "adventure-nbt")
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.SonarPlatform;
|
||||
import xyz.jonesdev.sonar.api.logger.LoggerWrapper;
|
||||
import xyz.jonesdev.sonar.bukkit.antibot.BukkitInjector;
|
||||
import xyz.jonesdev.sonar.bukkit.command.BukkitSonarCommand;
|
||||
import xyz.jonesdev.sonar.bukkit.fallback.FallbackBukkitInjector;
|
||||
import xyz.jonesdev.sonar.bukkit.listener.BukkitJoinListener;
|
||||
import xyz.jonesdev.sonar.common.boot.SonarBootstrap;
|
||||
|
||||
@@ -108,8 +108,8 @@ public final class SonarBukkit extends SonarBootstrap<SonarBukkitPlugin> {
|
||||
Objects.requireNonNull(getPlugin().getCommand("sonar")).setExecutor(new BukkitSonarCommand());
|
||||
|
||||
// Try to inject into the server
|
||||
if (FallbackBukkitInjector.isLateBindEnabled()) {
|
||||
getPlugin().getServer().getScheduler().runTask(getPlugin(), FallbackBukkitInjector::inject);
|
||||
if (BukkitInjector.isLateBindEnabled()) {
|
||||
getPlugin().getServer().getScheduler().runTask(getPlugin(), BukkitInjector::inject);
|
||||
} else {
|
||||
getPlugin().getServer().getPluginManager().registerEvents(new BukkitJoinListener(), getPlugin());
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package xyz.jonesdev.sonar.bukkit;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import xyz.jonesdev.sonar.bukkit.fallback.FallbackBukkitInjector;
|
||||
import xyz.jonesdev.sonar.bukkit.antibot.BukkitInjector;
|
||||
|
||||
public final class SonarBukkitPlugin extends JavaPlugin {
|
||||
private SonarBukkit bootstrap;
|
||||
@@ -26,8 +26,8 @@ public final class SonarBukkitPlugin extends JavaPlugin {
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Inject early if late-bind is disabled
|
||||
if (!FallbackBukkitInjector.isLateBindEnabled()) {
|
||||
FallbackBukkitInjector.inject();
|
||||
if (!BukkitInjector.isLateBindEnabled()) {
|
||||
BukkitInjector.inject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-19
@@ -15,35 +15,35 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.bukkit.fallback;
|
||||
package xyz.jonesdev.sonar.bukkit.antibot;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.FallbackInboundHandlerAdapter;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake.HandshakePacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginStartPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.InboundHandlerAdapter;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.handshake.HandshakePacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.login.LoginStartPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Objects;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_INBOUND_HANDLER;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake.HandshakePacket.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.SONAR_INBOUND_HANDLER;
|
||||
import static xyz.jonesdev.sonar.common.protocol.packets.handshake.HandshakePacket.*;
|
||||
|
||||
final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
final class BukkitInboundHandler extends InboundHandlerAdapter {
|
||||
private static final ProtocolVersion DEFAULT_PROTOCOL_VERSION = ProtocolVersion.MINECRAFT_1_7_2;
|
||||
|
||||
private FallbackPacketRegistry.ProtocolRegistry registry;
|
||||
private SonarPacketRegistry.ProtocolRegistry registry;
|
||||
|
||||
FallbackBukkitInboundHandler() {
|
||||
updateRegistry(FallbackPacketRegistry.HANDSHAKE, DEFAULT_PROTOCOL_VERSION);
|
||||
BukkitInboundHandler() {
|
||||
updateRegistry(SonarPacketRegistry.HANDSHAKE, DEFAULT_PROTOCOL_VERSION);
|
||||
|
||||
super.channelRemovalListener = (pipeline, name, handler) -> {
|
||||
final ChannelInactiveListener inactiveListener = pipeline.get(ChannelInactiveListener.class);
|
||||
@@ -54,9 +54,9 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
};
|
||||
}
|
||||
|
||||
public void updateRegistry(final @NotNull FallbackPacketRegistry registry,
|
||||
public void updateRegistry(final @NotNull SonarPacketRegistry registry,
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
this.registry = registry.getProtocolRegistry(FallbackPacketRegistry.Direction.SERVERBOUND, protocolVersion);
|
||||
this.registry = registry.getProtocolRegistry(SonarPacketRegistry.Direction.SERVERBOUND, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +79,7 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
final int packetId = ProtocolUtil.readVarInt(byteBuf);
|
||||
final FallbackPacket packet = registry.createPacket(packetId);
|
||||
final SonarPacket packet = registry.createPacket(packetId);
|
||||
|
||||
// Skip the packet if it's not registered within Sonar's packet registry
|
||||
if (packet == null) {
|
||||
@@ -119,7 +119,7 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
// Let the actual handler know about the handshake packet
|
||||
handleHandshake(ctx, handshake.getHostname(), handshake.getProtocolVersionId());
|
||||
// Be ready for the next packet (which is supposed to be a login packet)
|
||||
updateRegistry(FallbackPacketRegistry.LOGIN, Objects.requireNonNull(protocolVersion));
|
||||
updateRegistry(SonarPacketRegistry.LOGIN, Objects.requireNonNull(protocolVersion));
|
||||
break;
|
||||
default:
|
||||
byteBuf.release();
|
||||
@@ -136,9 +136,9 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
byteBuf.readerIndex(originalReaderIndex);
|
||||
ctx.fireChannelRead(byteBuf.retain());
|
||||
// TODO: recode this?
|
||||
final ChannelHandler inboundHandler = ctx.pipeline().remove(FALLBACK_INBOUND_HANDLER);
|
||||
final ChannelHandler inboundHandler = ctx.pipeline().remove(SONAR_INBOUND_HANDLER);
|
||||
if (inboundHandler != null && channelRemovalListener != null) {
|
||||
channelRemovalListener.accept(ctx.pipeline(), FALLBACK_INBOUND_HANDLER, inboundHandler);
|
||||
channelRemovalListener.accept(ctx.pipeline(), SONAR_INBOUND_HANDLER, inboundHandler);
|
||||
}
|
||||
}, loginStart.getUsername(), socketAddress);
|
||||
byteBuf.release();
|
||||
+8
-8
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.bukkit.fallback;
|
||||
package xyz.jonesdev.sonar.bukkit.antibot;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
@@ -26,7 +26,7 @@ import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackInjectedChannelInitializer;
|
||||
import xyz.jonesdev.sonar.common.netty.SonarInjectedChannelInitializer;
|
||||
import xyz.jonesdev.sonar.common.util.exception.ReflectiveOperationException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -34,8 +34,8 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_INACTIVE_LISTENER;
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_PACKET_DECODER;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.SONAR_INACTIVE_LISTENER;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.SONAR_PACKET_DECODER;
|
||||
import static xyz.jonesdev.sonar.bukkit.SonarBukkit.INITIALIZE_LISTENER;
|
||||
|
||||
// Check out these links if you want to see some more magic
|
||||
@@ -43,7 +43,7 @@ import static xyz.jonesdev.sonar.bukkit.SonarBukkit.INITIALIZE_LISTENER;
|
||||
// https://github.com/dmulloy2/ProtocolLib/blob/master/TinyProtocol/src/main/java/com/comphenix/tinyprotocol/TinyProtocol.java
|
||||
// https://github.com/ViaVersion/ViaVersion/blob/master/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitChannelInitializer.java
|
||||
@UtilityClass
|
||||
public class FallbackBukkitInjector {
|
||||
public class BukkitInjector {
|
||||
private final String LEGACY_NMS_PACKAGE;
|
||||
private final String OBC_PACKAGE;
|
||||
|
||||
@@ -253,10 +253,10 @@ public class FallbackBukkitInjector {
|
||||
|
||||
INITIALIZE_LISTENER.thenAccept(__ -> {
|
||||
try {
|
||||
childHandlerField.set(_bootstrap, new FallbackInjectedChannelInitializer(originalInitializer,
|
||||
childHandlerField.set(_bootstrap, new SonarInjectedChannelInitializer(originalInitializer,
|
||||
pipeline -> {
|
||||
pipeline.addAfter("splitter", FALLBACK_PACKET_DECODER, new FallbackBukkitInboundHandler());
|
||||
pipeline.addFirst(FALLBACK_INACTIVE_LISTENER, new ChannelInactiveListener());
|
||||
pipeline.addAfter("splitter", SONAR_PACKET_DECODER, new BukkitInboundHandler());
|
||||
pipeline.addFirst(SONAR_INACTIVE_LISTENER, new ChannelInactiveListener());
|
||||
}
|
||||
));
|
||||
} catch (IllegalAccessException exception) {
|
||||
+6
-2
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.bukkit.fallback;
|
||||
package xyz.jonesdev.sonar.bukkit.antibot;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -78,7 +78,11 @@ public enum BukkitServerVersion {
|
||||
MINECRAFT_1_21_5,
|
||||
MINECRAFT_1_21_6,
|
||||
MINECRAFT_1_21_7,
|
||||
MINECRAFT_1_21_8;
|
||||
MINECRAFT_1_21_8,
|
||||
MINECRAFT_1_21_9,
|
||||
MINECRAFT_1_21_10,
|
||||
MINECRAFT_1_21_11,
|
||||
MINECRAFT_26_1;
|
||||
|
||||
static final BukkitServerVersion[] REVERSED_VALUES;
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.bukkit.fallback;
|
||||
package xyz.jonesdev.sonar.bukkit.antibot;
|
||||
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.*;
|
||||
@@ -24,7 +24,7 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.bukkit.fallback.FallbackBukkitInjector;
|
||||
import xyz.jonesdev.sonar.bukkit.antibot.BukkitInjector;
|
||||
import xyz.jonesdev.sonar.common.util.FakeChannelUtil;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
@@ -32,7 +32,7 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_BANDWIDTH;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.SONAR_BANDWIDTH;
|
||||
|
||||
// https://github.com/ViaVersion/ViaVersion/blob/master/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/JoinListener.java
|
||||
public final class BukkitJoinListener implements Listener {
|
||||
@@ -46,13 +46,13 @@ public final class BukkitJoinListener implements Listener {
|
||||
|
||||
static {
|
||||
try {
|
||||
final Method handleMethod = FallbackBukkitInjector.getOBCClass("entity.CraftPlayer")
|
||||
final Method handleMethod = BukkitInjector.getOBCClass("entity.CraftPlayer")
|
||||
.getDeclaredMethod("getHandle");
|
||||
final Field listenerField = FallbackBukkitInjector.findField(false, handleMethod.getReturnType(),
|
||||
final Field listenerField = BukkitInjector.findField(false, handleMethod.getReturnType(),
|
||||
"PlayerConnection", "ServerGamePacketListenerImpl");
|
||||
final Field networkManagerField = FallbackBukkitInjector.findField(true, listenerField.getType(),
|
||||
final Field networkManagerField = BukkitInjector.findField(true, listenerField.getType(),
|
||||
"NetworkManager", "Connection");
|
||||
final Field channelField = FallbackBukkitInjector.getFieldAt(networkManagerField.getType(), Channel.class, 0);
|
||||
final Field channelField = BukkitInjector.getFieldAt(networkManagerField.getType(), Channel.class, 0);
|
||||
|
||||
_handleMethod = MethodHandles.lookup().unreflect(handleMethod);
|
||||
_listenerField = MethodHandles.lookup().unreflectGetter(listenerField);
|
||||
@@ -88,7 +88,7 @@ public final class BukkitJoinListener implements Listener {
|
||||
}
|
||||
|
||||
// Close the channel if Sonar's handlers are not found when the PlayerJoinEvent is called
|
||||
if (channel.pipeline().context(FALLBACK_BANDWIDTH) == null) {
|
||||
if (channel.pipeline().context(SONAR_BANDWIDTH) == null) {
|
||||
channel.close();
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
|
||||
@@ -14,7 +14,6 @@ dependencies {
|
||||
implementation(project(":common"))
|
||||
|
||||
compileOnly(rootProject.libs.bungeecord)
|
||||
testCompileOnly(rootProject.libs.bungeecord)
|
||||
|
||||
implementation(rootProject.libs.adventure.platform.bungee) {
|
||||
exclude(module = "adventure-nbt")
|
||||
|
||||
@@ -28,8 +28,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.SonarPlatform;
|
||||
import xyz.jonesdev.sonar.api.logger.LoggerWrapper;
|
||||
import xyz.jonesdev.sonar.bungee.antibot.BungeeInjector;
|
||||
import xyz.jonesdev.sonar.bungee.command.BungeeSonarCommand;
|
||||
import xyz.jonesdev.sonar.bungee.fallback.FallbackBungeeInjector;
|
||||
import xyz.jonesdev.sonar.common.boot.SonarBootstrap;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -107,7 +107,7 @@ public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
|
||||
getPlugin().getServer().getPluginManager().registerCommand(getPlugin(), new BungeeSonarCommand());
|
||||
|
||||
// Make sure to inject into the server's connection handler
|
||||
FallbackBungeeInjector.inject();
|
||||
BungeeInjector.inject();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.bungee.fallback;
|
||||
package xyz.jonesdev.sonar.bungee.antibot;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
@@ -25,16 +25,16 @@ import net.md_5.bungee.protocol.PacketWrapper;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.LoginRequest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.common.fallback.FallbackInboundHandlerAdapter;
|
||||
import xyz.jonesdev.sonar.common.InboundHandlerAdapter;
|
||||
import xyz.jonesdev.sonar.common.util.exception.ReflectiveOperationException;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake.HandshakePacket.STATUS;
|
||||
import static xyz.jonesdev.sonar.common.protocol.packets.handshake.HandshakePacket.STATUS;
|
||||
|
||||
final class FallbackBungeeInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
final class BungeeInboundHandler extends InboundHandlerAdapter {
|
||||
|
||||
private static final MethodHandle CHANNEL_WRAPPER_GETTER;
|
||||
|
||||
+10
-10
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.bungee.fallback;
|
||||
package xyz.jonesdev.sonar.bungee.antibot;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
@@ -27,15 +27,15 @@ 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;
|
||||
import xyz.jonesdev.sonar.common.netty.SonarInjectedChannelInitializer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static net.md_5.bungee.netty.PipelineUtils.PACKET_DECODER;
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_PACKET_HANDLER;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.SONAR_PACKET_HANDLER;
|
||||
|
||||
@UtilityClass
|
||||
public class FallbackBungeeInjector {
|
||||
public class BungeeInjector {
|
||||
public void inject() {
|
||||
try {
|
||||
final Field childField;
|
||||
@@ -61,9 +61,9 @@ public class FallbackBungeeInjector {
|
||||
// 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 ChannelInitializer<Channel> injectedInitializer = new SonarInjectedChannelInitializer(
|
||||
originalInitializer, pipeline -> pipeline.addAfter(PACKET_DECODER, SONAR_PACKET_HANDLER,
|
||||
new BungeeInboundHandler()));
|
||||
|
||||
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
@@ -86,9 +86,9 @@ public class FallbackBungeeInjector {
|
||||
if (!original.getChannelAcceptor().accept(channel)) {
|
||||
return false;
|
||||
}
|
||||
FallbackInjectedChannelInitializer.inject(channel,
|
||||
pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
|
||||
new FallbackBungeeInboundHandler()));
|
||||
SonarInjectedChannelInitializer.inject(channel,
|
||||
pipeline -> pipeline.addAfter(PACKET_DECODER, SONAR_PACKET_HANDLER,
|
||||
new BungeeInboundHandler()));
|
||||
return true;
|
||||
});
|
||||
ProxyServer.getInstance().unsafe().setFrontendChannelInitializer(newInitializer);
|
||||
@@ -23,7 +23,7 @@ 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.api.antibot.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.captcha.filters.CurvesOverlayFilter;
|
||||
import xyz.jonesdev.sonar.captcha.filters.NoiseOverlayFilter;
|
||||
|
||||
@@ -49,8 +49,11 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final Color[] COLORS = new Color[4];
|
||||
private static final float[] COLOR_FRACTIONS = new float[COLORS.length];
|
||||
static final Font FONT;
|
||||
|
||||
static {
|
||||
FONT = TTFFontProvider.loadFont("/assets/fonts/Kingthings_Trypewriter_2.ttf");
|
||||
|
||||
FBM.setAmount(0.6f);
|
||||
FBM.setScale(15);
|
||||
|
||||
@@ -113,8 +116,8 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
}
|
||||
|
||||
// Apply the random gradient effect
|
||||
graphics.setPaint(new LinearGradientPaint(0, 0, width, height,
|
||||
COLOR_FRACTIONS, COLORS, MultipleGradientPaint.CycleMethod.REPEAT));
|
||||
graphics.setPaint(new RadialGradientPaint(0, 0, width,
|
||||
COLOR_FRACTIONS, COLORS, MultipleGradientPaint.CycleMethod.REFLECT));
|
||||
}
|
||||
|
||||
private void drawCharacters(final @NotNull Graphics2D graphics,
|
||||
@@ -124,8 +127,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
|
||||
for (int i = 0; i < answer.length; i++) {
|
||||
// Create a glyph vector for the character with a random font
|
||||
final Font font = StandardTTFFontProvider.FONTS[RANDOM.nextInt(StandardTTFFontProvider.FONTS.length)];
|
||||
glyphs[i] = font.createGlyphVector(ctx, String.valueOf(answer[i]));
|
||||
glyphs[i] = FONT.createGlyphVector(ctx, String.valueOf(answer[i]));
|
||||
}
|
||||
|
||||
final double scalingXY = 5 - Math.min(answer.length, 5) * 0.65;
|
||||
@@ -135,7 +137,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
.mapToDouble(glyph -> glyph.getLogicalBounds().getWidth() * scalingXY - 1)
|
||||
.sum();
|
||||
double beginX = Math.max(Math.min(width / 2D - totalWidth / 2D, totalWidth), 0);
|
||||
double beginY = (height + StandardTTFFontProvider.STANDARD_FONT_SIZE / 2D) / 2D + scalingXY;
|
||||
double beginY = (height + TTFFontProvider.STANDARD_FONT_SIZE / 2D) / 2D + scalingXY;
|
||||
|
||||
// Draw each glyph one by one
|
||||
for (final GlyphVector glyph : glyphs) {
|
||||
|
||||
+3
-13
@@ -17,33 +17,23 @@
|
||||
|
||||
package xyz.jonesdev.sonar.captcha;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
@UtilityClass
|
||||
class StandardTTFFontProvider {
|
||||
private static final String[] FONT_NAMES = {"Kingthings_Trypewriter_2"};
|
||||
static final Font[] FONTS = new Font[FONT_NAMES.length];
|
||||
public final class TTFFontProvider {
|
||||
static final int STANDARD_FONT_SIZE = 25;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < FONT_NAMES.length; i++) {
|
||||
FONTS[i] = loadFont(String.format("/assets/fonts/%s.ttf", FONT_NAMES[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private static Font loadFont(final @NotNull String path) {
|
||||
public static Font loadFont(final @NotNull String path) {
|
||||
try (final InputStream inputStream = StandardCaptchaGenerator.class.getResourceAsStream(path)) {
|
||||
// Load the font from the TTF file
|
||||
final Font customFont = Font.createFont(Font.TRUETYPE_FONT, Objects.requireNonNull(inputStream));
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.complex;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.antibot.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.captcha.TTFFontProvider;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class ComplexCaptchaGenerator implements CaptchaGenerator {
|
||||
private final File background;
|
||||
private final int width = 128, height = 128;
|
||||
private BufferedImage backgroundImage;
|
||||
|
||||
private static final Font[] FONTS = {
|
||||
TTFFontProvider.loadFont("/assets/fonts/dotness.ttf"), // by http://bythebutterfly.com/
|
||||
TTFFontProvider.loadFont("/assets/fonts/DotMatrix.ttf"),
|
||||
};
|
||||
private static final Random RANDOM = new SecureRandom();
|
||||
private static final double MAX_ROTATION_RADIANS = Math.toRadians(15);
|
||||
private static final int LINE_COUNT = 8;
|
||||
private static final int MIN_LINE_COLOR = 100;
|
||||
private static final int MAX_TEXT_COLOR = 150;
|
||||
private static final int DOT_COUNT = 100;
|
||||
|
||||
private @NotNull BufferedImage createBackgroundImage() {
|
||||
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
|
||||
final Graphics2D graphics = image.createGraphics();
|
||||
if (background == null) {
|
||||
graphics.setBackground(Color.WHITE);
|
||||
graphics.clearRect(0, 0, image.getWidth(), image.getHeight());
|
||||
return image;
|
||||
}
|
||||
if (backgroundImage == null) {
|
||||
try {
|
||||
backgroundImage = ImageIO.read(background);
|
||||
} catch (IOException exception) {
|
||||
throw new IllegalStateException("Could not read background image", exception);
|
||||
}
|
||||
}
|
||||
graphics.drawImage(backgroundImage, 0, 0, Color.WHITE, null);
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BufferedImage createImage(char @NotNull [] answer) {
|
||||
final BufferedImage image = createBackgroundImage();
|
||||
final Graphics2D graphics = image.createGraphics();
|
||||
|
||||
final String text = new String(answer);
|
||||
final int padding = 12;
|
||||
final double maxWidth = width - 2D * padding;
|
||||
final double maxHeight = height - 2D * padding;
|
||||
|
||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
final FontRenderContext frc = graphics.getFontRenderContext();
|
||||
float optimalSize = 24;
|
||||
final float trialSize = 100;
|
||||
|
||||
final Rectangle2D trialBounds = FONTS[0].deriveFont(trialSize).getStringBounds(text, frc);
|
||||
|
||||
if (trialBounds.getWidth() > 0 && trialBounds.getHeight() > 0) {
|
||||
final double scaleFactorWidth = maxWidth / trialBounds.getWidth();
|
||||
final double scaleFactorHeight = maxHeight / trialBounds.getHeight();
|
||||
optimalSize = (float) (trialSize * Math.min(scaleFactorWidth, scaleFactorHeight));
|
||||
}
|
||||
|
||||
if (optimalSize < 1f) {
|
||||
optimalSize = 1f;
|
||||
}
|
||||
|
||||
final Font finalFont = FONTS[0].deriveFont(optimalSize);
|
||||
graphics.setFont(finalFont);
|
||||
|
||||
final Rectangle2D fullBounds = finalFont.getStringBounds(text, frc);
|
||||
|
||||
double currentX = (width - fullBounds.getWidth()) / 2D;
|
||||
|
||||
final double baselineY = (height / 2D) - (fullBounds.getHeight() / 2D) - fullBounds.getY();
|
||||
double currentY = baselineY;
|
||||
|
||||
for (final char c : answer) {
|
||||
final Font font = FONTS[RANDOM.nextInt(FONTS.length)].deriveFont(optimalSize);
|
||||
graphics.setFont(font);
|
||||
|
||||
final String character = String.valueOf(c);
|
||||
final Rectangle2D charBounds = font.getStringBounds(character, frc);
|
||||
|
||||
final double charWidth = charBounds.getWidth();
|
||||
final double charHeight = charBounds.getHeight();
|
||||
final double charCenterX = currentX + charWidth / 2D;
|
||||
final double charCenterY = baselineY + charBounds.getY() + charHeight / 2D;
|
||||
|
||||
final Color[] colors = new Color[2 + RANDOM.nextInt(2)];
|
||||
final float[] colorFractions = new float[colors.length];
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
colors[i] = getRandomTextColor();
|
||||
colorFractions[i] = i / (float) colors.length;
|
||||
}
|
||||
|
||||
graphics.setPaint(new RadialGradientPaint((float) currentX, (float) currentY, (float) charWidth,
|
||||
colorFractions, colors, MultipleGradientPaint.CycleMethod.REFLECT));
|
||||
|
||||
final double rotation = (RANDOM.nextDouble() * 2 * MAX_ROTATION_RADIANS) - MAX_ROTATION_RADIANS;
|
||||
|
||||
final AffineTransform originalTransform = graphics.getTransform();
|
||||
|
||||
graphics.rotate(rotation, charCenterX, charCenterY);
|
||||
|
||||
final TextLayout layout = new TextLayout(character, font, frc);
|
||||
|
||||
final AffineTransform translate = AffineTransform.getTranslateInstance(currentX, currentY);
|
||||
final Shape outline = layout.getOutline(translate);
|
||||
graphics.fill(outline);
|
||||
graphics.setTransform(originalTransform);
|
||||
|
||||
currentX += charWidth;
|
||||
currentY += RANDOM.nextDouble(charHeight / 4) - charHeight / 8;
|
||||
}
|
||||
|
||||
drawNoiseLines(graphics);
|
||||
drawNoiseDots(graphics);
|
||||
graphics.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
private @NotNull Color getRandomTextColor() {
|
||||
final int r = Math.min(RANDOM.nextInt(256), MAX_TEXT_COLOR);
|
||||
final int g = Math.min(RANDOM.nextInt(256), MAX_TEXT_COLOR);
|
||||
final int b = Math.min(RANDOM.nextInt(256), MAX_TEXT_COLOR);
|
||||
return new Color(r, g, b, 220);
|
||||
}
|
||||
|
||||
private @NotNull Color getRandomColor() {
|
||||
final int r = Math.max(RANDOM.nextInt(256), MIN_LINE_COLOR);
|
||||
final int g = Math.max(RANDOM.nextInt(256), MIN_LINE_COLOR);
|
||||
final int b = Math.max(RANDOM.nextInt(256), MIN_LINE_COLOR);
|
||||
final int a = Math.max(Math.min(RANDOM.nextInt(256), 200), MIN_LINE_COLOR);
|
||||
return new Color(r, g, b, a);
|
||||
}
|
||||
|
||||
private void drawNoiseLines(final @NotNull Graphics2D graphics) {
|
||||
for (int i = 0; i < LINE_COUNT; i++) {
|
||||
graphics.setColor(getRandomColor());
|
||||
graphics.setStroke(new BasicStroke(1f + RANDOM.nextFloat() * 2f,
|
||||
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
|
||||
|
||||
if (RANDOM.nextBoolean()) {
|
||||
float x1 = RANDOM.nextInt(width);
|
||||
float y1 = RANDOM.nextInt(height);
|
||||
float ctrlX = RANDOM.nextInt(width);
|
||||
float ctrlY = RANDOM.nextInt(height);
|
||||
float x2 = RANDOM.nextInt(width);
|
||||
float y2 = RANDOM.nextInt(height);
|
||||
|
||||
graphics.draw(new QuadCurve2D.Float(x1, y1, ctrlX, ctrlY, x2, y2));
|
||||
} else {
|
||||
int x1 = RANDOM.nextInt(width);
|
||||
int y1 = RANDOM.nextInt(height);
|
||||
int x2 = RANDOM.nextInt(width);
|
||||
int y2 = RANDOM.nextInt(height);
|
||||
|
||||
graphics.drawLine(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawNoiseDots(final @NotNull Graphics2D graphics) {
|
||||
for (int i = 0; i < DOT_COUNT; i++) {
|
||||
graphics.setColor(getRandomColor());
|
||||
|
||||
final int x = RANDOM.nextInt(width);
|
||||
final int y = RANDOM.nextInt(height);
|
||||
final int radius = 1 + RANDOM.nextInt(5);
|
||||
|
||||
graphics.fillOval(x, y, radius, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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.filters;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public final class CircleInverseFilter {
|
||||
private final int amount, minRadius, maxRadiusExpansion;
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public void transform(final @NotNull BufferedImage image) {
|
||||
final int minX = image.getWidth() / 4;
|
||||
final int minY = image.getHeight() / 4;
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
// Generate random position and radius for the circle
|
||||
final float centerX = minX + RANDOM.nextInt(image.getWidth() - minX * 2);
|
||||
final float centerY = minY + RANDOM.nextInt(image.getHeight() - minY * 2);
|
||||
final int radius = minRadius + RANDOM.nextInt(maxRadiusExpansion);
|
||||
|
||||
final Circle circle = new Circle(centerX, centerY, radius);
|
||||
// Draw inverted circle
|
||||
_addInvertedCircle(image, circle);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _addInvertedCircle(final @NotNull BufferedImage bufferedImage,
|
||||
final @NotNull Circle circle) {
|
||||
for (int x = 0; x < bufferedImage.getWidth(); x++) {
|
||||
for (int y = 0; y < bufferedImage.getHeight(); y++) {
|
||||
if (isWithinCircle(x, y, circle, circle.radius)) {
|
||||
// Invert colors within the circle
|
||||
final int rgb = bufferedImage.getRGB(x, y);
|
||||
final int invertedRGB = invertColorAndFilter(rgb);
|
||||
bufferedImage.setRGB(x, y, invertedRGB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isWithinCircle(final float x, final float y, final @NotNull Circle circle, int radius) {
|
||||
final float distanceX = x - circle.centerX;
|
||||
final float distanceY = y - circle.centerY;
|
||||
return distanceX * distanceX + distanceY * distanceY <= radius * radius;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
static final class Circle {
|
||||
private final float centerX;
|
||||
private final float centerY;
|
||||
private final int radius;
|
||||
}
|
||||
|
||||
private static int invertColorAndFilter(final int rgb) {
|
||||
final Color color = new Color(rgb);
|
||||
final int red = Math.max(Color.LIGHT_GRAY.getRed() - color.getRed(), 0);
|
||||
final int green = Math.max(Color.LIGHT_GRAY.getGreen() - color.getGreen(), 0);
|
||||
final int blue = Math.max(Color.LIGHT_GRAY.getBlue() - color.getBlue(), 0);
|
||||
return new Color(red, green, blue).getRGB();
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.filters;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public final class GridOverlayFilter {
|
||||
private final int amount, lineWidth, randomOffset;
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public void transform(final @NotNull BufferedImage image,
|
||||
final @NotNull Graphics2D graphics) {
|
||||
final int spacingX = image.getWidth() / amount + lineWidth;
|
||||
final int spacingY = image.getHeight() / amount + lineWidth;
|
||||
int currentX = spacingX / 2;
|
||||
int currentY = spacingY / 2;
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
graphics.setStroke(new BasicStroke(lineWidth * 0.5f + lineWidth * RANDOM.nextFloat()));
|
||||
graphics.drawLine(currentX, 0, currentX + RANDOM.nextInt(randomOffset), image.getHeight());
|
||||
graphics.drawLine(0, currentY, image.getWidth(), currentY + RANDOM.nextInt(randomOffset));
|
||||
|
||||
currentX += spacingX + lineWidth;
|
||||
currentY += spacingY + lineWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ 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.api.antibot.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.captcha.filters.NoiseOverlayFilter;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
My fonts are free for personal use. You also MAY redistribute the fonts on your website as long as you guve credit to http://bythebutterfly.com as the creator of the fonts. If you are interested in commercial use, please email me at BYTHEBUTTERFLY@GMAIL.COM
|
||||
|
||||
Thanks, and enjoy :)
|
||||
|
||||
Vanessa
|
||||
@@ -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
|
||||
@@ -16,7 +16,8 @@
|
||||
*/
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.api.antibot.captcha.CaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.captcha.complex.ComplexCaptchaGenerator;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -28,7 +29,7 @@ import java.util.Random;
|
||||
public class Main {
|
||||
public void main(final String... args) throws IOException {
|
||||
final Random random = new Random();
|
||||
final StandardCaptchaGenerator standardCaptchaGenerator = new StandardCaptchaGenerator(null);
|
||||
final CaptchaGenerator standardCaptchaGenerator = new ComplexCaptchaGenerator(null);
|
||||
|
||||
final long start = System.currentTimeMillis();
|
||||
final char[] dictionary = {'a', 'b', 'c', 'd', 'e', 'f'/*, 'g'*/, 'h'/*, 'i'*/, 'j',
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
package xyz.jonesdev.sonar.common;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
@@ -29,8 +29,8 @@ import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class FallbackBandwidthHandler extends ChannelDuplexHandler {
|
||||
public static final ChannelHandler INSTANCE = new FallbackBandwidthHandler();
|
||||
public final class BandwidthHandler extends ChannelDuplexHandler {
|
||||
public static final ChannelHandler INSTANCE = new BandwidthHandler();
|
||||
|
||||
@Override
|
||||
public void channelRead(final ChannelHandlerContext ctx, final @NotNull Object msg) throws Exception {
|
||||
+9
-5
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
package xyz.jonesdev.sonar.common;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
@@ -25,13 +25,14 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.common.netty.TailExceptionsHandler;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
public final class InboundHandler extends ChannelInboundHandlerAdapter {
|
||||
private final Consumer<ChannelPipeline> sonarPipelineInjector;
|
||||
@Setter
|
||||
@Getter
|
||||
@@ -55,11 +56,11 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
// Account for this by checking if the inetAddress has been set yet
|
||||
if (inetAddress != null) {
|
||||
// Remove the IP address from the queue
|
||||
Sonar.get0().getFallback().getQueue().getPlayers().compute(inetAddress, (ignored, action) -> {
|
||||
Sonar.get0().getAntiBot().getQueue().getPlayers().compute(inetAddress, (ignored, action) -> {
|
||||
// The player is not queued, so we need to remove them from other maps as well
|
||||
if (action == null) {
|
||||
// Remove the IP address from the connected players, if needed
|
||||
Sonar.get0().getFallback().getConnected().compute(inetAddress, (__, v) -> {
|
||||
Sonar.get0().getAntiBot().getConnected().compute(inetAddress, (__, v) -> {
|
||||
/*
|
||||
* Remove this account from the online players or decrement the number of accounts
|
||||
* with the same IP, but only if the player is logging into the backend server.
|
||||
@@ -67,7 +68,7 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
* we've never actually incremented it in the first place ¯\_(ツ)_/¯
|
||||
*/
|
||||
if (v == null) {
|
||||
Sonar.get0().getFallback().getOnline().compute(inetAddress,
|
||||
Sonar.get0().getAntiBot().getOnline().compute(inetAddress,
|
||||
(ignored1, count) -> count == null || count <= 1 ? null : count - 1);
|
||||
}
|
||||
return null;
|
||||
@@ -85,5 +86,8 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
ctx.close();
|
||||
if (TailExceptionsHandler.LOG_EXCEPTIONS) {
|
||||
cause.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
-30
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
package xyz.jonesdev.sonar.common;
|
||||
|
||||
import io.netty.channel.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,13 +23,14 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.fingerprint.FingerprintingUtil;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackTimeoutHandler;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.netty.SonarTimeoutHandler;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.util.EaglerUtil;
|
||||
import xyz.jonesdev.sonar.common.util.GeyserUtil;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
@@ -39,14 +40,15 @@ import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.*;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.*;
|
||||
import static xyz.jonesdev.sonar.common.protocol.SonarPacketPreparer.*;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandlerAdapter {
|
||||
public abstract class InboundHandlerAdapter extends ChannelInboundHandlerAdapter {
|
||||
protected @Nullable String username;
|
||||
protected ProtocolVersion protocolVersion;
|
||||
protected @Nullable String handshakeHostname;
|
||||
protected @Nullable RemovalListener channelRemovalListener;
|
||||
|
||||
/**
|
||||
@@ -64,7 +66,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
protocolVersion = ProtocolVersion.fromId(protocol);
|
||||
ctx.pipeline().addFirst(FALLBACK_BANDWIDTH, FallbackBandwidthHandler.INSTANCE);
|
||||
handshakeHostname = hostname;
|
||||
ctx.pipeline().addFirst(SONAR_BANDWIDTH, BandwidthHandler.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,10 +97,10 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
this.username = username;
|
||||
|
||||
final InetAddress inetAddress = socketAddress.getAddress();
|
||||
ctx.pipeline().get(FallbackInboundHandler.class).setInetAddress(inetAddress);
|
||||
ctx.pipeline().get(InboundHandler.class).setInetAddress(inetAddress);
|
||||
|
||||
// Check if Fallback is already verifying a player with the same IP address
|
||||
if (Sonar.get0().getFallback().getConnected().containsKey(inetAddress)) {
|
||||
// Check if Sonar is already verifying a player with the same IP address
|
||||
if (Sonar.get0().getAntiBot().getConnected().containsKey(inetAddress)) {
|
||||
customDisconnect(ctx.channel(), alreadyVerifying, protocolVersion);
|
||||
return;
|
||||
}
|
||||
@@ -112,7 +115,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
// Check if the player failed the verification too many times
|
||||
final int limit = Sonar.get0().getConfig().getVerification().getBlacklistThreshold();
|
||||
if (limit > 0) {
|
||||
final int score = Sonar.get0().getFallback().getBlacklist().asMap().getOrDefault(hostAddress, 0);
|
||||
final int score = Sonar.get0().getAntiBot().getBlacklist().asMap().getOrDefault(hostAddress, 0);
|
||||
if (score >= limit) {
|
||||
customDisconnect(ctx.channel(), blacklisted, protocolVersion);
|
||||
return;
|
||||
@@ -120,7 +123,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
}
|
||||
|
||||
// Don't continue the verification process if the verification is disabled
|
||||
if (!Sonar.get0().getFallback().shouldVerifyNewPlayers()) {
|
||||
if (!Sonar.get0().getAntiBot().shouldVerifyNewPlayers()) {
|
||||
initialLogin(ctx.channel(), inetAddress, initialLoginAction);
|
||||
return;
|
||||
}
|
||||
@@ -132,6 +135,13 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
return;
|
||||
}
|
||||
|
||||
// Completely skip EaglercraftX connections if configured
|
||||
if (EaglerUtil.isEaglerConnection(ctx.channel())
|
||||
&& !Sonar.get0().getConfig().getVerification().isCheckEagler()) {
|
||||
initialLogin(ctx.channel(), inetAddress, initialLoginAction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we actually have to verify the player
|
||||
final String fingerprint = FingerprintingUtil.getFingerprint(username, hostAddress);
|
||||
if (Sonar.get0().getVerifiedPlayerController().getCache().contains(fingerprint)) {
|
||||
@@ -140,7 +150,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
}
|
||||
|
||||
// Check if the IP address is currently being rate-limited
|
||||
if (!Sonar.get0().getFallback().getRatelimiter().attempt(inetAddress)) {
|
||||
if (!Sonar.get0().getAntiBot().getRatelimiter().attempt(inetAddress)) {
|
||||
customDisconnect(ctx.channel(), reconnectedTooFast, protocolVersion);
|
||||
return;
|
||||
}
|
||||
@@ -149,7 +159,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
rewriteProtocol(ctx, channelRemovalListener);
|
||||
|
||||
// Queue the connection for further processing
|
||||
Sonar.get0().getFallback().getQueue().getPlayers().compute(inetAddress, (__, runnable) -> {
|
||||
Sonar.get0().getAntiBot().getQueue().getPlayers().compute(inetAddress, (__, runnable) -> {
|
||||
// Check if the player is already queued since we don't want bots to flood the queue
|
||||
if (runnable != null) {
|
||||
customDisconnect(ctx.channel(), alreadyQueued, protocolVersion);
|
||||
@@ -158,7 +168,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
}
|
||||
|
||||
// Create an instance for the user and let the verification handler take over the channel
|
||||
return () -> new FallbackUserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser);
|
||||
return () -> new UserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser,
|
||||
handshakeHostname);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -169,11 +180,13 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
final @NotNull InetAddress inetAddress,
|
||||
final @NotNull Runnable loginPacket) throws Exception {
|
||||
final int maxOnlinePerIp = Sonar.get0().getConfig().getMaxOnlinePerIp();
|
||||
final int newCount = Sonar.get0().getFallback().getOnline().compute(inetAddress,
|
||||
(__, count) -> count == null ? 1 : count + 1);
|
||||
if (newCount > maxOnlinePerIp) {
|
||||
customDisconnect(channel, tooManyOnlinePerIP, protocolVersion);
|
||||
return;
|
||||
if (maxOnlinePerIp > 0) {
|
||||
final int newCount = Sonar.get0().getAntiBot().getOnline().compute(inetAddress,
|
||||
(__, count) -> count == null ? 1 : count + 1);
|
||||
if (newCount > maxOnlinePerIp) {
|
||||
customDisconnect(channel, tooManyOnlinePerIP, protocolVersion);
|
||||
return;
|
||||
}
|
||||
}
|
||||
loginPacket.run();
|
||||
}
|
||||
@@ -189,6 +202,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
// Don't remove floodgate's pipelines
|
||||
|| entry.getKey().startsWith("geyser")
|
||||
|| entry.getKey().startsWith("floodgate")
|
||||
|| entry.getKey().startsWith("eagler")
|
||||
|| entry.getKey().equals("DefaultChannelPipeline$TailContext#0")) {
|
||||
continue;
|
||||
}
|
||||
@@ -198,14 +212,14 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
}
|
||||
}
|
||||
// Add our read/write timeout handler
|
||||
ctx.pipeline().addFirst(FALLBACK_TIMEOUT, new FallbackTimeoutHandler(
|
||||
ctx.pipeline().addFirst(SONAR_TIMEOUT, new SonarTimeoutHandler(
|
||||
Sonar.get0().getConfig().getVerification().getReadTimeout(),
|
||||
Sonar.get0().getConfig().getVerification().getWriteTimeout(),
|
||||
TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
private static void customDisconnect(final @NotNull Channel channel,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final @NotNull SonarPacket packet,
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
if (channel.isActive()) {
|
||||
if (channel.eventLoop().inEventLoop()) {
|
||||
@@ -220,7 +234,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
* Disconnect the player before verification (during login)
|
||||
*/
|
||||
private static void _customDisconnect(final @NotNull Channel channel,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final @NotNull SonarPacket packet,
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
// TODO: recode this
|
||||
// Remove the connection handler pipeline to completely take over the channel
|
||||
@@ -233,10 +247,10 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
// Close the channel if no encoder exists
|
||||
if (currentEncoder != null) {
|
||||
// We don't need to update the encoder if it has already been replaced by Sonar
|
||||
if (!(currentEncoder instanceof FallbackPacketEncoder)) {
|
||||
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
channel.pipeline().replace(encoder, FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
if (!(currentEncoder instanceof SonarPacketEncoder)) {
|
||||
final SonarPacketEncoder newEncoder = new SonarPacketEncoder(protocolVersion);
|
||||
newEncoder.updateRegistry(SonarPacketRegistry.LOGIN);
|
||||
channel.pipeline().replace(encoder, SONAR_PACKET_ENCODER, newEncoder);
|
||||
}
|
||||
ProtocolUtil.closeWith(channel, protocolVersion, packet);
|
||||
} else {
|
||||
+42
-38
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
package xyz.jonesdev.sonar.common;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -25,30 +25,31 @@ import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.antibot.SonarUser;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.event.impl.UserVerifyJoinEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackTailExceptionsHandler;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackVarInt21FrameDecoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackVarIntLengthEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketDecoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.DisconnectPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.verification.FallbackPreJoinHandler;
|
||||
import xyz.jonesdev.sonar.common.netty.MinecraftVarInt21FrameDecoder;
|
||||
import xyz.jonesdev.sonar.common.netty.MinecraftVarIntLengthEncoder;
|
||||
import xyz.jonesdev.sonar.common.netty.TailExceptionsHandler;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketDecoder;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketPreparer;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.play.DisconnectPacket;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.verification.LoginHandler;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.*;
|
||||
|
||||
@Getter
|
||||
@ToString(of = {"protocolVersion", "inetAddress", "geyser"})
|
||||
public final class FallbackUserWrapper implements FallbackUser {
|
||||
@ToString(of = {"protocolVersion", "inetAddress", "hostname", "geyser"})
|
||||
public final class UserWrapper implements SonarUser {
|
||||
@Accessors(fluent = true)
|
||||
private final Channel channel;
|
||||
private final InetAddress inetAddress;
|
||||
@@ -56,22 +57,25 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
private final String fingerprint;
|
||||
private final String username;
|
||||
private final boolean geyser;
|
||||
private final @Nullable String hostname;
|
||||
private final SystemTimer loginTimer;
|
||||
@Setter
|
||||
private boolean forceCaptcha;
|
||||
|
||||
public FallbackUserWrapper(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull InetAddress inetAddress,
|
||||
final @NotNull ProtocolVersion protocolVersion,
|
||||
final @NotNull String username,
|
||||
final @NotNull String fingerprint,
|
||||
final boolean geyser) {
|
||||
public UserWrapper(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull InetAddress inetAddress,
|
||||
final @NotNull ProtocolVersion protocolVersion,
|
||||
final @NotNull String username,
|
||||
final @NotNull String fingerprint,
|
||||
final boolean geyser,
|
||||
final @Nullable String hostname) {
|
||||
this.channel = ctx.channel();
|
||||
this.inetAddress = inetAddress;
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.username = username;
|
||||
this.fingerprint = fingerprint;
|
||||
this.geyser = geyser;
|
||||
this.hostname = hostname;
|
||||
this.loginTimer = new SystemTimer();
|
||||
|
||||
GlobalSonarStatistics.totalAttemptedVerifications++;
|
||||
@@ -97,48 +101,48 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
}
|
||||
|
||||
// How? Is there some kind of de-sync or race condition?
|
||||
if (channel.pipeline().context(FALLBACK_FRAME_ENCODER) != null) {
|
||||
if (channel.pipeline().context(SONAR_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);
|
||||
Sonar.get0().getAntiBot().getConnected().compute(inetAddress, (__, v) -> true);
|
||||
|
||||
// Replace normal encoder to allow custom packets
|
||||
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
|
||||
channel.pipeline().addFirst(FALLBACK_FRAME_ENCODER, FallbackVarIntLengthEncoder.INSTANCE);
|
||||
channel.pipeline().addLast(FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
final SonarPacketEncoder newEncoder = new SonarPacketEncoder(protocolVersion);
|
||||
channel.pipeline().addFirst(SONAR_FRAME_ENCODER, MinecraftVarIntLengthEncoder.INSTANCE);
|
||||
channel.pipeline().addLast(SONAR_PACKET_ENCODER, newEncoder);
|
||||
|
||||
// Replace normal decoder to allow custom packets
|
||||
final FallbackPacketDecoder newDecoder = new FallbackPacketDecoder(protocolVersion);
|
||||
channel.pipeline().addFirst(FALLBACK_FRAME_DECODER, new FallbackVarInt21FrameDecoder());
|
||||
channel.pipeline().addLast(FALLBACK_PACKET_DECODER, newDecoder);
|
||||
final SonarPacketDecoder newDecoder = new SonarPacketDecoder(protocolVersion);
|
||||
channel.pipeline().addFirst(SONAR_FRAME_DECODER, new MinecraftVarInt21FrameDecoder());
|
||||
channel.pipeline().addLast(SONAR_PACKET_DECODER, newDecoder);
|
||||
|
||||
// We're sending the LoginSuccess packet now
|
||||
newDecoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
newDecoder.updateRegistry(SonarPacketRegistry.LOGIN);
|
||||
newEncoder.updateRegistry(SonarPacketRegistry.LOGIN);
|
||||
// Send LoginSuccess packet to make the client think they are joining the server
|
||||
write(FallbackPreparer.loginSuccess);
|
||||
write(SonarPacketPreparer.loginSuccess);
|
||||
|
||||
// pre-1.20.2 clients do not have the configuration stage
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
newDecoder.updateRegistry(FallbackPacketRegistry.GAME);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.GAME);
|
||||
newDecoder.updateRegistry(SonarPacketRegistry.GAME);
|
||||
newEncoder.updateRegistry(SonarPacketRegistry.GAME);
|
||||
}
|
||||
|
||||
// Listen for all incoming packets by setting the packet listener
|
||||
newDecoder.setListener(new FallbackPreJoinHandler(this));
|
||||
newDecoder.setListener(new LoginHandler(this));
|
||||
|
||||
// Make sure to catch all exceptions during the verification
|
||||
channel.pipeline().addLast(FALLBACK_TAIL_EXCEPTIONS, FallbackTailExceptionsHandler.INSTANCE);
|
||||
channel.pipeline().addLast(SONAR_TAIL_EXCEPTIONS, TailExceptionsHandler.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(final @NotNull Component reason) {
|
||||
final FallbackPacketEncoder encoder = channel.pipeline().get(FallbackPacketEncoder.class);
|
||||
final boolean duringLogin = encoder != null && encoder.getPacketRegistry() == FallbackPacketRegistry.LOGIN;
|
||||
final SonarPacketEncoder encoder = channel.pipeline().get(SonarPacketEncoder.class);
|
||||
final boolean duringLogin = encoder != null && encoder.getPacketRegistry() == SonarPacketRegistry.LOGIN;
|
||||
ProtocolUtil.closeWith(channel, protocolVersion, new DisconnectPacket(reason, duringLogin));
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ class LibraryLoader {
|
||||
Library.builder()
|
||||
.groupId("com{}github{}ben-manes{}caffeine")
|
||||
.artifactId("caffeine")
|
||||
.version("3.2.0")
|
||||
.version("3.2.3")
|
||||
.relocate("com{}github{}benmanes{}caffeine", "xyz{}jonesdev{}sonar{}libs{}caffeine")
|
||||
.build(),
|
||||
// ORMLite
|
||||
@@ -68,26 +68,38 @@ class LibraryLoader {
|
||||
|
||||
// Only load adventure if not on Velocity
|
||||
if (platform != SonarPlatform.VELOCITY) {
|
||||
libraryManager.loadLibraries(
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-minimessage")
|
||||
.version("4.13.1") // adventure-platforms hasn't updated in years... Please update! :'(
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-serializer-gson")
|
||||
.version("4.18.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-nbt")
|
||||
.version("4.18.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build()
|
||||
);
|
||||
if (platform != SonarPlatform.PAPER) {
|
||||
libraryManager.loadLibraries(
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-minimessage")
|
||||
.version("4.21.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-serializer-gson")
|
||||
.version("4.21.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-nbt")
|
||||
.version("4.21.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build()
|
||||
);
|
||||
} else {
|
||||
// On Paper, we only relocate the nbt package since the rest of adventure is bundled with the server.
|
||||
libraryManager.loadLibrary(
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-nbt")
|
||||
.version("4.21.0")
|
||||
.relocate("net{}kyori{}adventure{}nbt", "xyz{}jonesdev{}sonar{}libs{}kyori{}adventure{}nbt")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,9 +36,9 @@ import xyz.jonesdev.sonar.api.notification.ActionBarNotificationHandler;
|
||||
import xyz.jonesdev.sonar.api.notification.ChatNotificationHandler;
|
||||
import xyz.jonesdev.sonar.api.statistics.SonarStatistics;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.ratelimit.CaffeineCacheRatelimiter;
|
||||
import xyz.jonesdev.sonar.common.fallback.ratelimit.NoopCacheRatelimiter;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketPreparer;
|
||||
import xyz.jonesdev.sonar.common.ratelimit.CaffeineCacheRatelimiter;
|
||||
import xyz.jonesdev.sonar.common.ratelimit.NoopCacheRatelimiter;
|
||||
import xyz.jonesdev.sonar.common.service.ScheduledServiceManager;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.subcommand.*;
|
||||
@@ -137,26 +137,26 @@ public abstract class SonarBootstrap<T> implements Sonar {
|
||||
|
||||
// Prepare cached packets
|
||||
getLogger().info("Taking cached snapshots of all packets...");
|
||||
FallbackPreparer.prepare();
|
||||
SonarPacketPreparer.prepare();
|
||||
|
||||
// Update ratelimiter cache
|
||||
getFallback().setRatelimiter(getConfig().getVerification().getReconnectDelay() > 0L
|
||||
getAntiBot().setRatelimiter(getConfig().getVerification().getReconnectDelay() > 0L
|
||||
? new CaffeineCacheRatelimiter(Duration.ofMillis(getConfig().getVerification().getReconnectDelay()))
|
||||
: NoopCacheRatelimiter.INSTANCE);
|
||||
|
||||
// Update blacklist cache
|
||||
final long blacklistTime = getConfig().getVerification().getBlacklistTime();
|
||||
final boolean blacklistExists = getFallback().getBlacklist() != null;
|
||||
final boolean blacklistExists = getAntiBot().getBlacklist() != null;
|
||||
// Make sure the blacklist is only set when we need it to prevent data loss
|
||||
if (!blacklistExists // Make sure we create a new cache if it doesn't exist yet
|
||||
|| getFallback().getBlacklistTime() != blacklistTime) {
|
||||
|| getAntiBot().getBlacklistTime() != blacklistTime) {
|
||||
// Create a new cache with the configured blacklist time
|
||||
getFallback().setBlacklist(Caffeine.newBuilder()
|
||||
getAntiBot().setBlacklist(Caffeine.newBuilder()
|
||||
.expireAfterWrite(Duration.ofMillis(getConfig().getVerification().getBlacklistTime()))
|
||||
.ticker(Ticker.systemTicker())
|
||||
.build());
|
||||
// Store the new blacklist time, so we don't have to reset the blacklist every reload
|
||||
getFallback().setBlacklistTime(blacklistTime);
|
||||
getAntiBot().setBlacklistTime(blacklistTime);
|
||||
// Warn the user about changing the expiry of the blacklist values
|
||||
if (blacklistExists) {
|
||||
getLogger().warn("The blacklist has been reset as the duration of entries has changed.");
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
package xyz.jonesdev.sonar.common.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -29,7 +29,7 @@ import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
import java.util.List;
|
||||
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java
|
||||
public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
public final class MinecraftVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
|
||||
@Override
|
||||
protected void decode(final @NotNull ChannelHandlerContext ctx,
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
package xyz.jonesdev.sonar.common.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
@@ -28,8 +28,8 @@ import java.util.List;
|
||||
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java
|
||||
@ChannelHandler.Sharable
|
||||
public final class FallbackVarIntLengthEncoder extends MessageToMessageEncoder<ByteBuf> {
|
||||
public static final FallbackVarIntLengthEncoder INSTANCE = new FallbackVarIntLengthEncoder();
|
||||
public final class MinecraftVarIntLengthEncoder extends MessageToMessageEncoder<ByteBuf> {
|
||||
public static final MinecraftVarIntLengthEncoder INSTANCE = new MinecraftVarIntLengthEncoder();
|
||||
|
||||
@Override
|
||||
protected void encode(final @NotNull ChannelHandlerContext ctx,
|
||||
+11
-7
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
package xyz.jonesdev.sonar.common.netty;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
@@ -24,7 +24,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.SonarPlatform;
|
||||
import xyz.jonesdev.sonar.common.fallback.FallbackInboundHandler;
|
||||
import xyz.jonesdev.sonar.common.InboundHandler;
|
||||
import xyz.jonesdev.sonar.common.util.FakeChannelUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.ReflectiveOperationException;
|
||||
|
||||
@@ -33,10 +33,10 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_INBOUND_HANDLER;
|
||||
import static xyz.jonesdev.sonar.api.antibot.ChannelPipelines.SONAR_INBOUND_HANDLER;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackInjectedChannelInitializer extends ChannelInitializer<Channel> {
|
||||
public final class SonarInjectedChannelInitializer extends ChannelInitializer<Channel> {
|
||||
private static final MethodHandle INIT_CHANNEL_METHOD;
|
||||
|
||||
static {
|
||||
@@ -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);
|
||||
@@ -67,13 +71,13 @@ public final class FallbackInjectedChannelInitializer extends ChannelInitializer
|
||||
// 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)) {
|
||||
final FallbackInboundHandler inboundHandler = new FallbackInboundHandler(sonarPipelineInjector);
|
||||
final InboundHandler inboundHandler = new InboundHandler(sonarPipelineInjector);
|
||||
// We need to be careful on Bukkit, as the encoder can be different
|
||||
if (Sonar.get0().getPlatform() == SonarPlatform.BUKKIT) {
|
||||
final String encoder = Sonar.get0().getPlatform().getEncoder().apply(channel.pipeline());
|
||||
channel.pipeline().addBefore(encoder, FALLBACK_INBOUND_HANDLER, inboundHandler);
|
||||
channel.pipeline().addBefore(encoder, SONAR_INBOUND_HANDLER, inboundHandler);
|
||||
} else {
|
||||
channel.pipeline().addFirst(FALLBACK_INBOUND_HANDLER, inboundHandler);
|
||||
channel.pipeline().addFirst(SONAR_INBOUND_HANDLER, inboundHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
package xyz.jonesdev.sonar.common.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
@@ -24,8 +24,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class FallbackTimeoutHandler extends IdleStateHandler {
|
||||
public FallbackTimeoutHandler(final int readTimeout, final int writeTimeout, final TimeUnit timeUnit) {
|
||||
public final class SonarTimeoutHandler extends IdleStateHandler {
|
||||
public SonarTimeoutHandler(final int readTimeout, final int writeTimeout, final TimeUnit timeUnit) {
|
||||
super(false, readTimeout, writeTimeout, 0L, timeUnit);
|
||||
}
|
||||
|
||||
+8
-3
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
package xyz.jonesdev.sonar.common.netty;
|
||||
|
||||
import io.netty.channel.ChannelDuplexHandler;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
@@ -23,8 +23,10 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler {
|
||||
public static final FallbackTailExceptionsHandler INSTANCE = new FallbackTailExceptionsHandler();
|
||||
public final class TailExceptionsHandler extends ChannelDuplexHandler {
|
||||
public static final TailExceptionsHandler INSTANCE = new TailExceptionsHandler();
|
||||
// Do not enable unless instructed by support.
|
||||
public static final boolean LOG_EXCEPTIONS = Boolean.getBoolean("sonar.log-netty-exceptions");
|
||||
|
||||
// We can override the default exceptionCaught method since the server
|
||||
// does not have any other pipelines that could handle this error.
|
||||
@@ -33,5 +35,8 @@ public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler {
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
// Close the channel if we encounter any errors.
|
||||
ctx.close();
|
||||
if (LOG_EXCEPTIONS) {
|
||||
cause.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -15,14 +15,14 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.event.impl.CaptchaGenerationEndEvent;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.MapCaptchaInfo;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.MapColorPalette;
|
||||
import xyz.jonesdev.sonar.common.protocol.map.MapCaptchaInfo;
|
||||
import xyz.jonesdev.sonar.common.protocol.map.MapColorPalette;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
@@ -62,7 +62,7 @@ public class CaptchaPreparer {
|
||||
for (int j = 0; j < answer.length; j++) {
|
||||
answer[j] = alphabet[RANDOM.nextInt(alphabet.length)];
|
||||
}
|
||||
final BufferedImage image = Sonar.get0().getFallback().getCaptchaGenerator().createImage(answer);
|
||||
final BufferedImage image = Sonar.get0().getAntiBot().getCaptchaGenerator().createImage(answer);
|
||||
// Convert and cache converted Minecraft map bytes
|
||||
cached[preparedAmount++] = new MapCaptchaInfo(new String(answer), MapColorPalette.imageToBuffer(image));
|
||||
}
|
||||
+3
-3
@@ -15,12 +15,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
|
||||
public interface FallbackPacket {
|
||||
public interface SonarPacket {
|
||||
|
||||
/**
|
||||
* Encodes the packet sent by the server
|
||||
+10
-10
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -24,22 +24,22 @@ import io.netty.handler.codec.DecoderException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.maxTotalPacketsSent;
|
||||
import static xyz.jonesdev.sonar.common.protocol.SonarPacketPreparer.maxTotalPacketsSent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
public final class SonarPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
private final ProtocolVersion protocolVersion;
|
||||
private FallbackPacketRegistry.ProtocolRegistry registry;
|
||||
private SonarPacketRegistry.ProtocolRegistry registry;
|
||||
@Setter
|
||||
private FallbackPacketListener listener;
|
||||
private SonarPacketListener listener;
|
||||
private int totalPacketsSent;
|
||||
|
||||
public void updateRegistry(final @NotNull FallbackPacketRegistry registry) {
|
||||
this.registry = registry.getProtocolRegistry(FallbackPacketRegistry.Direction.SERVERBOUND, protocolVersion);
|
||||
public void updateRegistry(final @NotNull SonarPacketRegistry registry) {
|
||||
this.registry = registry.getProtocolRegistry(SonarPacketRegistry.Direction.SERVERBOUND, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +62,7 @@ public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
|
||||
// Read the packet ID and then create the packet from it
|
||||
final int packetId = ProtocolUtil.readVarInt(byteBuf);
|
||||
final FallbackPacket packet = registry.createPacket(packetId);
|
||||
final SonarPacket packet = registry.createPacket(packetId);
|
||||
|
||||
// Skip the packet if it's not registered within Sonar's packet registry
|
||||
if (packet == null) {
|
||||
@@ -98,7 +98,7 @@ public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPacketSize(final int packetSize, final @NotNull FallbackPacket packet) throws Exception {
|
||||
private void checkPacketSize(final int packetSize, final @NotNull SonarPacket packet) throws Exception {
|
||||
final int expectedMaxLen = packet.expectedMaxLength(protocolVersion);
|
||||
if (expectedMaxLen != -1 && packetSize > expectedMaxLen) {
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Packet too large: " + packetSize + " max: " + expectedMaxLen)
|
||||
+10
-10
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -23,27 +23,27 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackPacketEncoder extends MessageToByteEncoder<FallbackPacket> {
|
||||
public final class SonarPacketEncoder extends MessageToByteEncoder<SonarPacket> {
|
||||
private final ProtocolVersion protocolVersion;
|
||||
@Getter
|
||||
private FallbackPacketRegistry packetRegistry;
|
||||
private FallbackPacketRegistry.ProtocolRegistry protocolRegistry;
|
||||
private SonarPacketRegistry packetRegistry;
|
||||
private SonarPacketRegistry.ProtocolRegistry protocolRegistry;
|
||||
|
||||
public void updateRegistry(final @NotNull FallbackPacketRegistry packetRegistry) {
|
||||
public void updateRegistry(final @NotNull SonarPacketRegistry packetRegistry) {
|
||||
this.packetRegistry = packetRegistry;
|
||||
this.protocolRegistry = packetRegistry.getProtocolRegistry(FallbackPacketRegistry.Direction.CLIENTBOUND, protocolVersion);
|
||||
this.protocolRegistry = packetRegistry.getProtocolRegistry(SonarPacketRegistry.Direction.CLIENTBOUND, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final @NotNull SonarPacket packet,
|
||||
final @NotNull ByteBuf out) throws Exception {
|
||||
final Class<? extends FallbackPacket> originalPacket = packet instanceof FallbackPacketSnapshot
|
||||
? ((FallbackPacketSnapshot) packet).getOriginalPacketClass() : packet.getClass();
|
||||
final Class<? extends SonarPacket> originalPacket = packet instanceof SonarPacketSnapshot
|
||||
? ((SonarPacketSnapshot) packet).getOriginalPacketClass() : packet.getClass();
|
||||
final int packetId = protocolRegistry.getPacketId(originalPacket);
|
||||
ProtocolUtil.writeVarInt(out, packetId);
|
||||
packet.encode(out, protocolVersion);
|
||||
+3
-3
@@ -15,17 +15,17 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FallbackPacketListener {
|
||||
public interface SonarPacketListener {
|
||||
|
||||
/**
|
||||
* Handles the incoming packet
|
||||
*
|
||||
* @param packet Packet to handle
|
||||
*/
|
||||
void handle(final @NotNull FallbackPacket packet);
|
||||
void handle(final @NotNull SonarPacket packet);
|
||||
}
|
||||
+124
-108
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
@@ -23,21 +23,24 @@ import net.kyori.adventure.nbt.IntBinaryTag;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
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.complex.ComplexCaptchaGenerator;
|
||||
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.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.protocol.block.BlockType;
|
||||
import xyz.jonesdev.sonar.common.protocol.block.BlockUpdate;
|
||||
import xyz.jonesdev.sonar.common.protocol.dimension.DimensionRegistry;
|
||||
import xyz.jonesdev.sonar.common.protocol.dimension.DimensionType;
|
||||
import xyz.jonesdev.sonar.common.protocol.entity.EntityType;
|
||||
import xyz.jonesdev.sonar.common.protocol.item.ItemType;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.configuration.RegistryDataPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.configuration.UpdateTagsPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.login.LoginSuccessPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.play.*;
|
||||
import xyz.jonesdev.sonar.common.util.ComponentHolder;
|
||||
|
||||
import java.io.File;
|
||||
@@ -45,14 +48,14 @@ import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
@UtilityClass
|
||||
public class FallbackPreparer {
|
||||
public class SonarPacketPreparer {
|
||||
private final Random RANDOM = new Random();
|
||||
|
||||
public static final int PLAYER_ENTITY_ID = RANDOM.nextInt();
|
||||
public static final int VEHICLE_ENTITY_ID = RANDOM.nextInt();
|
||||
|
||||
public static final BlockType[] POSSIBLE_BLOCK_TYPES = BlockType.values();
|
||||
public final FallbackPacket[] BLOCKS_PACKETS = new FallbackPacket[POSSIBLE_BLOCK_TYPES.length];
|
||||
public final SonarPacket[] BLOCKS_PACKETS = new SonarPacket[POSSIBLE_BLOCK_TYPES.length];
|
||||
|
||||
public final int BLOCKS_PER_ROW = 8; // 8 * 8 = 64 (vanilla protocol maximum)
|
||||
public final int SPAWN_X_POSITION = 16 / 2; // middle of the chunk
|
||||
@@ -66,68 +69,74 @@ public class FallbackPreparer {
|
||||
|
||||
private final int MAP_SLOT = RANDOM.nextInt(9);
|
||||
|
||||
public static final FallbackPacket CAPTCHA_SET_CONTAINER_SLOT = new SetContainerSlotPacket(
|
||||
public static final SonarPacket CAPTCHA_SET_CONTAINER_SLOT = new SetContainerSlotPacket(
|
||||
0, 36 + MAP_SLOT, 1, ItemType.FILLED_MAP, CompoundBinaryTag.builder()
|
||||
.put("map", IntBinaryTag.intBinaryTag(0)) // map id
|
||||
.build());
|
||||
public final static FallbackPacket CAPTCHA_HELD_ITEM_SLOT = new SetHeldItemPacket(MAP_SLOT);
|
||||
public final FallbackPacket DEFAULT_ABILITIES = new PlayerAbilitiesPacket(0x00, 0, 0);
|
||||
public final FallbackPacket NO_MOVE_ABILITIES = new PlayerAbilitiesPacket(0x02, 0, 0);
|
||||
public final FallbackPacket NO_MOVE_ABILITIES_BEDROCK = new PlayerAbilitiesPacket(0x06, 0, 0);
|
||||
public final FallbackPacket CAPTCHA_POSITION = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
public static final SonarPacket CAPTCHA_SET_CONTAINER_SLOT_OFFHAND = new SetContainerSlotPacket(
|
||||
0, 45, 1, ItemType.FILLED_MAP, CompoundBinaryTag.builder()
|
||||
.put("map", IntBinaryTag.intBinaryTag(0)) // map id
|
||||
.build());
|
||||
public final static SonarPacket CAPTCHA_HELD_ITEM_SLOT = new SetHeldItemPacket(MAP_SLOT);
|
||||
public final SonarPacket DEFAULT_ABILITIES = new PlayerAbilitiesPacket(0x00, 0, 0);
|
||||
public final SonarPacket NO_MOVE_ABILITIES = new PlayerAbilitiesPacket(0x02, 0, 0);
|
||||
public final SonarPacket NO_MOVE_ABILITIES_BEDROCK = new PlayerAbilitiesPacket(0x06, 0, 0);
|
||||
public final SonarPacket CAPTCHA_POSITION = new SonarPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, 10000, SPAWN_Z_POSITION, 0, 90, 0, 0, false, false, true));
|
||||
// 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 SonarPacket[] EMPTY_CHUNK_DATA = new SonarPacket[]{
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(0, 0)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(0, 1)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(0, -1)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(1, 0)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(1, 1)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(1, -1)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(-1, 0)),
|
||||
new SonarPacketSnapshot(new ChunkDataPacket(-1, 1)),
|
||||
new SonarPacketSnapshot(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))};
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20_5);
|
||||
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()));
|
||||
public static final FallbackPacket SPAWN_BOAT_ENTITY = new FallbackPacketSnapshot(new SpawnEntityPacket(
|
||||
public final SonarPacket PRE_JOIN_KEEP_ALIVE = new SonarPacketSnapshot(new KeepAlivePacket(PRE_JOIN_KEEP_ALIVE_ID));
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_20 = new SonarPacket[] {
|
||||
new SonarPacketSnapshot(new RegistryDataPacket(DimensionRegistry.CODEC_1_20, null, null))};
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20_5);
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_21 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21);
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_21_2 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_2);
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_21_4 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_4);
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_21_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_5);
|
||||
public final SonarPacket[] REGISTRY_SYNC_1_21_11 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_11);
|
||||
public final SonarPacket[] REGISTRY_SYNC_26_1 = RegistryDataPacket.of(DimensionRegistry.CODEC_26_1);
|
||||
public final SonarPacket TAGS_UPDATE_26_1 = UpdateTagsPacket.of(DimensionRegistry.TAGS_26_1);
|
||||
public final SonarPacket START_WRITING_CHUNKS = new GameEventPacket(13, 0);
|
||||
public final static SonarPacket INVALID_HELD_ITEM_SLOT = new SetHeldItemPacket(-1);
|
||||
public final SonarPacket RANDOM_KEEP_ALIVE = new SonarPacketSnapshot(new KeepAlivePacket(RANDOM.nextInt()));
|
||||
public static final SonarPacket SPAWN_BOAT_ENTITY = new SonarPacketSnapshot(new SpawnEntityPacket(
|
||||
VEHICLE_ENTITY_ID, EntityType.BOAT, SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
|
||||
0, 0, 0, 0));
|
||||
public static final FallbackPacket SPAWN_MINECART_ENTITY = new FallbackPacketSnapshot(new SpawnEntityPacket(
|
||||
public static final SonarPacket SPAWN_MINECART_ENTITY = new SonarPacketSnapshot(new SpawnEntityPacket(
|
||||
VEHICLE_ENTITY_ID, EntityType.MINECART, SPAWN_X_POSITION, IN_AIR_Y_POSITION - 16, SPAWN_Z_POSITION,
|
||||
0, 0, 0, 0));
|
||||
public static final FallbackPacket REMOVE_VEHICLE = new RemoveEntitiesPacket(VEHICLE_ENTITY_ID);
|
||||
public static final FallbackPacket SET_VEHICLE_PASSENGERS = new FallbackPacketSnapshot(
|
||||
public static final SonarPacket REMOVE_VEHICLE = new RemoveEntitiesPacket(VEHICLE_ENTITY_ID);
|
||||
public static final SonarPacket SET_VEHICLE_PASSENGERS = new SonarPacketSnapshot(
|
||||
new SetPassengersPacket(VEHICLE_ENTITY_ID, PLAYER_ENTITY_ID));
|
||||
public FallbackPacket[] incorrectCaptcha;
|
||||
public SonarPacket[] incorrectCaptcha;
|
||||
|
||||
public FallbackPacket loginSuccess;
|
||||
public FallbackPacket welcomeMessage;
|
||||
public FallbackPacket enterCodeMessage;
|
||||
public static FallbackPacket joinGame;
|
||||
public FallbackPacket defaultSpawnPosition;
|
||||
public FallbackPacket spawnPosition;
|
||||
public FallbackPacket fallStartPosition;
|
||||
public FallbackPacket fallStartPositionLegacy;
|
||||
public static FallbackPacket transferToOrigin;
|
||||
public FallbackPacket blacklisted;
|
||||
public FallbackPacket alreadyQueued;
|
||||
public FallbackPacket alreadyVerifying;
|
||||
public FallbackPacket reconnectedTooFast;
|
||||
public FallbackPacket protocolBlacklisted;
|
||||
public FallbackPacket unsupportedVersion;
|
||||
public FallbackPacket tooManyOnlinePerIP;
|
||||
public FallbackPacket[] xpCountdown;
|
||||
public FallbackPacket updateTime;
|
||||
public SonarPacket loginSuccess;
|
||||
public SonarPacket welcomeMessage;
|
||||
public SonarPacket enterCodeMessage;
|
||||
public static SonarPacket joinGame;
|
||||
public SonarPacket defaultSpawnPosition;
|
||||
public SonarPacket spawnPosition;
|
||||
public SonarPacket fallStartPosition;
|
||||
public SonarPacket fallStartPositionLegacy;
|
||||
public SonarPacket blacklisted;
|
||||
public SonarPacket alreadyQueued;
|
||||
public SonarPacket alreadyVerifying;
|
||||
public SonarPacket reconnectedTooFast;
|
||||
public SonarPacket protocolBlacklisted;
|
||||
public SonarPacket unsupportedVersion;
|
||||
public SonarPacket tooManyOnlinePerIP;
|
||||
public SonarPacket[] xpCountdown;
|
||||
public SonarPacket updateTime;
|
||||
|
||||
public static int maxMovementTick, dynamicSpawnYPosition, maxTotalPacketsSent;
|
||||
|
||||
@@ -135,7 +144,7 @@ public class FallbackPreparer {
|
||||
// Preload the packet registry to avoid CPU/RAM issues on 1st connection
|
||||
Sonar.get0().getLogger().info("Preloading all registered packets...");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
FallbackPacketRegistry.values();
|
||||
SonarPacketRegistry.values();
|
||||
|
||||
// Prepare LoginSuccess packet with capped username to 16 characters
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
@@ -143,10 +152,10 @@ public class FallbackPreparer {
|
||||
if (username.length() > 16) {
|
||||
username = username.substring(0, 16);
|
||||
}
|
||||
loginSuccess = new FallbackPacketSnapshot(new LoginSuccessPacket(uuid, username, true));
|
||||
loginSuccess = new SonarPacketSnapshot(new LoginSuccessPacket(uuid, username, true));
|
||||
|
||||
// Prepare JoinGame packet
|
||||
joinGame = new FallbackPacketSnapshot(new JoinGamePacket(PLAYER_ENTITY_ID,
|
||||
joinGame = new SonarPacketSnapshot(new JoinGamePacket(PLAYER_ENTITY_ID,
|
||||
Sonar.get0().getConfig().getVerification().getGamemode().getId(),
|
||||
-1, 0, 0,
|
||||
RANDOM.nextInt(3), 1, 0, 0,
|
||||
@@ -167,15 +176,16 @@ 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(
|
||||
defaultSpawnPosition = new SonarPacketSnapshot(new SetDefaultSpawnPositionPacket(
|
||||
"minecraft:overworld",
|
||||
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION));
|
||||
spawnPosition = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
spawnPosition = new SonarPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
|
||||
0, 0, FIRST_TELEPORT_ID, 0, false, false, true));
|
||||
fallStartPosition = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
fallStartPosition = new SonarPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, dynamicSpawnYPosition - IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
|
||||
0, -90, SECOND_TELEPORT_ID, 1 << 1, false, false, true));
|
||||
fallStartPositionLegacy = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
fallStartPositionLegacy = new SonarPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, dynamicSpawnYPosition, SPAWN_Z_POSITION,
|
||||
0, -90, 0, 0, false, false, true));
|
||||
|
||||
@@ -192,26 +202,17 @@ public class FallbackPreparer {
|
||||
blocks[index++] = new BlockUpdate(position, POSSIBLE_BLOCK_TYPES[i]);
|
||||
}
|
||||
}
|
||||
BLOCKS_PACKETS[i] = new FallbackPacketSnapshot(new UpdateSectionBlocksPacket(0, 0, blocks));
|
||||
BLOCKS_PACKETS[i] = new SonarPacketSnapshot(new UpdateSectionBlocksPacket(0, 0, blocks));
|
||||
}
|
||||
|
||||
// Prepare disconnect packets during login
|
||||
blacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getBlacklisted(), true));
|
||||
alreadyVerifying = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getAlreadyVerifying(), true));
|
||||
alreadyQueued = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
unsupportedVersion = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getUnsupportedVersion(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getTooManyOnlinePerIp(), true));
|
||||
|
||||
// Prepare transfer packet
|
||||
if (Sonar.get0().getConfig().getGeneralConfig().getBoolean("verification.transfer.enabled")) {
|
||||
transferToOrigin = new FallbackPacketSnapshot(new TransferPacket(
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("verification.transfer.destination-host"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getInt("verification.transfer.destination-port")));
|
||||
} else {
|
||||
transferToOrigin = null;
|
||||
}
|
||||
blacklisted = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getBlacklisted(), true));
|
||||
alreadyVerifying = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getAlreadyVerifying(), true));
|
||||
alreadyQueued = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
unsupportedVersion = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getUnsupportedVersion(), true));
|
||||
tooManyOnlinePerIP = new SonarPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getTooManyOnlinePerIp(), true));
|
||||
|
||||
// Prepare update time packet
|
||||
final int timeOfDay = Sonar.get0().getConfig().getVerification().getTimeOfDay();
|
||||
@@ -226,70 +227,85 @@ public class FallbackPreparer {
|
||||
if (welcome.isEmpty()) {
|
||||
welcomeMessage = null;
|
||||
} else {
|
||||
welcomeMessage = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
welcomeMessage = new SonarPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
MiniMessage.miniMessage().deserialize(welcome,
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
|
||||
}
|
||||
|
||||
if (Sonar.get0().getConfig().getVerification().getMap().getTiming() != SonarConfiguration.Verification.Timing.NEVER
|
||||
|| Sonar.get0().getConfig().getVerification().getGravity().isCaptchaOnFail()) {
|
||||
// Prepare CAPTCHA messages
|
||||
enterCodeMessage = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
enterCodeMessage = new SonarPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("verification.captcha.enter"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
|
||||
incorrectCaptcha = new FallbackPacket[Sonar.get0().getConfig().getVerification().getMap().getMaxTries()];
|
||||
incorrectCaptcha = new SonarPacket[Sonar.get0().getConfig().getVerification().getMap().getMaxTries()];
|
||||
for (int i = 0; i < incorrectCaptcha.length; i++) {
|
||||
incorrectCaptcha[i] = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
incorrectCaptcha[i] = new SonarPacketSnapshot(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];
|
||||
xpCountdown = new SonarPacket[Sonar.get0().getConfig().getVerification().getMap().getMaxDuration() / 1000];
|
||||
|
||||
for (int i = 0; i < xpCountdown.length; i++) {
|
||||
final float bar = (float) i / xpCountdown.length;
|
||||
xpCountdown[i] = new FallbackPacketSnapshot(new SetExperiencePacket(bar, i, 0));
|
||||
xpCountdown[i] = new SonarPacketSnapshot(new SetExperiencePacket(bar, i, 0));
|
||||
}
|
||||
|
||||
// Update the CAPTCHA generator if necessary
|
||||
final CaptchaGenerationStartEvent generationStartEvent = new CaptchaGenerationStartEvent(
|
||||
Sonar.get0().getFallback().getCaptchaGenerator());
|
||||
Sonar.get0().getAntiBot().getCaptchaGenerator());
|
||||
Sonar.get0().getEventManager().publish(generationStartEvent);
|
||||
|
||||
if (generationStartEvent.getCaptchaGenerator() == null
|
||||
|| generationStartEvent.getCaptchaGenerator() instanceof StandardCaptchaGenerator
|
||||
|| generationStartEvent.getCaptchaGenerator() instanceof LegacyCaptchaGenerator) {
|
||||
|| generationStartEvent.getCaptchaGenerator() instanceof LegacyCaptchaGenerator
|
||||
|| generationStartEvent.getCaptchaGenerator() instanceof ComplexCaptchaGenerator) {
|
||||
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));
|
||||
switch (Sonar.get0().getConfig().getGeneralConfig()
|
||||
.getString("verification.checks.map-captcha.style").toLowerCase()) {
|
||||
case "legacy":
|
||||
Sonar.get0().getAntiBot().setCaptchaGenerator(new LegacyCaptchaGenerator(backgroundImage));
|
||||
break;
|
||||
case "complex":
|
||||
Sonar.get0().getAntiBot().setCaptchaGenerator(new ComplexCaptchaGenerator(backgroundImage));
|
||||
break;
|
||||
default:
|
||||
Sonar.get0().getAntiBot().setCaptchaGenerator(new StandardCaptchaGenerator(backgroundImage));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Sonar.get0().getLogger().info("Custom CAPTCHA generator detected, skipping reinitialization.");
|
||||
}
|
||||
|
||||
// Prepare CAPTCHA answers
|
||||
CaptchaPreparer.prepare();
|
||||
} else {
|
||||
// Throw away if not needed
|
||||
enterCodeMessage = null;
|
||||
incorrectCaptcha = null;
|
||||
xpCountdown = null;
|
||||
Sonar.get0().getFallback().setCaptchaGenerator(null);
|
||||
Sonar.get0().getAntiBot().setCaptchaGenerator(null);
|
||||
}
|
||||
|
||||
maxTotalPacketsSent = maxMovementTick + 2
|
||||
+ (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_5)) {
|
||||
public static @Nullable SonarPacket getTagsPacket(final @NotNull ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
|
||||
return TAGS_UPDATE_26_1;
|
||||
}
|
||||
return null; // apparently doesn't crash the client; we're safe... for now.
|
||||
}
|
||||
|
||||
public static SonarPacket[] getRegistryPackets(final @NotNull ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
|
||||
return REGISTRY_SYNC_26_1;
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_11)) {
|
||||
return REGISTRY_SYNC_1_21_11;
|
||||
} else 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;
|
||||
+105
-53
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import io.netty.util.collection.IntObjectHashMap;
|
||||
import io.netty.util.collection.IntObjectMap;
|
||||
@@ -23,14 +23,15 @@ import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
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.handshake.HandshakePacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginAcknowledgedPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginStartPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginSuccessPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.*;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.configuration.FinishConfigurationPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.configuration.RegistryDataPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.configuration.UpdateTagsPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.handshake.HandshakePacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.login.LoginAcknowledgedPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.login.LoginStartPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.login.LoginSuccessPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.play.*;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
@@ -38,10 +39,10 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion.*;
|
||||
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
|
||||
public enum FallbackPacketRegistry {
|
||||
public enum SonarPacketRegistry {
|
||||
HANDSHAKE {
|
||||
{
|
||||
serverbound.register(HandshakePacket.class, HandshakePacket::new,
|
||||
@@ -75,6 +76,8 @@ public enum FallbackPacketRegistry {
|
||||
clientbound.register(RegistryDataPacket.class, RegistryDataPacket::new,
|
||||
map(0x05, MINECRAFT_1_20_2, true),
|
||||
map(0x07, MINECRAFT_1_20_5, true));
|
||||
clientbound.register(UpdateTagsPacket.class, UpdateTagsPacket::new,
|
||||
map(0x0D, MINECRAFT_1_20_5, true));
|
||||
|
||||
serverbound.register(ClientInformationPacket.class, ClientInformationPacket::new,
|
||||
map(0x00, MINECRAFT_1_20_2, false));
|
||||
@@ -108,7 +111,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x29, MINECRAFT_1_20_2, true),
|
||||
map(0x2B, MINECRAFT_1_20_5, true),
|
||||
map(0x2C, MINECRAFT_1_21_2, true),
|
||||
map(0x2B, MINECRAFT_1_21_5, true));
|
||||
map(0x2B, MINECRAFT_1_21_5, true),
|
||||
map(0x30, MINECRAFT_1_21_9, true),
|
||||
map(0x31, MINECRAFT_26_1, true));
|
||||
// minecraft:keep_alive
|
||||
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
|
||||
map(0x00, MINECRAFT_1_7_2, true),
|
||||
@@ -126,7 +131,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x24, MINECRAFT_1_20_2, true),
|
||||
map(0x26, MINECRAFT_1_20_5, true),
|
||||
map(0x27, MINECRAFT_1_21_2, true),
|
||||
map(0x26, MINECRAFT_1_21_5, true));
|
||||
map(0x26, MINECRAFT_1_21_5, true),
|
||||
map(0x2B, MINECRAFT_1_21_9, true),
|
||||
map(0x2C, MINECRAFT_26_1, true));
|
||||
// minecraft:disconnect
|
||||
clientbound.register(DisconnectPacket.class, DisconnectPacket::new,
|
||||
map(0x40, MINECRAFT_1_7_2, true),
|
||||
@@ -143,7 +150,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x1A, MINECRAFT_1_19_4, true),
|
||||
map(0x1B, MINECRAFT_1_20_2, true),
|
||||
map(0x1D, MINECRAFT_1_20_5, true),
|
||||
map(0x1C, MINECRAFT_1_21_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),
|
||||
@@ -162,7 +170,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x3E, MINECRAFT_1_20_2, true),
|
||||
map(0x40, MINECRAFT_1_20_5, true),
|
||||
map(0x42, MINECRAFT_1_21_2, true),
|
||||
map(0x41, MINECRAFT_1_21_5, true));
|
||||
map(0x41, MINECRAFT_1_21_5, true),
|
||||
map(0x46, MINECRAFT_1_21_9, true),
|
||||
map(0x48, MINECRAFT_26_1, true));
|
||||
// minecraft:player_abilities
|
||||
clientbound.register(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new,
|
||||
map(0x39, MINECRAFT_1_7_2, true),
|
||||
@@ -181,7 +191,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x36, MINECRAFT_1_20_2, true),
|
||||
map(0x38, MINECRAFT_1_20_5, true),
|
||||
map(0x3A, MINECRAFT_1_21_2, true),
|
||||
map(0x39, MINECRAFT_1_21_5, true));
|
||||
map(0x39, MINECRAFT_1_21_5, true),
|
||||
map(0x3E, MINECRAFT_1_21_9, true),
|
||||
map(0x40, MINECRAFT_26_1, true));
|
||||
// minecraft:level_chunk_with_light
|
||||
clientbound.register(ChunkDataPacket.class, ChunkDataPacket::new,
|
||||
map(0x21, MINECRAFT_1_7_2, true),
|
||||
@@ -199,7 +211,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x25, MINECRAFT_1_20_2, true),
|
||||
map(0x27, MINECRAFT_1_20_5, true),
|
||||
map(0x28, MINECRAFT_1_21_2, true),
|
||||
map(0x27, MINECRAFT_1_21_5, true));
|
||||
map(0x27, MINECRAFT_1_21_5, true),
|
||||
map(0x2C, MINECRAFT_1_21_9, true),
|
||||
map(0x2D, MINECRAFT_26_1, true));
|
||||
// minecraft:remove_entities
|
||||
clientbound.register(RemoveEntitiesPacket.class, RemoveEntitiesPacket::new,
|
||||
map(0x13, MINECRAFT_1_7_2, true),
|
||||
@@ -220,7 +234,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x40, MINECRAFT_1_20_2, true),
|
||||
map(0x42, MINECRAFT_1_20_5, true),
|
||||
map(0x47, MINECRAFT_1_21_2, true),
|
||||
map(0x46, MINECRAFT_1_21_5, true));
|
||||
map(0x46, MINECRAFT_1_21_5, true),
|
||||
map(0x4B, MINECRAFT_1_21_9, true),
|
||||
map(0x4D, MINECRAFT_26_1, true));
|
||||
// minecraft:set_passengers
|
||||
clientbound.register(SetPassengersPacket.class, SetPassengersPacket::new,
|
||||
map(0x1B, MINECRAFT_1_7_2, true),
|
||||
@@ -238,7 +254,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x5D, MINECRAFT_1_20_3, true),
|
||||
map(0x5F, MINECRAFT_1_20_5, true),
|
||||
map(0x65, MINECRAFT_1_21_2, true),
|
||||
map(0x64, MINECRAFT_1_21_5, true));
|
||||
map(0x64, MINECRAFT_1_21_5, true),
|
||||
map(0x69, MINECRAFT_1_21_9, true),
|
||||
map(0x6B, MINECRAFT_26_1, true));
|
||||
// minecraft:add_entity
|
||||
clientbound.register(SpawnEntityPacket.class, SpawnEntityPacket::new,
|
||||
map(0x0E, MINECRAFT_1_7_2, true),
|
||||
@@ -261,7 +279,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x47, MINECRAFT_1_20_3, true),
|
||||
map(0x49, MINECRAFT_1_20_5, true),
|
||||
map(0x4E, MINECRAFT_1_21_2, true),
|
||||
map(0x4D, MINECRAFT_1_21_5, true));
|
||||
map(0x4D, MINECRAFT_1_21_5, true),
|
||||
map(0x52, MINECRAFT_1_21_9, true),
|
||||
map(0x54, MINECRAFT_26_1, true));
|
||||
// minecraft:ping
|
||||
clientbound.register(TransactionPacket.class, TransactionPacket::new,
|
||||
map(0x32, MINECRAFT_1_7_2, true),
|
||||
@@ -278,7 +298,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x33, MINECRAFT_1_20_2, true),
|
||||
map(0x35, MINECRAFT_1_20_5, true),
|
||||
map(0x37, MINECRAFT_1_21_2, true),
|
||||
map(0x36, MINECRAFT_1_21_5, true));
|
||||
map(0x36, MINECRAFT_1_21_5, true),
|
||||
map(0x3B, MINECRAFT_1_21_9, true),
|
||||
map(0x3D, MINECRAFT_26_1, true));
|
||||
// minecraft:set_default_spawn_position
|
||||
clientbound.register(SetDefaultSpawnPositionPacket.class, SetDefaultSpawnPositionPacket::new,
|
||||
map(0x05, MINECRAFT_1_7_2, true),
|
||||
@@ -298,7 +320,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x54, MINECRAFT_1_20_3, true),
|
||||
map(0x56, MINECRAFT_1_20_5, true),
|
||||
map(0x5B, MINECRAFT_1_21_2, true),
|
||||
map(0x5A, MINECRAFT_1_21_5, true));
|
||||
map(0x5A, MINECRAFT_1_21_5, true),
|
||||
map(0x5F, MINECRAFT_1_21_9, true),
|
||||
map(0x61, MINECRAFT_26_1, true));
|
||||
// minecraft:map_item_data
|
||||
clientbound.register(MapDataPacket.class, MapDataPacket::new,
|
||||
map(0x34, MINECRAFT_1_7_2, true),
|
||||
@@ -315,7 +339,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x2A, MINECRAFT_1_20_2, true),
|
||||
map(0x2C, MINECRAFT_1_20_5, true),
|
||||
map(0x2D, MINECRAFT_1_21_2, true),
|
||||
map(0x2C, MINECRAFT_1_21_5, true));
|
||||
map(0x2C, MINECRAFT_1_21_5, true),
|
||||
map(0x31, MINECRAFT_1_21_9, true),
|
||||
map(0x33, MINECRAFT_26_1, true));
|
||||
// minecraft:container_set_slot
|
||||
clientbound.register(SetContainerSlotPacket.class, SetContainerSlotPacket::new,
|
||||
map(0x2F, MINECRAFT_1_7_2, true),
|
||||
@@ -348,7 +374,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x5A, MINECRAFT_1_20_3, true),
|
||||
map(0x5C, MINECRAFT_1_20_5, true),
|
||||
map(0x61, MINECRAFT_1_21_2, true),
|
||||
map(0x60, MINECRAFT_1_21_5, true));
|
||||
map(0x60, MINECRAFT_1_21_5, true),
|
||||
map(0x65, MINECRAFT_1_21_9, true),
|
||||
map(0x67, MINECRAFT_26_1, true));
|
||||
// minecraft:system_chat
|
||||
clientbound.register(SystemChatPacket.class, SystemChatPacket::new,
|
||||
map(0x02, MINECRAFT_1_7_2, true),
|
||||
@@ -365,17 +393,22 @@ public enum FallbackPacketRegistry {
|
||||
map(0x69, MINECRAFT_1_20_3, true),
|
||||
map(0x6C, MINECRAFT_1_20_5, true),
|
||||
map(0x73, MINECRAFT_1_21_2, true),
|
||||
map(0x72, MINECRAFT_1_21_5, true));
|
||||
map(0x72, MINECRAFT_1_21_5, true),
|
||||
map(0x77, MINECRAFT_1_21_9, true),
|
||||
map(0x79, MINECRAFT_26_1, true));
|
||||
// minecraft:game_event
|
||||
clientbound.register(GameEventPacket.class, GameEventPacket::new,
|
||||
map(0x20, MINECRAFT_1_20_3, true),
|
||||
map(0x22, MINECRAFT_1_20_5, true),
|
||||
map(0x23, MINECRAFT_1_21_2, true),
|
||||
map(0x22, MINECRAFT_1_21_5, true));
|
||||
map(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),
|
||||
map(0x81, MINECRAFT_26_1, true));
|
||||
// minecraft:set_held_slot
|
||||
clientbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
|
||||
map(0x09, MINECRAFT_1_7_2, true),
|
||||
@@ -395,7 +428,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x51, MINECRAFT_1_20_3, true),
|
||||
map(0x53, MINECRAFT_1_20_5, true),
|
||||
map(0x63, MINECRAFT_1_21_2, true),
|
||||
map(0x62, MINECRAFT_1_21_5, true));
|
||||
map(0x62, MINECRAFT_1_21_5, true),
|
||||
map(0x67, MINECRAFT_1_21_9, true),
|
||||
map(0x69, MINECRAFT_26_1, true));
|
||||
// minecraft:animate
|
||||
clientbound.register(EntityAnimationPacket.class, EntityAnimationPacket::new,
|
||||
map(0x0B, MINECRAFT_1_7_2, true),
|
||||
@@ -425,12 +460,15 @@ public enum FallbackPacketRegistry {
|
||||
map(0x62, MINECRAFT_1_20_3, true),
|
||||
map(0x64, MINECRAFT_1_20_5, true),
|
||||
map(0x6B, MINECRAFT_1_21_2, true),
|
||||
map(0x6A, MINECRAFT_1_21_5, true));
|
||||
map(0x6A, MINECRAFT_1_21_5, true),
|
||||
map(0x6F, MINECRAFT_1_21_9, true),
|
||||
map(0x71, MINECRAFT_26_1, true));
|
||||
|
||||
// minecraft:client_tick_end
|
||||
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
|
||||
map(0x0B, MINECRAFT_1_21_2, false),
|
||||
map(0x0C, MINECRAFT_1_21_6, false));
|
||||
map(0x0C, MINECRAFT_1_21_6, false),
|
||||
map(0x0D, MINECRAFT_26_1, false));
|
||||
// minecraft:set_carried_item
|
||||
serverbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
|
||||
map(0x09, MINECRAFT_1_7_2, false),
|
||||
@@ -447,7 +485,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x2F, MINECRAFT_1_20_5, false),
|
||||
map(0x31, MINECRAFT_1_21_2, false),
|
||||
map(0x33, MINECRAFT_1_21_4, false),
|
||||
map(0x34, MINECRAFT_1_21_6, false));
|
||||
map(0x34, MINECRAFT_1_21_6, false),
|
||||
map(0x35, MINECRAFT_26_1, false));
|
||||
// minecraft:paddle_boat
|
||||
serverbound.register(PaddleBoatPacket.class, PaddleBoatPacket::new,
|
||||
map(0x11, MINECRAFT_1_9, false),
|
||||
@@ -465,7 +504,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x1C, MINECRAFT_1_20_3, false),
|
||||
map(0x1F, MINECRAFT_1_20_5, false),
|
||||
map(0x21, MINECRAFT_1_21_2, false),
|
||||
map(0x22, MINECRAFT_1_21_6, false));
|
||||
map(0x22, MINECRAFT_1_21_6, false),
|
||||
map(0x23, MINECRAFT_26_1, false));
|
||||
// minecraft:player_input
|
||||
serverbound.register(PlayerInputPacket.class, PlayerInputPacket::new,
|
||||
map(0x0C, MINECRAFT_1_7_2, false),
|
||||
@@ -484,7 +524,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x26, MINECRAFT_1_20_5, false),
|
||||
map(0x28, MINECRAFT_1_21_2, false),
|
||||
map(0x29, MINECRAFT_1_21_4, false),
|
||||
map(0x2A, MINECRAFT_1_21_6, false));
|
||||
map(0x2A, MINECRAFT_1_21_6, false),
|
||||
map(0x26, MINECRAFT_26_1, false));
|
||||
// minecraft:move_vehicle
|
||||
serverbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
|
||||
map(0x10, MINECRAFT_1_9, false),
|
||||
@@ -502,7 +543,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x1B, MINECRAFT_1_20_3, false),
|
||||
map(0x1E, MINECRAFT_1_20_5, false),
|
||||
map(0x20, MINECRAFT_1_21_2, false),
|
||||
map(0x21, MINECRAFT_1_21_6, false));
|
||||
map(0x21, MINECRAFT_1_21_6, false),
|
||||
map(0x22, MINECRAFT_26_1, false));
|
||||
// minecraft:chat
|
||||
serverbound.register(SystemChatPacket.class, SystemChatPacket::new,
|
||||
map(0x01, MINECRAFT_1_7_2, false),
|
||||
@@ -515,7 +557,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x05, MINECRAFT_1_19_3, false),
|
||||
map(0x06, MINECRAFT_1_20_5, false),
|
||||
map(0x07, MINECRAFT_1_21_2, false),
|
||||
map(0x08, MINECRAFT_1_21_6, false));
|
||||
map(0x08, MINECRAFT_1_21_6, false),
|
||||
map(0x09, MINECRAFT_26_1, false));
|
||||
// minecraft:keep_alive
|
||||
serverbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
|
||||
map(0x00, MINECRAFT_1_7_2, false),
|
||||
@@ -534,7 +577,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x15, MINECRAFT_1_20_3, false),
|
||||
map(0x18, MINECRAFT_1_20_5, false),
|
||||
map(0x1A, MINECRAFT_1_21_2, false),
|
||||
map(0x1B, MINECRAFT_1_21_6, false));
|
||||
map(0x1B, MINECRAFT_1_21_6, false),
|
||||
map(0x1C, MINECRAFT_26_1, false));
|
||||
// minecraft:client_information
|
||||
serverbound.register(ClientInformationPacket.class, ClientInformationPacket::new,
|
||||
map(0x15, MINECRAFT_1_7_2, false),
|
||||
@@ -549,7 +593,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x09, MINECRAFT_1_20_2, false),
|
||||
map(0x0A, MINECRAFT_1_20_5, false),
|
||||
map(0x0C, MINECRAFT_1_21_2, false),
|
||||
map(0x0D, MINECRAFT_1_21_6, false));
|
||||
map(0x0D, MINECRAFT_1_21_6, false),
|
||||
map(0x0E, MINECRAFT_26_1, false));
|
||||
// minecraft:custom_payload
|
||||
serverbound.register(PluginMessagePacket.class, PluginMessagePacket::new,
|
||||
map(0x17, MINECRAFT_1_7_2, false),
|
||||
@@ -566,7 +611,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x0F, MINECRAFT_1_20_2, false),
|
||||
map(0x12, MINECRAFT_1_21, false),
|
||||
map(0x14, MINECRAFT_1_21_2, false),
|
||||
map(0x15, MINECRAFT_1_21_6, false));
|
||||
map(0x15, MINECRAFT_1_21_6, false),
|
||||
map(0x16, MINECRAFT_26_1, false));
|
||||
// minecraft:move_player_status_only
|
||||
serverbound.register(SetPlayerOnGround.class, SetPlayerOnGround::new,
|
||||
map(0x03, MINECRAFT_1_7_2, false),
|
||||
@@ -585,7 +631,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x1A, MINECRAFT_1_20_3, false),
|
||||
map(0x1D, MINECRAFT_1_20_5, false),
|
||||
map(0x1F, MINECRAFT_1_21_2, false),
|
||||
map(0x20, MINECRAFT_1_21_6, false));
|
||||
map(0x20, MINECRAFT_1_21_6, false),
|
||||
map(0x21, MINECRAFT_26_1, false));
|
||||
// minecraft:move_player_pos
|
||||
serverbound.register(SetPlayerPositionPacket.class, SetPlayerPositionPacket::new,
|
||||
map(0x04, MINECRAFT_1_7_2, false),
|
||||
@@ -604,7 +651,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x17, MINECRAFT_1_20_3, false),
|
||||
map(0x1A, MINECRAFT_1_20_5, false),
|
||||
map(0x1C, MINECRAFT_1_21_2, false),
|
||||
map(0x1D, MINECRAFT_1_21_6, false));
|
||||
map(0x1D, MINECRAFT_1_21_6, false),
|
||||
map(0x1E, MINECRAFT_26_1, false));
|
||||
// minecraft:move_player_rot
|
||||
serverbound.register(SetPlayerRotationPacket.class, SetPlayerRotationPacket::new,
|
||||
map(0x05, MINECRAFT_1_7_2, false),
|
||||
@@ -623,7 +671,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x19, MINECRAFT_1_20_3, false),
|
||||
map(0x1C, MINECRAFT_1_20_5, false),
|
||||
map(0x1E, MINECRAFT_1_21_2, false),
|
||||
map(0x1F, MINECRAFT_1_21_6, false));
|
||||
map(0x1F, MINECRAFT_1_21_6, false),
|
||||
map(0x20, MINECRAFT_26_1, false));
|
||||
// minecraft:move_player_pos_rot
|
||||
serverbound.register(SetPlayerPositionRotationPacket.class, SetPlayerPositionRotationPacket::new,
|
||||
map(0x06, MINECRAFT_1_7_2, false),
|
||||
@@ -642,7 +691,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x18, MINECRAFT_1_20_3, false),
|
||||
map(0x1B, MINECRAFT_1_20_5, false),
|
||||
map(0x1D, MINECRAFT_1_21_2, false),
|
||||
map(0x1E, MINECRAFT_1_21_6, false));
|
||||
map(0x1E, MINECRAFT_1_21_6, false),
|
||||
map(0x1F, MINECRAFT_26_1, false));
|
||||
// minecraft:accept_teleportation
|
||||
serverbound.register(ConfirmTeleportationPacket.class, ConfirmTeleportationPacket::new,
|
||||
map(0x00, MINECRAFT_1_9, false));
|
||||
@@ -664,7 +714,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x27, MINECRAFT_1_20_5, false),
|
||||
map(0x29, MINECRAFT_1_21_2, false),
|
||||
map(0x2B, MINECRAFT_1_21_4, false),
|
||||
map(0x2C, MINECRAFT_1_21_6, false));
|
||||
map(0x2C, MINECRAFT_1_21_6, false),
|
||||
map(0x2D, MINECRAFT_26_1, false));
|
||||
// minecraft:swing
|
||||
serverbound.register(AnimationPacket.class, AnimationPacket::new,
|
||||
map(0x0A, MINECRAFT_1_7_2, false),
|
||||
@@ -682,7 +733,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x38, MINECRAFT_1_21_2, false),
|
||||
map(0x3A, MINECRAFT_1_21_4, false),
|
||||
map(0x3B, MINECRAFT_1_21_5, false),
|
||||
map(0x3C, MINECRAFT_1_21_6, false));
|
||||
map(0x3C, MINECRAFT_1_21_6, false),
|
||||
map(0x3F, MINECRAFT_26_1, false));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -694,8 +746,8 @@ public enum FallbackPacketRegistry {
|
||||
CLIENTBOUND
|
||||
}
|
||||
|
||||
public FallbackPacketRegistry.ProtocolRegistry getProtocolRegistry(final Direction direction,
|
||||
final ProtocolVersion version) {
|
||||
public SonarPacketRegistry.ProtocolRegistry getProtocolRegistry(final Direction direction,
|
||||
final ProtocolVersion version) {
|
||||
return (direction == Direction.SERVERBOUND ? serverbound : clientbound).getProtocolRegistry(version);
|
||||
}
|
||||
|
||||
@@ -718,9 +770,9 @@ public enum FallbackPacketRegistry {
|
||||
return registry;
|
||||
}
|
||||
|
||||
private <T extends FallbackPacket> void register(final @NotNull Class<T> clazz,
|
||||
final @NotNull Supplier<T> supplier,
|
||||
final PacketMapping @NotNull ... mappings) {
|
||||
private <T extends SonarPacket> void register(final @NotNull Class<T> clazz,
|
||||
final @NotNull Supplier<T> supplier,
|
||||
final PacketMapping @NotNull ... mappings) {
|
||||
if (mappings.length == 0) {
|
||||
throw new IllegalArgumentException("At least one mapping must be provided.");
|
||||
}
|
||||
@@ -765,17 +817,17 @@ public enum FallbackPacketRegistry {
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class ProtocolRegistry {
|
||||
private final ProtocolVersion protocolVersion;
|
||||
private final IntObjectMap<Supplier<? extends FallbackPacket>> packetIdToSupplier =
|
||||
private final IntObjectMap<Supplier<? extends SonarPacket>> packetIdToSupplier =
|
||||
new IntObjectHashMap<>(16, 0.5f);
|
||||
private final Map<Class<? extends FallbackPacket>, Integer> packetClassToId =
|
||||
private final Map<Class<? extends SonarPacket>, Integer> packetClassToId =
|
||||
new HashMap<>(16, 0.5f);
|
||||
|
||||
public FallbackPacket createPacket(final int packetId) {
|
||||
public SonarPacket createPacket(final int packetId) {
|
||||
final var supplier = packetIdToSupplier.get(packetId);
|
||||
return supplier == null ? null : supplier.get();
|
||||
}
|
||||
|
||||
public int getPacketId(final @NotNull Class<? extends FallbackPacket> clazz) {
|
||||
public int getPacketId(final @NotNull Class<? extends SonarPacket> clazz) {
|
||||
final int packetId = packetClassToId.getOrDefault(clazz, -1);
|
||||
if (packetId == -1) {
|
||||
throw new IllegalArgumentException("Could not find packet ID for " + clazz.getSimpleName());
|
||||
+6
-6
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
package xyz.jonesdev.sonar.common.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
@@ -25,20 +25,20 @@ import io.netty.util.collection.IntObjectMap;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.ID_TO_PROTOCOL_CONSTANT;
|
||||
import static xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion.ID_TO_PROTOCOL_CONSTANT;
|
||||
|
||||
// https://github.com/Nan1t/NanoLimbo/blob/main/src/main/java/ua/nanit/limbo/protocol/PacketSnapshot.java
|
||||
public final class FallbackPacketSnapshot implements FallbackPacket {
|
||||
public final class SonarPacketSnapshot implements SonarPacket {
|
||||
private final IntObjectMap<Integer> mappings = new IntObjectHashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
private final IntObjectMap<byte[]> cachedBytes = new IntObjectHashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
@Getter
|
||||
private final Class<? extends FallbackPacket> originalPacketClass;
|
||||
private final Class<? extends SonarPacket> originalPacketClass;
|
||||
|
||||
public FallbackPacketSnapshot(final @NotNull FallbackPacket originalPacket) {
|
||||
public SonarPacketSnapshot(final @NotNull SonarPacket originalPacket) {
|
||||
this.originalPacketClass = originalPacket.getClass();
|
||||
|
||||
final IntObjectMap<Integer> hashedData = new IntObjectHashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
+52
-11
@@ -15,15 +15,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.block;
|
||||
package xyz.jonesdev.sonar.common.protocol.block;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion.*;
|
||||
|
||||
// TODO: load mappings from a separate file
|
||||
@Getter
|
||||
@@ -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;
|
||||
@@ -75,7 +74,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 8163;
|
||||
}
|
||||
return 8173;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 8173;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 9250;
|
||||
}
|
||||
return 9451;
|
||||
}, protocolVersion -> (double) 0.75f),
|
||||
TRAPDOOR(protocolVersion -> {
|
||||
// We have to use wooden trapdoors for 1.7 since 1.7 doesn't have iron trapdoors
|
||||
@@ -124,7 +129,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 11293;
|
||||
}
|
||||
return 11303;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 11303;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 12380;
|
||||
}
|
||||
return 12582;
|
||||
}, protocolVersion -> 0.1875),
|
||||
END_PORTAL_FRAME(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -166,7 +177,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 8185;
|
||||
}
|
||||
return 8195;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 8195;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 9272;
|
||||
}
|
||||
return 9473;
|
||||
}, protocolVersion -> 0.8125),
|
||||
DAYLIGHT_SENSOR(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -211,7 +228,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 10006;
|
||||
}
|
||||
return 10016;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 10016;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 11093;
|
||||
}
|
||||
return 11295;
|
||||
}, protocolVersion -> 0.375),
|
||||
COBBLESTONE_WALL(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -253,7 +276,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 8696;
|
||||
}
|
||||
return 8706;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 8706;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 9783;
|
||||
}
|
||||
return 9984;
|
||||
}, protocolVersion -> 1.5),
|
||||
STONE_SLABS(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -298,7 +327,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 12110;
|
||||
}
|
||||
return 12120;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 12120;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 13197;
|
||||
}
|
||||
return 13399;
|
||||
}, protocolVersion -> 0.5),
|
||||
WHITE_CARPET(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -343,7 +378,13 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 11607;
|
||||
}
|
||||
return 11617;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 11617;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 12694;
|
||||
}
|
||||
return 12896;
|
||||
}, protocolVersion -> protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 0 : 0.0625);
|
||||
|
||||
private final Function<ProtocolVersion, Integer> id;
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.block;
|
||||
package xyz.jonesdev.sonar.common.protocol.block;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
+7
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.dimension;
|
||||
package xyz.jonesdev.sonar.common.protocol.dimension;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
@@ -40,6 +40,9 @@ public final class DimensionRegistry {
|
||||
public final CompoundBinaryTag CODEC_1_21_2;
|
||||
public final CompoundBinaryTag CODEC_1_21_4;
|
||||
public final CompoundBinaryTag CODEC_1_21_5;
|
||||
public final CompoundBinaryTag CODEC_1_21_11;
|
||||
public final CompoundBinaryTag CODEC_26_1;
|
||||
public final CompoundBinaryTag TAGS_26_1;
|
||||
|
||||
static {
|
||||
CODEC_1_16 = getCodec("codec_1_16.nbt");
|
||||
@@ -54,6 +57,9 @@ public final class DimensionRegistry {
|
||||
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");
|
||||
CODEC_1_21_11 = getCodec("codec_1_21_11.nbt");
|
||||
CODEC_26_1 = getCodec("codec_26_1.nbt");
|
||||
TAGS_26_1 = getCodec("tags_26_1.nbt");
|
||||
}
|
||||
|
||||
private @NotNull CompoundBinaryTag getCodec(final @NotNull String fileName) {
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.dimension;
|
||||
package xyz.jonesdev.sonar.common.protocol.dimension;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
+17
-5
@@ -15,15 +15,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.entity;
|
||||
package xyz.jonesdev.sonar.common.protocol.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion.*;
|
||||
|
||||
// TODO: load mappings from a separate file
|
||||
@Getter
|
||||
@@ -61,7 +61,13 @@ public enum EntityType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_5)) {
|
||||
return 84;
|
||||
}
|
||||
return 85;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 85;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
|
||||
return 87;
|
||||
}
|
||||
return 89;
|
||||
}),
|
||||
MINECART(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
@@ -100,7 +106,13 @@ public enum EntityType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_5)) {
|
||||
return 81;
|
||||
}
|
||||
return 82;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 82;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
|
||||
return 84;
|
||||
}
|
||||
return 85;
|
||||
});
|
||||
|
||||
private final Function<ProtocolVersion, Integer> id;
|
||||
+17
-5
@@ -15,15 +15,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.item;
|
||||
package xyz.jonesdev.sonar.common.protocol.item;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion.*;
|
||||
|
||||
// TODO: load mappings from a separate file
|
||||
@Getter
|
||||
@@ -79,7 +79,13 @@ public enum ItemType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_5)) {
|
||||
return 1042;
|
||||
}
|
||||
return 1059;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_7)) {
|
||||
return 1059;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 1104;
|
||||
}
|
||||
return 1105;
|
||||
}, protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 26;
|
||||
@@ -87,7 +93,13 @@ public enum ItemType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_4)) {
|
||||
return 36;
|
||||
}
|
||||
return 37;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_9)) {
|
||||
return 37;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_11)) {
|
||||
return 44;
|
||||
}
|
||||
return 46;
|
||||
});
|
||||
|
||||
private final Function<ProtocolVersion, Integer> id;
|
||||
+10
-10
@@ -15,21 +15,21 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.map;
|
||||
package xyz.jonesdev.sonar.common.protocol.map;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.MapDataPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.SonarUser;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.packets.play.MapDataPacket;
|
||||
|
||||
@Getter
|
||||
public final class MapCaptchaInfo {
|
||||
private final String answer;
|
||||
|
||||
private final FallbackPacket[] legacy;
|
||||
private final FallbackPacket modern;
|
||||
private final SonarPacket[] legacy;
|
||||
private final SonarPacket modern;
|
||||
|
||||
public MapCaptchaInfo(final @NotNull String answer, final byte @NotNull [] buffer) {
|
||||
this.answer = answer;
|
||||
@@ -39,7 +39,7 @@ public final class MapCaptchaInfo {
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
grid[i & Byte.MAX_VALUE][i >> 7] = buffer[i];
|
||||
}
|
||||
this.legacy = new FallbackPacket[grid.length];
|
||||
this.legacy = new SonarPacket[grid.length];
|
||||
for (int i = 0; i < grid.length; i++) {
|
||||
this.legacy[i] = new MapDataPacket(grid[i], i, 0, 0, true);
|
||||
}
|
||||
@@ -48,10 +48,10 @@ public final class MapCaptchaInfo {
|
||||
this.modern = new MapDataPacket(buffer, 0, 0, 0, true);
|
||||
}
|
||||
|
||||
public void delayedWrite(final @NotNull FallbackUser user) {
|
||||
public void delayedWrite(final @NotNull SonarUser user) {
|
||||
if (user.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
// 1.7.2-1.7.10 needs separate packets for each axis
|
||||
for (final FallbackPacket packet : legacy) {
|
||||
for (final SonarPacket packet : legacy) {
|
||||
user.delayedWrite(packet);
|
||||
}
|
||||
return;
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.map;
|
||||
package xyz.jonesdev.sonar.common.protocol.map;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
+4
-4
@@ -15,16 +15,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration;
|
||||
package xyz.jonesdev.sonar.common.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;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class FinishConfigurationPacket implements FallbackPacket {
|
||||
public final class FinishConfigurationPacket implements SonarPacket {
|
||||
public static final FinishConfigurationPacket INSTANCE = new FinishConfigurationPacket();
|
||||
|
||||
@Override
|
||||
+8
-8
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.configuration;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.*;
|
||||
@@ -23,9 +23,9 @@ import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketSnapshot;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketSnapshot;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -34,7 +34,7 @@ import java.util.List;
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class RegistryDataPacket implements FallbackPacket {
|
||||
public final class RegistryDataPacket implements SonarPacket {
|
||||
private CompoundBinaryTag tag;
|
||||
private String type;
|
||||
private List<RegistryDataPacket.Bundle> bundles;
|
||||
@@ -66,8 +66,8 @@ public final class RegistryDataPacket implements FallbackPacket {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static FallbackPacket @NotNull [] of(final @NotNull CompoundBinaryTag rootTag) {
|
||||
final FallbackPacket[] packets = new FallbackPacket[rootTag.size()];
|
||||
public static SonarPacket @NotNull [] of(final @NotNull CompoundBinaryTag rootTag) {
|
||||
final SonarPacket[] packets = new SonarPacket[rootTag.size()];
|
||||
int index = 0;
|
||||
for (final String type : rootTag.keySet()) {
|
||||
final ArrayList<RegistryDataPacket.Bundle> bundles = new ArrayList<>();
|
||||
@@ -76,7 +76,7 @@ public final class RegistryDataPacket implements FallbackPacket {
|
||||
// CompoundBinaryTag#getCompound(String) will return an empty compound tag when not exist.
|
||||
bundles.add(new Bundle(tag.getString("name"), tag.get("element") == null ? null : tag.getCompound("element")));
|
||||
}
|
||||
packets[index++] = new FallbackPacketSnapshot(new RegistryDataPacket(rootTag, type, bundles));
|
||||
packets[index++] = new SonarPacketSnapshot(new RegistryDataPacket(rootTag, type, bundles));
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Jones Development
|
||||
*
|
||||
* All rights reserved.
|
||||
* This software is proprietary and cannot be copied, modified, or distributed without explicit permission.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.configuration;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.IntBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacketSnapshot;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
// If you want a decent solution, use Sonar 3.0 - I don't have the time to implement tags.
|
||||
//
|
||||
// Taken from
|
||||
// https://github.com/BoomEaro/NanoLimbo/blob/feature/1.21.2/src/main/java/ua/nanit/limbo/protocol/packets/configuration/PacketUpdateTags.java
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public final class UpdateTagsPacket implements SonarPacket {
|
||||
private Map<String, Map<String, List<Integer>>> tags;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
ProtocolUtil.writeVarInt(byteBuf, this.tags.size());
|
||||
for (Map.Entry<String, Map<String, List<Integer>>> entry : this.tags.entrySet()) {
|
||||
ProtocolUtil.writeString(byteBuf, entry.getKey());
|
||||
|
||||
Map<String, List<Integer>> subTags = entry.getValue();
|
||||
ProtocolUtil.writeVarInt(byteBuf, subTags.size());
|
||||
|
||||
for (Map.Entry<String, List<Integer>> subEntry : subTags.entrySet()) {
|
||||
ProtocolUtil.writeString(byteBuf, subEntry.getKey());
|
||||
|
||||
List<Integer> ids = subEntry.getValue();
|
||||
ProtocolUtil.writeVarInt(byteBuf, ids.size());
|
||||
for (int id : ids) {
|
||||
ProtocolUtil.writeVarInt(byteBuf, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull SonarPacket of(@NotNull CompoundBinaryTag tags) {
|
||||
Map<String, Map<String, List<Integer>>> tagsMap = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, ? extends BinaryTag> namedTag : tags) {
|
||||
Map<String, List<Integer>> subTagsMap = new HashMap<>();
|
||||
CompoundBinaryTag subTag = (CompoundBinaryTag) namedTag.getValue();
|
||||
|
||||
for (Map.Entry<String, ? extends BinaryTag> subNamedTag : subTag) {
|
||||
List<Integer> idsList = new ArrayList<>();
|
||||
ListBinaryTag ids = (ListBinaryTag) subNamedTag.getValue();
|
||||
for (BinaryTag id : ids) {
|
||||
idsList.add(((IntBinaryTag) id).value());
|
||||
}
|
||||
subTagsMap.put(subNamedTag.getKey(), idsList);
|
||||
}
|
||||
tagsMap.put(namedTag.getKey(), subTagsMap);
|
||||
}
|
||||
return new SonarPacketSnapshot(new UpdateTagsPacket(tagsMap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -15,18 +15,18 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.handshake;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@ToString(of = {"protocolVersionId", "hostname", "port"})
|
||||
public final class HandshakePacket implements FallbackPacket {
|
||||
public final class HandshakePacket implements SonarPacket {
|
||||
private int protocolVersionId;
|
||||
private String hostname;
|
||||
private int port;
|
||||
+4
-4
@@ -15,13 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.login;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.login;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
|
||||
public final class LoginAcknowledgedPacket implements FallbackPacket {
|
||||
public final class LoginAcknowledgedPacket implements SonarPacket {
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.login;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.login;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
@@ -25,8 +25,8 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.UUID;
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class LoginStartPacket implements FallbackPacket {
|
||||
public final class LoginStartPacket implements SonarPacket {
|
||||
private String username;
|
||||
private @Nullable UUID uuid;
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.login;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.login;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,8 +23,8 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.FastUuidSansHyphens;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.UUID;
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class LoginSuccessPacket implements FallbackPacket {
|
||||
public final class LoginSuccessPacket implements SonarPacket {
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
private boolean strictErrorHandling;
|
||||
+4
-4
@@ -15,13 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.*;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@@ -29,7 +29,7 @@ import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString(of = {"entityId", "hand"})
|
||||
public final class AnimationPacket implements FallbackPacket {
|
||||
public final class AnimationPacket implements SonarPacket {
|
||||
private int entityId = -1;
|
||||
private int hand = MAIN_HAND;
|
||||
private LegacyAnimationType type = LegacyAnimationType.SWING_ARM;
|
||||
+20
-5
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -25,15 +25,16 @@ import lombok.ToString;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.LongArrayBinaryTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class ChunkDataPacket implements FallbackPacket {
|
||||
public final class ChunkDataPacket implements SonarPacket {
|
||||
private int sectionX, sectionZ;
|
||||
|
||||
@Override
|
||||
@@ -111,7 +112,7 @@ public final class ChunkDataPacket implements FallbackPacket {
|
||||
// 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};
|
||||
final byte[] sectionData = getSectionDataBytes(protocolVersion);
|
||||
int count = 24;
|
||||
ProtocolUtil.writeVarInt(byteBuf, sectionData.length * count);
|
||||
|
||||
@@ -141,6 +142,20 @@ public final class ChunkDataPacket implements FallbackPacket {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte @NonNull [] getSectionDataBytes(@NonNull ProtocolVersion protocolVersion) {
|
||||
final byte[] sectionData;
|
||||
|
||||
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_26_1)) {
|
||||
sectionData = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_5)) {
|
||||
sectionData = new byte[]{0, 0, 0, 0, 0, 1};
|
||||
} else {
|
||||
sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0};
|
||||
}
|
||||
return sectionData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException();
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,15 +23,15 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class ClientInformationPacket implements FallbackPacket {
|
||||
public final class ClientInformationPacket implements SonarPacket {
|
||||
private String locale;
|
||||
private byte viewDistance;
|
||||
private int chatVisibility;
|
||||
+4
-4
@@ -15,13 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
|
||||
public final class ClientTickEndPacket implements FallbackPacket {
|
||||
public final class ClientTickEndPacket implements SonarPacket {
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
+4
-4
@@ -15,22 +15,22 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class ConfirmTeleportationPacket implements FallbackPacket {
|
||||
public final class ConfirmTeleportationPacket implements SonarPacket {
|
||||
private int teleportId;
|
||||
|
||||
@Override
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,14 +23,14 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.kyori.adventure.text.Component;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ComponentHolder;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class DisconnectPacket implements FallbackPacket {
|
||||
public final class DisconnectPacket implements SonarPacket {
|
||||
private @NotNull ComponentHolder componentHolder;
|
||||
private boolean duringLogin;
|
||||
|
||||
+4
-4
@@ -15,22 +15,22 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class EntityAnimationPacket implements FallbackPacket {
|
||||
public final class EntityAnimationPacket implements SonarPacket {
|
||||
private int entityId;
|
||||
private Type type;
|
||||
|
||||
+4
-4
@@ -15,20 +15,20 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class GameEventPacket implements FallbackPacket {
|
||||
public final class GameEventPacket implements SonarPacket {
|
||||
private int type;
|
||||
private float value;
|
||||
|
||||
+6
-6
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -25,10 +25,10 @@ import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
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.fallback.protocol.dimension.DimensionRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionType;
|
||||
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.protocol.dimension.DimensionRegistry;
|
||||
import xyz.jonesdev.sonar.common.protocol.dimension.DimensionType;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -36,7 +36,7 @@ import java.util.Objects;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class JoinGamePacket implements FallbackPacket {
|
||||
public final class JoinGamePacket implements SonarPacket {
|
||||
private int entityId;
|
||||
private int gamemode;
|
||||
private int previousGamemode;
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,15 +23,15 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class KeepAlivePacket implements FallbackPacket {
|
||||
public final class KeepAlivePacket implements SonarPacket {
|
||||
private long id;
|
||||
|
||||
@Override
|
||||
+4
-4
@@ -15,21 +15,21 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class MapDataPacket implements FallbackPacket {
|
||||
public final class MapDataPacket implements SonarPacket {
|
||||
private byte[] buffer;
|
||||
private int x, y;
|
||||
private int scaling;
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
package xyz.jonesdev.sonar.common.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -23,14 +23,14 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.api.antibot.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.protocol.SonarPacket;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class PaddleBoatPacket implements FallbackPacket {
|
||||
public final class PaddleBoatPacket implements SonarPacket {
|
||||
private boolean leftPaddle, rightPaddle;
|
||||
|
||||
@Override
|
||||
Loaded 100 of 190 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user