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