Compare commits

...
28 Commits
Author SHA1 Message Date
Jones a0b14214ae Release 2.1.18 (#418) 2024-12-01 14:00:32 +01:00
Jones 3d96a32f81 Fix crash issue on 1.13-1.13.2
(Backported minor changes from 3.0.0)
2024-12-01 01:23:54 +01:00
Jones de67ab12c2 Downgrade mysql-connector-j to 9.0.0 2024-11-30 19:46:08 +01:00
Jones adef9d9ccb Release 2.1.17 (#417) 2024-11-26 17:06:20 +01:00
Jones 71b40af656 Bump mariadb-java-client from 3.4.1 to 3.5.1 2024-11-23 17:07:21 +01:00
Jones 3a79711a8b Bump mysql-connector-j from 9.0.0 to 9.1.0 2024-11-23 17:06:29 +01:00
Jones 3094f12f84 Bump Gradle from 8.11 to 8.11.1 2024-11-23 17:02:51 +01:00
Jones a74c3da8d4 Use version name instead of ID for logging 2024-11-23 15:13:48 +01:00
dependabot[bot] 427768fc43 Bump io.netty:netty-all from 4.1.114.Final to 4.1.115.Final (#412)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.1.114.Final to 4.1.115.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.114.Final...netty-4.1.115.Final)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 03:57:07 +01:00
dependabot[bot] b0d7dfb735 Bump org.projectlombok:lombok from 1.18.34 to 1.18.36 (#413)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.34 to 1.18.36.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.34...v1.18.36)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 03:56:53 +01:00
Jones ff9216c4cc Add spotless for codestyle (#410)
* Add spotless for codestyle

* Fix license header file

* Bump Gradle from 8.10.2 to 8.11
2024-11-11 17:52:52 +01:00
Jones 43a1aa2ae8 Release 2.1.16 (#409) 2024-11-11 14:14:04 +01:00
Jones f36a613124 Clear ByteBuf if the packet has no start 2024-11-08 15:53:39 +01:00
Jones 3e193bddd7 Fix "invalid username" never being used 2024-11-07 18:44:43 +01:00
Jones 66d0651d1e Release 2.1.15 (#407) 2024-11-04 15:35:41 +01:00
dependabot[bot] b21c4e8a9a Bump com.gradleup.shadow from 8.3.3 to 8.3.5 (#406)
Bumps [com.gradleup.shadow](https://github.com/GradleUp/shadow) from 8.3.3 to 8.3.5.
- [Release notes](https://github.com/GradleUp/shadow/releases)
- [Commits](https://github.com/GradleUp/shadow/compare/8.3.3...8.3.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 15:23:40 +01:00
Jones b77e0c4806 Remove accidental debugging statement 2024-11-03 12:36:04 +01:00
Jones cb76dfe06e Release 2.1.14 (#405) 2024-11-02 14:59:53 +01:00
Jones d0a758473f Move username check to post-login 2024-11-02 14:57:11 +01:00
Jones e4dfab87da Fix pre-join disconnects not encoding correctly 2024-11-02 14:53:57 +01:00
Jones 2fe3ab1d8d Make unsupported version message configurable 2024-11-02 14:53:27 +01:00
Akkariin 4483e52852 Update language/config files for chinese. (#404)
* Update language/config files for chinese.

* Emphasizing parts makes it an accurate description of something.

* [ci skip] Fix space
2024-10-31 22:01:24 +01:00
Jones 22b41151d6 [ci skip] Display sponsors in README 2024-10-30 18:12:58 +01:00
Jones e849060db1 [ci skip] Add FUNDING.yml 2024-10-28 17:11:23 +01:00
Jones 59b338e775 Add client ticking check for 1.21.2+ 2024-10-27 15:50:44 +01:00
Jones e33ee1333a Release 2.1.13 (#403) 2024-10-26 17:10:37 +02:00
Jones 50e6b017f8 Don't serialize modern json twice 2024-10-26 17:08:46 +02:00
Jones f25cc18cb9 Fix NoClassDefFoundError on BungeeCord and Bukkit 2024-10-26 17:08:29 +02:00
47 changed files with 309 additions and 232 deletions

No files matched your search

+1
View File
@@ -0,0 +1 @@
patreon: jonesdev
+5
View File
@@ -48,6 +48,11 @@ Sonar also protects against spambot attacks since it queues the incoming connect
Sonar is unlikely to ever falsely prevent a player from joining the server since Minecraft uses the TCP protocol, which means that packets are always sent in the correct order. Therefore, lag or ping should not affect the bot check.
If you or one of your players experiences a false positive, make sure to report it by opening a [GitHub issue](https://github.com/jonesdevelopment/sonar/issues/new/choose) or a ticket on the [Discord server](https://jonesdev.xyz/discord/).
## Sponsors
Massive thanks to the sponsors of Sonar who help keep this project running:
<a href="https://github.com/Hydoxl"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/107579333?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
## Building
If you want to build your own version of Sonar, please take a look at the [Sonar building documentation](https://docs.jonesdev.xyz/development/building).
<br>
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) ${YEAR} Sonar Contributors
* Copyright (C) 2024 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
@@ -14,3 +14,4 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-3
View File
@@ -14,6 +14,3 @@ tasks {
archiveFileName = "sonar-api-${rootProject.version}.jar"
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
@@ -75,28 +75,23 @@ public interface Sonar {
void reload();
@NotNull
default SonarVersion getVersion() {
@NotNull default SonarVersion getVersion() {
return SonarVersion.INSTANCE;
}
@NotNull
default SonarEventManager getEventManager() {
@NotNull default SonarEventManager getEventManager() {
return SonarEventManager.INSTANCE;
}
@NotNull
default AttackTracker getAttackTracker() {
@NotNull default AttackTracker getAttackTracker() {
return AttackTracker.INSTANCE;
}
@NotNull
default Fallback getFallback() {
@NotNull default Fallback getFallback() {
return Fallback.INSTANCE;
}
@NotNull
static Sonar get() {
@NotNull static Sonar get() {
return SonarSupplier.sonar;
}
}
@@ -220,16 +220,12 @@ public final class SonarConfiguration {
webhook.content = webhookConfig.getString("webhook.content");
webhook.footer.text = webhookConfig.getString("webhook.embed.footer.text");
webhook.footer.iconUrl = webhookConfig.getString("webhook.embed.footer.icon-url");
final String realEmbedPath = "webhook.embed";
final String embedPath = realEmbedPath + ".";
webhook.embed.title = webhookConfig.getString(embedPath + "title");
webhook.embed.titleUrl = webhookConfig.getString(embedPath + "title-url");
webhook.embed.description = String.join("\n", webhookConfig.getStringList(embedPath + "description"));
webhook.embed.r = webhookConfig.getInt(embedPath + "color.red");
webhook.embed.g = webhookConfig.getInt(embedPath + "color.green");
webhook.embed.b = webhookConfig.getInt(embedPath + "color.blue");
webhook.embed.title = webhookConfig.getString("webhook.embed.title");
webhook.embed.titleUrl = webhookConfig.getString("webhook.embed.title-url");
webhook.embed.description = String.join("\n", webhookConfig.getStringList("webhook.embed.description"));
webhook.embed.r = webhookConfig.getInt("webhook.embed.color.red");
webhook.embed.g = webhookConfig.getInt("webhook.embed.color.green");
webhook.embed.b = webhookConfig.getInt("webhook.embed.color.blue");
if (!webhook.url.isEmpty()) {
if (webhook.username.isEmpty()) {
@@ -266,6 +262,7 @@ public final class SonarConfiguration {
tooManyOnlinePerIp = deserializeDisconnectMessage("too-many-online-per-ip");
verification.currentlyPreparing = deserializeDisconnectMessage("verification.currently-preparing");
verification.unsupportedVersion = deserializeDisconnectMessage("verification.unsupported-version");
verification.tooFastReconnect = deserializeDisconnectMessage("verification.too-fast-reconnect");
verification.alreadyVerifying = deserializeDisconnectMessage("verification.already-verifying");
verification.alreadyQueued = deserializeDisconnectMessage("verification.already-queued");
@@ -440,6 +437,7 @@ public final class SonarConfiguration {
private Component blacklisted;
private Component protocolBlacklisted;
private Component currentlyPreparing;
private Component unsupportedVersion;
}
@Getter
@@ -460,7 +458,7 @@ public final class SonarConfiguration {
Library.builder()
.groupId("org{}mariadb{}jdbc")
.artifactId("mariadb-java-client")
.version("3.4.1")
.version("3.5.1")
.relocate("org{}mariadb", "xyz{}jonesdev{}sonar{}libs{}mariadb")
.build()),
H2("H2", "jdbc:h2:file:%s", new H2DatabaseTypeAdapter(),
@@ -27,23 +27,17 @@ import xyz.jonesdev.sonar.api.timer.SystemTimer;
import java.net.InetAddress;
public interface FallbackUser {
@NotNull
Channel channel();
@NotNull Channel channel();
@NotNull
InetAddress getInetAddress();
@NotNull InetAddress getInetAddress();
@NotNull
ProtocolVersion getProtocolVersion();
@NotNull ProtocolVersion getProtocolVersion();
@NotNull
SystemTimer getLoginTimer();
@NotNull SystemTimer getLoginTimer();
@NotNull
String getFingerprint();
@NotNull String getFingerprint();
@NotNull
String getUsername();
@NotNull String getUsername();
boolean isForceCaptcha();
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Sonar Contributors
* Copyright (C) 2024 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
@@ -26,52 +26,53 @@ import java.util.Map;
@Getter
@RequiredArgsConstructor
public enum ProtocolVersion {
UNKNOWN(-1),
MINECRAFT_1_7_2(4),
MINECRAFT_1_7_6(5),
MINECRAFT_1_8(47),
MINECRAFT_1_9(107),
MINECRAFT_1_9_1(108),
MINECRAFT_1_9_2(109),
MINECRAFT_1_9_4(110),
MINECRAFT_1_10(210),
MINECRAFT_1_11(315),
MINECRAFT_1_11_1(316),
MINECRAFT_1_12(335),
MINECRAFT_1_12_1(338),
MINECRAFT_1_12_2(340),
MINECRAFT_1_13(393),
MINECRAFT_1_13_1(401),
MINECRAFT_1_13_2(404),
MINECRAFT_1_14(477),
MINECRAFT_1_14_1(480),
MINECRAFT_1_14_2(485),
MINECRAFT_1_14_3(490),
MINECRAFT_1_14_4(498),
MINECRAFT_1_15(573),
MINECRAFT_1_15_1(575),
MINECRAFT_1_15_2(578),
MINECRAFT_1_16(735),
MINECRAFT_1_16_1(736),
MINECRAFT_1_16_2(751),
MINECRAFT_1_16_3(753),
MINECRAFT_1_16_4(754),
MINECRAFT_1_17(755),
MINECRAFT_1_17_1(756),
MINECRAFT_1_18(757),
MINECRAFT_1_18_2(758),
MINECRAFT_1_19(759),
MINECRAFT_1_19_1(760),
MINECRAFT_1_19_3(761),
MINECRAFT_1_19_4(762),
MINECRAFT_1_20(763),
MINECRAFT_1_20_2(764),
MINECRAFT_1_20_3(765),
MINECRAFT_1_20_5(766),
MINECRAFT_1_21(767),
MINECRAFT_1_21_2(768);
UNKNOWN(-1, "Unknown"),
MINECRAFT_1_7_2(4, "1.7.2"),
MINECRAFT_1_7_6(5, "1.7.6"),
MINECRAFT_1_8(47, "1.8"),
MINECRAFT_1_9(107, "1.9"),
MINECRAFT_1_9_1(108, "1.9.1"),
MINECRAFT_1_9_2(109, "1.9.2"),
MINECRAFT_1_9_4(110, "1.9.3"),
MINECRAFT_1_10(210, "1.10"),
MINECRAFT_1_11(315, "1.11"),
MINECRAFT_1_11_1(316, "1.11.1"),
MINECRAFT_1_12(335, "1.12"),
MINECRAFT_1_12_1(338, "1.12.1"),
MINECRAFT_1_12_2(340, "1.12.2"),
MINECRAFT_1_13(393, "1.13"),
MINECRAFT_1_13_1(401, "1.13.1"),
MINECRAFT_1_13_2(404, "1.13.2"),
MINECRAFT_1_14(477, "1.14"),
MINECRAFT_1_14_1(480, "1.14.1"),
MINECRAFT_1_14_2(485, "1.14.2"),
MINECRAFT_1_14_3(490, "1.14.3"),
MINECRAFT_1_14_4(498, "1.14.4"),
MINECRAFT_1_15(573, "1.15"),
MINECRAFT_1_15_1(575, "1.15.1"),
MINECRAFT_1_15_2(578, "1.15.2"),
MINECRAFT_1_16(735, "1.16"),
MINECRAFT_1_16_1(736, "1.16.1"),
MINECRAFT_1_16_2(751, "1.16.2"),
MINECRAFT_1_16_3(753, "1.16.3"),
MINECRAFT_1_16_4(754, "1.16.4"),
MINECRAFT_1_17(755, "1.17"),
MINECRAFT_1_17_1(756, "1.17.1"),
MINECRAFT_1_18(757, "1.18"),
MINECRAFT_1_18_2(758, "1.18.2"),
MINECRAFT_1_19(759, "1.19"),
MINECRAFT_1_19_1(760, "1.19.1"),
MINECRAFT_1_19_3(761, "1.19.3"),
MINECRAFT_1_19_4(762, "1.19.4"),
MINECRAFT_1_20(763, "1.20"),
MINECRAFT_1_20_2(764, "1.20.2"),
MINECRAFT_1_20_3(765, "1.20.3"),
MINECRAFT_1_20_5(766, "1.20.5"),
MINECRAFT_1_21(767, "1.21"),
MINECRAFT_1_21_2(768, "1.21.2");
private final int protocol;
private final String name;
public static final ProtocolVersion LATEST_VERSION;
public static final Map<Integer, ProtocolVersion> ID_TO_PROTOCOL_CONSTANT;
+18 -2
View File
@@ -3,7 +3,8 @@ import net.kyori.indra.git.IndraGitExtension
plugins {
java
alias(libs.plugins.shadow)
alias(libs.plugins.indra.git) apply true
alias(libs.plugins.indra.git)
alias(libs.plugins.spotless)
}
allprojects {
@@ -15,6 +16,7 @@ allprojects {
apply(plugin = "java")
apply(plugin = "com.gradleup.shadow")
apply(plugin = "com.diffplug.spotless")
dependencies {
compileOnly(rootProject.libs.lombok)
@@ -31,6 +33,17 @@ allprojects {
compileOnly(rootProject.libs.libby.core)
}
spotless {
java {
endWithNewline()
formatAnnotations()
removeUnusedImports()
trimTrailingWhitespace()
indentWithSpaces(2)
licenseHeaderFile("../HEADER")
}
}
tasks {
shadowJar {
// Set the file name of the shadowed jar
@@ -80,6 +93,9 @@ allprojects {
attributes["Git-Commit"] = gitCommit
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
}
}
@@ -87,7 +103,7 @@ tasks {
// This is a small wrapper tasks to simplify the building process
register("build-sonar") {
val subprojects = listOf("api", "captcha", "common", "bukkit", "bungeecord", "velocity")
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:shadowJar") }
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:spotlessApply", "$it:shadowJar") }
dependsOn(buildTasks)
}
}
-3
View File
@@ -46,6 +46,3 @@ tasks {
relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori")
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
-3
View File
@@ -30,6 +30,3 @@ tasks {
archiveFileName = "Sonar-Bungee.jar" // Hardcode a shortened version of the name
}
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
-3
View File
@@ -5,6 +5,3 @@ dependencies {
testCompileOnly(project(":api"))
testCompileOnly(rootProject.libs.imagefilters)
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Sonar Contributors
* Copyright (C) 2024 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
-3
View File
@@ -3,6 +3,3 @@ dependencies {
implementation(project(":captcha"))
compileOnly(rootProject.libs.adventure.nbt)
}
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
@@ -83,8 +83,7 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
* will run before the connection knows that there has been an error.
*/
@Override
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx,
final Throwable cause) throws Exception {
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
ctx.close();
}
}
@@ -28,6 +28,7 @@ import xyz.jonesdev.sonar.api.fingerprint.FingerprintingUtil;
import xyz.jonesdev.sonar.common.fallback.netty.FallbackTimeoutHandler;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
import xyz.jonesdev.sonar.common.util.GeyserUtil;
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
@@ -73,17 +74,23 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
final @NotNull Runnable initialLoginAction,
final @NotNull String username,
final @NotNull InetSocketAddress socketAddress) throws Exception {
// Check if the player has already sent a login packet
if (this.username != null) {
// Count every single attempted login
GlobalSonarStatistics.countLogin();
// Ensure that the player sent a handshake packet
if (protocolVersion == null) {
throw QuietDecoderException.INSTANCE;
}
// Connections from unknown protocol versions will be discarded
// as this is the safest way of handling unwanted connections.
// Sonar does not support snapshots or Minecraft versions older than 1.7.2
if (protocolVersion.isUnknown()) {
customDisconnect(ctx.channel(), unsupportedVersion, ProtocolVersion.MINECRAFT_1_7_2);
return;
}
// Ensure that the player has not sent a login packet yet
if (this.username != null) {
throw QuietDecoderException.INSTANCE;
}
GlobalSonarStatistics.countLogin();
this.username = username;
final InetAddress inetAddress = socketAddress.getAddress();
@@ -150,17 +157,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
return null;
}
return () -> {
// Check if the username matches the valid name regex to prevent
// UTF-16 names or other types of exploits
if (!Sonar.get().getConfig().getVerification().getValidNameRegex().matcher(username).matches()) {
customDisconnect(ctx.channel(), invalidUsername, protocolVersion);
return;
}
// Create an instance for the user and let the verification handler take over the channel
new FallbackUserWrapper(ctx.channel(), inetAddress, protocolVersion, username, fingerprint, geyser);
};
// Create an instance for the user and let the verification handler take over the channel
return () -> new FallbackUserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser);
});
}
@@ -231,6 +229,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
private static void _customDisconnect(final @NotNull Channel channel,
final @NotNull FallbackPacket packet,
final @NotNull ProtocolVersion protocolVersion) {
// TODO: recode this
// Remove the connection handler pipeline to completely take over the channel
final String handler = Sonar.get().getPlatform().getConnectionHandler();
if (channel.pipeline().context(handler) != null) {
@@ -243,6 +242,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
// We don't need to update the encoder if it has already been replaced by Sonar
if (!(currentEncoder instanceof FallbackPacketEncoder)) {
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
channel.pipeline().replace(encoder, FALLBACK_PACKET_ENCODER, newEncoder);
}
ProtocolUtil.closeWith(channel, protocolVersion, packet);
@@ -18,6 +18,7 @@
package xyz.jonesdev.sonar.common.fallback;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -59,13 +60,13 @@ public final class FallbackUserWrapper implements FallbackUser {
@Setter
private boolean forceCaptcha;
public FallbackUserWrapper(final @NotNull Channel channel,
public FallbackUserWrapper(final @NotNull ChannelHandlerContext ctx,
final @NotNull InetAddress inetAddress,
final @NotNull ProtocolVersion protocolVersion,
final @NotNull String username,
final @NotNull String fingerprint,
final boolean geyser) {
this.channel = channel;
this.channel = ctx.channel();
this.inetAddress = inetAddress;
this.protocolVersion = protocolVersion;
this.username = username;
@@ -82,7 +83,7 @@ public final class FallbackUserWrapper implements FallbackUser {
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.connection")
.replace("<username>", username)
.replace("<ip>", Sonar.get().getConfig().formatAddress(inetAddress))
.replace("<protocol>", String.valueOf(protocolVersion.getProtocol())));
.replace("<protocol>", protocolVersion.getName()));
}
// Call the VerifyJoinEvent for external API usage
@@ -30,8 +30,7 @@ public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler {
// does not have any other pipelines that could handle this error.
// Additionally, this will also run after our custom decoder.
@Override
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx,
final Throwable cause) throws Exception {
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
// Close the channel if we encounter any errors.
ctx.close();
}
@@ -43,6 +43,7 @@ public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
// Skip any runs of 0x00 we might find
final int packetStart = byteBuf.forEachByte(ByteProcessor.FIND_NON_NUL);
if (packetStart == -1) {
byteBuf.clear();
return;
}
byteBuf.readerIndex(packetStart);
@@ -422,6 +422,8 @@ public enum FallbackPacketRegistry {
map(0x64, MINECRAFT_1_20_5, true),
map(0x6B, MINECRAFT_1_21_2, true));
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
map(0x0B, MINECRAFT_1_21_2, false));
serverbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
map(0x09, MINECRAFT_1_7_2, false),
map(0x17, MINECRAFT_1_9, false),
@@ -111,7 +111,7 @@ public class FallbackPreparer {
public FallbackPacket alreadyVerifying;
public FallbackPacket reconnectedTooFast;
public FallbackPacket protocolBlacklisted;
public FallbackPacket invalidUsername;
public FallbackPacket unsupportedVersion;
public FallbackPacket tooManyOnlinePerIP;
public FallbackPacket[] xpCountdown;
public FallbackPacket updateTime;
@@ -188,7 +188,7 @@ public class FallbackPreparer {
alreadyQueued = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getAlreadyQueued(), true));
protocolBlacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getProtocolBlacklisted(), true));
reconnectedTooFast = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getTooFastReconnect(), true));
invalidUsername = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getInvalidUsername(), true));
unsupportedVersion = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getUnsupportedVersion(), true));
tooManyOnlinePerIP = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getTooManyOnlinePerIp(), true));
// Prepare transfer packet
@@ -88,10 +88,12 @@ public final class ChunkDataPacket implements FallbackPacket {
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_8)) {
byteBuf.writeInt(0);
byteBuf.writeBytes(new byte[2]);
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_15)) {
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_13)) {
ProtocolUtil.writeVarInt(byteBuf, 0);
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18)) {
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_15)) {
ProtocolUtil.writeByteArray(byteBuf, new byte[256 * 4]);
} else if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_18)) {
ProtocolUtil.writeVarInt(byteBuf, 0);
} else {
final byte[] sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0};
int count = protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2) ? 24 : 16;
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2024 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.common.fallback.protocol.packets.play;
import io.netty.buffer.ByteBuf;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
public final class ClientTickEndPacket implements FallbackPacket {
@Override
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
throw new UnsupportedOperationException();
}
@Override
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
}
@Override
public int expectedMaxLength(final ProtocolVersion protocolVersion) {
// This packet is always empty
return 0;
}
}
@@ -41,7 +41,7 @@ public final class DisconnectPacket implements FallbackPacket {
@Override
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
// Force json serialization during login phase
// Force JSON serialization during login phase
componentHolder.write(byteBuf, protocolVersion, duringLogin);
}
@@ -91,7 +91,7 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
private final boolean enableGravityCheck, enableCollisionsCheck;
private boolean teleported, canFall, checkMovement;
private double y, deltaY, blockHeight;
private int movementTick, expectedTeleportId = FIRST_TELEPORT_ID;
private int movementTick, clientTick, expectedTeleportId = FIRST_TELEPORT_ID;
private SetPlayerPositionRotationPacket lastPositionPacket;
@Override
@@ -139,6 +139,8 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
// Pass these packets back to the login handler
// TODO: recode this
preJoinHandler.handle(packet);
} else if (packet instanceof ClientTickEndPacket) {
clientTick++;
}
}
@@ -200,6 +202,11 @@ public final class FallbackGravityHandler extends FallbackVerificationHandler {
checkState(Math.abs(Math.abs(x) - BLOCKS_PER_ROW) < BLOCKS_PER_ROW, "illegal x offset: " + x);
checkState(Math.abs(Math.abs(z) - BLOCKS_PER_ROW) < BLOCKS_PER_ROW, "illegal z offset: " + z);
// Check if the client is ticking correctly
if (user.getProtocolVersion().greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
checkState(clientTick >= movementTick, "invalid ticking: " + clientTick + "/" + movementTick);
}
if (!onGround) {
// The deltaY is 0 whenever the player sends their first position packet.
// We have to account for this or the player will falsely fail the verification.
@@ -157,6 +157,11 @@ public final class FallbackPreJoinHandler extends FallbackVerificationHandler {
private void markSuccess() {
if (user.channel().isActive()) {
if (!Sonar.get().getConfig().getVerification().getValidNameRegex().matcher(user.getUsername()).matches()) {
user.disconnect(Sonar.get().getConfig().getVerification().getInvalidUsername());
return;
}
// Pass the player to the next verification handler
final FallbackGravityHandler gravityHandler = new FallbackGravityHandler(user, this);
user.channel().pipeline().get(FallbackPacketDecoder.class).setListener(gravityHandler);
@@ -93,7 +93,7 @@ public abstract class FallbackVerificationHandler implements FallbackPacketListe
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.failed")
.replace("<username>", user.getUsername())
.replace("<ip>", Sonar.get().getConfig().formatAddress(user.getInetAddress()))
.replace("<protocol>", String.valueOf(user.getProtocolVersion().getProtocol()))
.replace("<protocol>", user.getProtocolVersion().getName())
.replace("<reason>", reason));
}
@@ -123,7 +123,7 @@ public abstract class FallbackVerificationHandler implements FallbackPacketListe
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.blacklisted")
.replace("<username>", user.getUsername())
.replace("<ip>", Sonar.get().getConfig().formatAddress(user.getInetAddress()))
.replace("<protocol>", String.valueOf(user.getProtocolVersion().getProtocol())));
.replace("<protocol>", user.getProtocolVersion().getName()));
}
}
@@ -22,6 +22,7 @@ import com.google.gson.internal.LazilyParsedNumber;
import io.netty.buffer.ByteBuf;
import net.kyori.adventure.nbt.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
@@ -36,9 +37,9 @@ public final class ComponentHolder {
private final BinaryTag binaryTag;
public ComponentHolder(final @NotNull Component component) {
this.modernJson = ProtocolUtil.PRE_1_20_3_SERIALIZER.serialize(component);
this.legacyJson = ProtocolUtil.PRE_1_16_SERIALIZER.serialize(component);
this.binaryTag = serialize(new JsonParser().parse(ProtocolUtil.MODERN_SERIALIZER.serialize(component)));
this.modernJson = GsonComponentSerializer.gson().serialize(component);
this.legacyJson = GsonComponentSerializer.colorDownsamplingGson().serialize(component);
this.binaryTag = serialize(new JsonParser().parse(this.modernJson));
}
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java
@@ -15,27 +15,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/*
* Copyright 2021 Andrew Steinborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package xyz.jonesdev.sonar.common.util;
import io.netty.buffer.ByteBuf;
@@ -50,9 +29,6 @@ import lombok.experimental.UtilityClass;
import net.kyori.adventure.nbt.BinaryTag;
import net.kyori.adventure.nbt.BinaryTagType;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.json.JSONOptions;
import net.kyori.option.OptionState;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionRegistry;
@@ -66,41 +42,6 @@ import java.util.concurrent.TimeUnit;
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
@UtilityClass
public class ProtocolUtil {
public static final GsonComponentSerializer PRE_1_16_SERIALIZER = GsonComponentSerializer.builder()
.downsampleColors()
.options(OptionState.optionState()
// before 1.16
.value(JSONOptions.EMIT_RGB, Boolean.FALSE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.LEGACY_ONLY)
// before 1.20.3
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
.build())
.build();
public static final GsonComponentSerializer PRE_1_20_3_SERIALIZER = GsonComponentSerializer.builder()
.options(OptionState.optionState()
// after 1.16
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY)
// before 1.20.3
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.FALSE)
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.FALSE)
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.FALSE)
.build())
.build();
public static final GsonComponentSerializer MODERN_SERIALIZER = GsonComponentSerializer.builder()
.options(OptionState.optionState()
// after 1.16
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.MODERN_ONLY)
// after 1.20.3
.value(JSONOptions.EMIT_COMPACT_TEXT_COMPONENT, Boolean.TRUE)
.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, Boolean.TRUE)
.value(JSONOptions.VALIDATE_STRICT_EVENTS, Boolean.TRUE)
.build())
.build();
public static final boolean DEBUG = Boolean.getBoolean("sonar.debug-traces");
private static final int[] VAR_INT_LENGTHS = new int[65];
@@ -140,6 +81,27 @@ public class ProtocolUtil {
throw DEBUG ? new DecoderException("Bad VarInt") : QuietDecoderException.INSTANCE;
}
/*
* Copyright 2021 Andrew Steinborn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
public static void writeVarInt(final @NotNull ByteBuf byteBuf, final int value) {
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
// that the proxy will write, to improve inlining.
+25 -24
View File
@@ -11,10 +11,10 @@
# 需要帮助吗? https://jonesdev.xyz/discord
# 源代码: https://github.com/jonesdevelopment/sonar
# 文件: https://docs.jonesdev.xyz/administration/configuring-sonar
# Copyright Jones Development and Sonar Contributors, 以 GPL-3.0 许可
# Copyright Jones Development and Sonar Contributors, 以 GPL-3.0 许可证分发
#
# 未归类的设置
# 常规的设置
general:
# Sonar 是否应该自动检查新的更新?
# Sonar 使用 GitHub API 检查当前版本是否过时
@@ -24,18 +24,19 @@ general:
# 具有相同 IP 地址的在线玩家的最大数量
max-online-per-ip: 3
# 攻击检测器的敏感度设置
# 只有当您知道自己在做什么的时候才编辑它
# 攻击检测器
# 只有当您知道自己在做什么的时候才应该编辑它
attack-tracker:
# 在一段时间内至少需要 x 个新玩家加入才满足触发条件.
# 在一段时间内至少需要多少个新玩家加入才满足触发条件?
min-players-for-attack: 8
# 至少经过多少毫秒后才可以解除遭受攻击模式
# (该值为毫秒. 1秒等于1000毫秒.)
min-attack-duration: 30000
# 攻击检测器要重复检测到多少次攻击 才能确认服务器正在遭受攻击?
# 要重复检测到多少次攻击 才应该被确认为服务器正在遭受攻击?
# 该值作为缓冲区 以避免可能的误判
min-attack-threshold: 2
# 当从遭受攻击标记为解除攻击时 应该需要等待多久才能再次被标记为正在遭受攻击?
# 当从遭受攻击状态标记为已缓解攻击状态时
# 至少需要多少毫秒才允许为对于可能检测到的攻击重新进入遭受攻击状态?
# (该值为毫秒. 1秒等于1000毫秒.)
attack-cooldown-delay: 3000
@@ -43,7 +44,7 @@ attack-tracker:
# 提示: IP 地址将以纯文本形式保存 请确保您的数据库安全!
database:
# 要连接到的数据库类型
# 可用类型: NONE (不使用数据库), MYSQL, MARIADB, H2
# 可用类型: NONE (不使用数据库), MYSQL, MARIADB, H2 (本地数据库)
type: NONE
# Sonar 插件目录中用于 H2 数据库的文件
filename: verified_players
@@ -72,31 +73,31 @@ verification:
# 可用类型: ALWAYS, DURING_ATTACK, NEVER
# - ALWAYS: 玩家始终需要验证 直到他们通过验证为止
# - DURING_ATTACK: 玩家仅在服务器疑似遭到攻击时验证
# - NEVER: 玩家不会被验证
# - NEVER: 永远不检查未被验证过的玩家
timing: ALWAYS
checks:
# 检查玩家的下落移动是否遵循原版客户端.
gravity:
# Sonar 是否应该检查玩家的下落移动? (推荐启用)
enabled: true
# 当玩家验证失败时 是否向他们发送验证码?
# 当玩家验证失败时 是否向他们发送地图验证码?
captcha-on-fail: false
# 玩家跌落在平台上多少tick后才能被算作站在平台上?
max-movement-ticks: 8
# 检查玩家是否与下方生成的方块发生碰撞
# 检查玩家是否可以正确地站在方块上
collision:
# Sonar 是否应该生成方块平台以检查玩家下落与方块之间的碰撞? (推荐启用)
enabled: true
# 检查客户端坐在实体上时是否发送了正确的数据包
vehicle:
# 声纳是否应该检查玩家是否正确进入船只?
# Sonar 是否应该让玩家坐在实体上, 以便检查他们的数据包是否合法?
enabled: true
# 客户端发送的最小数据包数量
# 客户端需要发送的所需的最小数据包数量
minimum-packets: 2
# 地图验证码
# 手持地图验证码
map-captcha:
# Sonar 应该在什么时候向玩家发送验证码?
# 可用类型: ALWAYS, DURING_ATTACK, NEVER
@@ -141,8 +142,8 @@ verification:
# 为此您必须在服务器软件的配置文件中允许接受来自transfer的连接.
# 此外 您可能希望减少 Velocity 或其它服务器软件/插件的登录速率限制
# 因为这可能会阻止玩家快速地重新连接到服务器
# 如果你的服务器允许 Bedrock 玩家通过间歇泉加入, 请确保为间歇泉设置了
# 传输工具 TransferTool, 以便将 Bedrock 玩家重定向到正确的服务器.
# 如果你的服务器允许 Bedrock 玩家通过 Geyser 加入, 请确保为 Geyser 设置了
# TransferTool 扩展, 以便将 Bedrock 玩家重定向到正确的服务器.
# https://github.com/onebeastchris/TransferTool
enabled: false
# 当玩家通过验证后, Sonar 应该将玩家转移到哪个服务器
@@ -153,28 +154,28 @@ verification:
# 如果服务器地址不包含端口 请保留25565.
destination-port: 25565
# 玩家在虚拟服务器中的游戏模式
# 玩家正在验证时所使用的游戏模式
# 可用类型: SURVIVAL, CREATIVE, ADVENTURE
# - SURVIVAL: 生存模式, 所有UI可见
# - CREATIVE: 创造模式, 隐藏血量和饱食度
# - ADVENTURE: 冒险模式, 所有UI可见
gamemode: ADVENTURE
# 验证世界的夏令时间
# 您可以在这里找到所有的夏令时间:
# 验证过程中玩家所看到的当前世界中的一天时间
# 您可以在这里找到您想要的时间:
# https://minecraft.wiki/w/Daylight_cycle
# 这只是一个可视化设置, 不会改变验证过程!
# 该选项不会改变验证过程.
# 如果该值设置为 1000, 则不会发送数据包.
time-of-day: 1000
# Sonar 缓存它发送到客户端的大部分数据包, 包括 LoginSuccess 数据包.
# Sonar 应该使用哪个用户名来接收 LoginSuccess 数据包?
# 如果不修改客户端, 用户名将不会对玩家可见
cached-username: "Sonar"
# 当 Sonar 尝试验证玩家时 是否在控制台中打印它?
# 当 Sonar 尝试验证玩家时 是否在控制台中打印有关玩家的信息?
log-connections: true
# Sonar 是否应该记录在攻击期间内的验证会话?
# Sonar 是否应该在攻击期间内打印日志?
log-during-attack: false
# Sonar 是否应该记录验证过程中玩家的移动位置的变化?
# 有助于发现错误 但不建议在非调试环境下的服务器启用该选项.
# 有助于发现错误 但不建议在生产环境下的服务器启用该选项.
debug-xyz-positions: false
# Sonar 是否应该检查来自 Geyser 的(基岩版)玩家?
# 此功能是实验性的. 请报告任何因为误判而导致无法通过检查的问题
@@ -186,7 +187,7 @@ verification:
# 服务器在断开玩家连接前停止发送数据包的时间
# (该值为毫秒. 1秒等于1000毫秒.)
write-timeout: 10000
# 当玩家在需要验证时(即还未通过检查的情况下)需要等待多少毫秒才可以重新连接?
# 当玩家在还未通过检查的情况下断开连接后需要等待多少毫秒才可以重新连接?
# (该值为毫秒. 1秒等于1000毫秒.)
rejoin-delay: 5000
# 当玩家验证失败后, Sonar 应该记住他多久?
@@ -208,6 +208,11 @@ verification:
- <yellow>Vaše anti-bot data ještě nejsou připravena.
- <gray>Počkejte prosím několik sekund, než se pokusíte znovu ověřit.
- <footer>
# Zpráva o odpojení, která se zobrazí, když se někdo připojí s nepodporovanou verzí Minecraftu
unsupported-version:
- <header>
- <red>Tento server nepodporuje vaši verzi Minecraftu.
- <footer>
# Zpráva o odpojení, která se zobrazí, když se někdo znovu připojí příliš rychle během ověření
too-fast-reconnect:
- <header>
@@ -203,31 +203,36 @@ verification:
# Setzen Sie dies auf '', um die Willkommensnachricht vollständig zu deaktivieren
welcome: '<prefix><green>Sie werden gerade überprüft. Bitte bewegen Sie sich nicht, dies ist ein automatischer Vorgang.'
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, während der CAPTCHA noch nicht vorbereitet wurde
# Nachricht, die angezeigt wird, wenn jemand beitritt, während der CAPTCHA noch nicht vorbereitet wurde
currently-preparing:
- <header>
- <yellow>Deine Anti-Bot-Daten wurden noch nicht vorbereitet.
- <gray>Bitte warte einige Sekunden bevor du es erneut versuchst.
- <footer>
# Trennungs-Nachricht, die angezeigt wird, wenn jemand zu schnell während der Verifizierung erneut beitritt
# Nachricht, die angezeigt wird, wenn jemand mit einer nicht unterstützten Minecraft-Version beitritt
unsupported-version:
- <header>
- <red>Dieser Server unterstützt deine Version von Minecraft nicht.
- <footer>
# Nachricht, die angezeigt wird, wenn jemand zu schnell während der Verifizierung erneut beitritt
too-fast-reconnect:
- <header>
- <gold>Du hast zu schnell erneut eine Verbindung hergestellt, versuche es später noch einmal.
- <gray>Bitte warte einige Sekunden bevor du es erneut versuchst.
- <footer>
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits verifiziert wird
# Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits verifiziert wird
already-verifying:
- <header>
- <red>Deine IP-Adresse wird derzeit verifiziert.
- <red>Bitte warte einige Sekunden bevor du es erneut versuchst.
- <footer>
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits in der Warteschlange für die Verifizierung ist
# Nachricht, die angezeigt wird, wenn jemand beitritt, aber bereits in der Warteschlange für die Verifizierung ist
already-queued:
- <header>
- <red>Deine IP-Adresse befindet sich derzeit in der Warteschlange für die Verifizierung.
- <red>Bitte warte einige Minuten, bevor du es erneut versuchst.
- <footer>
# Trennungs-Nachricht, die angezeigt wird, wenn jemand beitritt, aber vorübergehend auf der Blacklist steht
# Nachricht, die angezeigt wird, wenn jemand beitritt, aber vorübergehend auf der Blacklist steht
blacklisted:
- <header>
- <red>Du bist derzeit vom Betreten des Servers ausgeschlossen.
@@ -208,6 +208,11 @@ verification:
- <yellow>Your anti-bot data has not been prepared yet.
- <gray>Please wait a few seconds before trying to verify again.
- <footer>
# Disconnect message that is shown when someone joins with an unsupported Minecraft version
unsupported-version:
- <header>
- <red>This server does not support your version of Minecraft.
- <footer>
# Disconnect message that is shown when someone rejoins too fast during verification
too-fast-reconnect:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>Tus datos anti-bot aún no se han preparado.
- <gray>Espere unos segundos antes de intentar realizar la verificación nuevamente.
- <footer>
# Mensaje de desconexión que se muestra cuando alguien se une con una versión de Minecraft no soportada
unsupported-version:
- <header>
- <red>Este servidor no es compatible con tu versión de Minecraft.
- <footer>
# Disconnect message that is shown when someone rejoins too fast during verification
too-fast-reconnect:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>Vos données anti-bot n'ont pas encore été préparées.
- <gray>Veuillez patienter quelques secondes avant d'essayer de vous vérifier à nouveau.
- <footer>
# Message de déconnexion affiché lorsque quelqu'un se connecte avec une version de Minecraft non prise en charge
unsupported-version:
- <header>
- <red>Ce serveur ne prend pas en charge votre version de Minecraft.
- <footer>
# Message de déconnexion affiché lorsque quelqu'un se reconnecte trop rapidement pendant la vérification
too-fast-reconnect:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>Data anti-bot Anda belum disiapkan.
- <gray>Silakan tunggu beberapa detik sebelum mencoba verifikasi lagi.
- <footer>
# Pesan putus yang ditampilkan ketika seseorang bergabung dengan versi Minecraft yang tidak didukung
unsupported-version:
- <header>
- <red>Server ini tidak mendukung versi Minecraft Anda.
- <footer>
# Pesan putus yang ditampilkan saat seseorang bergabung kembali terlalu cepat selama verifikasi
too-fast-reconnect:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>ანტიბოტი ჯერ არ მომზადებულა.
- <gray>გთხოვთ დაიცადოთ რამოდენიმე წამი სანამ ხელახლა შემოხვალთ.
- <footer>
# Disconnect message that is shown when someone joins with an unsupported Minecraft version
unsupported-version:
- <header>
- <red>This server does not support your version of Minecraft.
- <footer>
# გავარდნის მესიჯი რომელიც არის ნაჩვენები როცა ვინმე ხელახლა შემოდის ძალიან სწრაფად შემოწმების დროს.
too-fast-reconnect:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>Uw anti-bot gegevens zijn nog niet voorbereid.
- <gray>Wacht een paar seconden voordat u opnieuw probeert te verifiëren.
- <footer>
# Verbindingsbericht dat wordt weergegeven wanneer iemand lid wordt met een niet-ondersteunde Minecraft-versie
unsupported-version:
- <header>
- <red>Deze server ondersteunt jouw versie van Minecraft niet.
- <footer>
# Verbindingsbericht dat wordt weergegeven wanneer iemand tijdens de verificatie te snel opnieuw deelneemt
too-fast-reconnect:
- <header>
@@ -211,6 +211,11 @@ verification:
- <yellow>Twoje dane antybotowe nie zostały jeszcze przygotowane.
- <gray>Odczekaj kilka sekund przed ponowną próbą weryfikacji.
- <footer>
# Komunikat o rozłączeniu wyświetlany, gdy ktoś dołączy z nieobsługiwaną wersją Minecrafta
unsupported-version:
- <header>
- <red>Ten serwer nie obsługuje twojej wersji gry Minecraft.
- <footer>
# Disconnect message that is shown when someone rejoins too fast during verification
too-fast-reconnect:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>Капча еще не подготовлена.
- <gray>Пожалуйста, подождите несколько секунд, прежде чем повторить попытку.
- <footer>
# Сообщение об отключении, которое появляется, когда кто-то присоединяется к серверу с неподдерживаемой версией Minecraft
unsupported-version:
- <header>
- <red>Этот сервер не поддерживает вашу версию Minecraft.
- <footer>
# Сообщение, которое показывается когда слишком много людей проходят проверку
too-many-players:
- <header>
@@ -208,6 +208,11 @@ verification:
- <yellow>Anti-bot verileriniz henüz hazır değil.
- <gray>Tekrar doğrulamayı denemeden önce lütfen birkaç saniye bekleyin.
- <footer>
# Birisi desteklenmeyen bir Minecraft sürümüyle katıldığında gösterilen bağlantıyı kes mesajı
unsupported-version:
- <header>
- <red>Bu sunucu senin Minecraft sürümünü desteklemiyor.
- <footer>
# Doğrulama sırasında birisi çok hızlı bir şekilde yeniden katıldığında gösterilen bağlantıyı kesme mesajı
too-fast-reconnect:
- <header>
@@ -27,7 +27,7 @@ footer:
# 当玩家尝试加入但有太多在线玩家同时使用者玩家的 IP 地址时显示的踢出消息.
too-many-online-per-ip:
- '<header>'
- <red>您所使用的 IP 地址已经无法再登录更多账户了.
- <red>您所使用的 IP 地址已经无法再在该服务器上登录更多账户了.
- '<footer>'
# 有关命令的语言配置.
@@ -77,11 +77,11 @@ commands:
# '/sonar verbose' 命令的消息
verbose:
# 该子命令的描述
description: "启用或禁用 Sonar 冗余"
description: "启用或禁用 Sonar 的实时状态信息"
# 玩家订阅详细信息时显示的消息
subscribe: '<prefix>已为您显示 Sonar 的详细信息.'
subscribe: '<prefix>已为您显示 Sonar 的实时状态信息.'
# 玩家取消订阅详细信息时显示的消息
unsubscribe: '<prefix>不再为您显示 Sonar 的详细信息.'
unsubscribe: '<prefix>不再为您显示 Sonar 的实时状态信息.'
# '/sonar notify' 命令的消息
notify:
@@ -95,7 +95,7 @@ commands:
# '/sonar blacklist' 命令的消息
blacklist:
# 该子命令的描述
description: "管理黑名单 IP 地址"
description: "管理黑名单中的 IP 地址"
# 当尝试清理黑名单但黑名单中没有任何 IP 地址显示的消息
empty: '<prefix>黑名单中没有任何 IP 地址.'
# 当成功清理黑名单时显示的消息
@@ -114,7 +114,7 @@ commands:
# '/sonar verified' 命令的消息
verified:
# 该子命令的描述
description: "管理已验证的 IP 地址"
description: "管理已验证(白名单中)的 IP 地址"
# 当尝试清除白名单但为空时显示的消息
empty: '<prefix>白名单中没有任何玩家.'
# 当成功清理白名单时显示的消息
@@ -130,7 +130,7 @@ commands:
# 当尝试移除一个不在白名单中的 IP 地址时显示的消息
ip-not-found: '<prefix>您提供的 IP 地址不在白名单中.'
# 当尝试移除一个查询 IP 地址的验证历史时显示的信息
history: '<prefix><yellow>以前的 UUID 用于 <ip>:'
history: '<prefix><yellow><ip> 所拥有的历史 UUID:'
history-entry: ' <gray>▪ <white><uuid>'
# '/sonar statistics' 命令的消息
@@ -199,8 +199,8 @@ verification:
incorrect: '<prefix><red>您输入了错误的答案! 请重试.'
# 当玩家正在接受验证时显示的信息
# 将此项设置为''可完全禁用欢迎信息
welcome: '<prefix><green>您正在接受验证. 请不要移动; 这是一个自动过程.'
# 将此项设置为''可完全禁用加入时发送的消息
welcome: '<prefix><green>正在验证您的客户端. 请不要移动...'
# 当验证码还在准备的时候显示的踢出消息
currently-preparing:
@@ -208,6 +208,11 @@ verification:
- <yellow>反机器人还在准备所需的数据
- <gray>请稍后重新加入服务器
- <footer>
# 当有人使用不支持的版本加入时显示的断开信息
unsupported-version:
- <header>
- <red>此服务器不支持您的威廉与版本.
- <footer>
# 当玩家需要验证时重新连接速度太快时显示的踢出消息
too-fast-reconnect:
- <header>
@@ -263,7 +268,7 @@ verbose:
# 默认的状态栏
normal: '<prefix><gray>每秒连接数 <white><connections-per-second> <dark_aqua>╺ <gray>每秒登录次数 <white><logins-per-second> <dark_aqua>╺ <gray>正在验证的连接数 <white><verifying> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
# 遭受攻击时的状态栏
attack: '<prefix><gray>每秒连接数 <white><connections-per-second> <dark_aqua>╺ <gray>每秒登录次数 <white><logins-per-second> <dark_aqua>╺ <gray>排队连接数 <white><queued> <dark_aqua>╺ <gray>正在验证的连接数 <white><verifying> <dark_aqua>╺ <gray>攻击持续时间 <white><attack-duration> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
attack: '<prefix><gray>每秒连接数 <white><connections-per-second> <dark_aqua>╺ <gray>每秒登录次数 <white><logins-per-second> <dark_aqua>╺ <gray>正在排队的连接数 <white><queued> <dark_aqua>╺ <gray>正在验证的连接数 <white><verifying> <dark_aqua>╺ <gray>攻击持续时间 <white><attack-duration> <dark_aqua>| <green>⬆ <white><outgoing-traffic>/s <red>⬇ <white><incoming-traffic>/s <green><bold><animation>'
# 动画占位符
# 其它预设:
# - ▙, ▛, ▜, ▟
+1 -1
View File
@@ -1,3 +1,3 @@
group=xyz.jonesdev
version=2.1.12
version=2.1.18
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
+4 -3
View File
@@ -1,5 +1,5 @@
[versions]
netty = "4.1.114.Final"
netty = "4.1.115.Final"
adventure = "4.17.0"
adventure-platform = "4.3.4"
bstats = "3.1.0"
@@ -8,7 +8,8 @@ pluginyml = "0.6.0"
[plugins]
indra-git = "net.kyori.indra.git:3.1.3"
shadow = "com.gradleup.shadow:8.3.3"
shadow = "com.gradleup.shadow:8.3.5"
spotless = "com.diffplug.spotless:7.0.0.BETA4"
pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" }
pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
@@ -31,7 +32,7 @@ caffeine = "com.github.ben-manes.caffeine:caffeine:3.1.8"
annotations = "org.jetbrains:annotations:26.0.1"
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.34"
lombok = "org.projectlombok:lombok:1.18.36"
bungeecord = "net.md-5:bungeecord-proxy:1.21-SNAPSHOT"
velocity = "com.velocitypowered:velocity-proxy:3.4.0-SNAPSHOT"
# We have to use 1.8.8 for backwards compatibility
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored Executable → Regular
View File
File mode changed.