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