mirror of
https://github.com/jonesdevelopment/sonar.git
synced 2026-11-05 09:20:15 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bc3d73cb7 | ||
|
|
d3aaba4650 | ||
|
|
68d99dd59b | ||
|
|
5f77f21ee9 | ||
|
|
c5e1d12424 | ||
|
|
25dbbf0b1f | ||
|
|
cbf04f6f2e | ||
|
|
8966d7d0e8 | ||
|
|
064a3cee2a | ||
|
|
260af8b2be | ||
|
|
a7d52467b8 | ||
|
|
0ed6b0351c | ||
|
|
a152633b41 | ||
|
|
f618d1ce77 | ||
|
|
ea35904d33 | ||
|
|
ececb66bf1 | ||
|
|
6caa37e3e0 | ||
|
|
a057199e0b | ||
|
|
d0bbcdc600 | ||
|
|
0a5ce856f3 | ||
|
|
261acbd9e2 |
No files matched your search
+2
-2
@@ -36,8 +36,8 @@ allprojects {
|
||||
testAnnotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
|
||||
// adventure
|
||||
compileOnly("net.kyori:adventure-text-minimessage:4.16.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.16.0")
|
||||
compileOnly("net.kyori:adventure-text-minimessage:4.17.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.17.0")
|
||||
|
||||
compileOnly("com.j256.ormlite:ormlite-jdbc:6.1") // ORMLite
|
||||
compileOnly("com.github.ben-manes.caffeine:caffeine:3.1.8") // caching
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
group=xyz.jonesdev.sonar
|
||||
version=2.0.28
|
||||
version=2.0.31
|
||||
description=Effective Anti-bot plugin for Velocity, BungeeCord, and Bukkit (1.7-latest)
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -83,7 +83,8 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -201,11 +202,11 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_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.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
||||
Vendored
+10
-10
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import xyz.jonesdev.sonar.api.verbose.Notification;
|
||||
import xyz.jonesdev.sonar.api.verbose.Verbose;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.InetAddress;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.UUID;
|
||||
@@ -63,8 +62,6 @@ public interface Sonar {
|
||||
*/
|
||||
@NotNull LoggerWrapper getLogger();
|
||||
|
||||
@NotNull File getDataDirectory();
|
||||
|
||||
@NotNull SonarConfiguration getConfig();
|
||||
|
||||
@NotNull SubcommandRegistry getSubcommandRegistry();
|
||||
|
||||
@@ -182,20 +182,31 @@ public final class SonarConfiguration {
|
||||
verification.vehicle.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.vehicle.timing"));
|
||||
|
||||
verification.map.timing = Verification.Timing.valueOf(generalConfig.getString("verification.checks.map-captcha.timing"));
|
||||
verification.map.flare = generalConfig.getBoolean("verification.checks.map-captcha.effects.flare");
|
||||
verification.map.scratches = generalConfig.getBoolean("verification.checks.map-captcha.effects.scratches");
|
||||
verification.map.ripple = generalConfig.getBoolean("verification.checks.map-captcha.effects.ripple");
|
||||
verification.map.smear = generalConfig.getBoolean("verification.checks.map-captcha.effects.smear");
|
||||
verification.map.pinch = generalConfig.getBoolean("verification.checks.map-captcha.effects.pinch");
|
||||
verification.map.saturation = (float) generalConfig.getYaml().getDouble(
|
||||
"verification.checks.map-captcha.effects.saturation", 0.3);
|
||||
verification.map.distortion = (float) generalConfig.getYaml().getDouble(
|
||||
"verification.checks.map-captcha.effects.distortion", 2);
|
||||
verification.map.precomputeAmount = generalConfig.getInt("verification.checks.map-captcha.precompute");
|
||||
verification.map.maxDuration = generalConfig.getInt("verification.checks.map-captcha.max-duration");
|
||||
verification.map.bump = generalConfig.getBoolean("verification.checks.map-captcha.effects.bump");
|
||||
|
||||
verification.map.distortion.enabled = generalConfig.getBoolean("verification.checks.map-captcha.effects.distortion.enabled");
|
||||
verification.map.distortion.shape = generalConfig.getInt("verification.checks.map-captcha.effects.distortion.shape");
|
||||
verification.map.distortion.distance = generalConfig.getInt("verification.checks.map-captcha.effects.distortion.distance");
|
||||
verification.map.distortion.density = (float) generalConfig.getYaml().getDouble("verification.checks.map-captcha.effects.distortion.density");
|
||||
verification.map.distortion.mix = (float) generalConfig.getYaml().getDouble("verification.checks.map-captcha.effects.distortion.mix");
|
||||
|
||||
final String backgroundImagePath = generalConfig.getString("verification.checks.map-captcha.background");
|
||||
if (!backgroundImagePath.isEmpty()) {
|
||||
verification.map.backgroundImage = new File(pluginFolder, backgroundImagePath);
|
||||
if (!verification.map.backgroundImage.exists()) {
|
||||
Sonar.get().getLogger().error("The background image does not exist! Please check the configuration.");
|
||||
}
|
||||
} else {
|
||||
verification.map.backgroundImage = null;
|
||||
}
|
||||
|
||||
verification.map.autoColor = generalConfig.getBoolean("verification.checks.map-captcha.auto-color");
|
||||
verification.map.precomputeAmount = clamp(generalConfig.getInt("verification.checks.map-captcha.precompute"), 1, 1000);
|
||||
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.dictionary = generalConfig.getString("verification.checks.map-captcha.dictionary");
|
||||
verification.map.fonts = generalConfig.getStringList("verification.checks.map-captcha.font-names");
|
||||
|
||||
verification.brand.enabled = generalConfig.getBoolean("verification.checks.client-brand.enabled");
|
||||
verification.brand.validRegex = Pattern.compile(generalConfig.getString("verification.checks.client-brand.valid-regex"));
|
||||
@@ -317,7 +328,6 @@ public final class SonarConfiguration {
|
||||
verification.successLog = formatString(messagesConfig.getString("verification.logs.successful"));
|
||||
|
||||
verification.map.enterCode = deserialize(formatString(messagesConfig.getString("verification.captcha.enter-code")));
|
||||
verification.map.enterCodeActionBar = formatString(messagesConfig.getString("verification.captcha.action-bar"));
|
||||
verification.map.failedCaptcha = deserialize(formatString(messagesConfig.getString("verification.captcha.incorrect")));
|
||||
verification.currentlyPreparing = deserialize(fromList(messagesConfig.getStringList("verification.currently-preparing")));
|
||||
verification.tooFastReconnect = deserialize(fromList(messagesConfig.getStringList("verification.too-fast-reconnect")));
|
||||
@@ -352,7 +362,11 @@ public final class SonarConfiguration {
|
||||
}
|
||||
|
||||
private static int clamp(final int v, final int max, final int min) {
|
||||
return Math.max(Math.min(v, min), max);
|
||||
final int output = Math.max(Math.min(v, min), max);
|
||||
if (output != v) {
|
||||
Sonar.get().getLogger().warn("Clamped configuration value {} to {}", v, output);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public String formatAddress(final InetAddress inetAddress) {
|
||||
@@ -457,21 +471,28 @@ public final class SonarConfiguration {
|
||||
@Getter
|
||||
public static final class Map {
|
||||
private Timing timing;
|
||||
private boolean flare;
|
||||
private boolean scratches;
|
||||
private boolean ripple;
|
||||
private boolean smear;
|
||||
private boolean pinch;
|
||||
private float saturation;
|
||||
private float distortion;
|
||||
private boolean bump;
|
||||
private File backgroundImage;
|
||||
private boolean autoColor;
|
||||
private int precomputeAmount;
|
||||
private int maxDuration;
|
||||
private int maxTries;
|
||||
private String dictionary;
|
||||
private Component enterCode;
|
||||
private Component failedCaptcha;
|
||||
private String enterCodeActionBar;
|
||||
private List<String> fonts;
|
||||
|
||||
private Smear distortion = new Smear();
|
||||
|
||||
@Getter
|
||||
public static final class Smear {
|
||||
private boolean enabled;
|
||||
private int shape;
|
||||
private int distance;
|
||||
private float density;
|
||||
private float mix;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
@@ -13,7 +13,8 @@ bukkit {
|
||||
authors = listOf("Jones Development", "Sonar Contributors")
|
||||
website = "https://jonesdev.xyz/discord/"
|
||||
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
|
||||
softDepend = listOf("Geyser-Spigot", "floodgate", "Protocolize", "packetevents", "ProtocolLib", "ViaVersion")
|
||||
softDepend = listOf("Geyser-Spigot", "floodgate", "Protocolize", "ProtocolSupport",
|
||||
"ViaVersion", "packetevents", "ProtocolLib", "FastLogin")
|
||||
foliaSupported = true
|
||||
|
||||
commands {
|
||||
@@ -36,12 +37,8 @@ dependencies {
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.3.2")
|
||||
implementation("net.kyori:adventure-platform-api:4.3.2")
|
||||
implementation("net.kyori:adventure-platform-facet:4.3.2")
|
||||
|
||||
// adventure minimessage
|
||||
compileOnly("net.kyori:adventure-text-minimessage:4.16.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.16.0")
|
||||
// adventure nbt
|
||||
implementation("net.kyori:adventure-nbt:4.16.0")
|
||||
implementation("net.kyori:adventure-nbt:4.17.0")
|
||||
|
||||
// We have to use 1.8 for backwards compatibility
|
||||
compileOnly("org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT")
|
||||
|
||||
@@ -40,9 +40,8 @@ public final class SonarBukkit extends SonarBootstrap<SonarBukkitPlugin> {
|
||||
public static SonarBukkit INSTANCE;
|
||||
|
||||
public SonarBukkit(final @NotNull SonarBukkitPlugin plugin) {
|
||||
super(plugin, new BukkitLibraryManager(
|
||||
plugin, plugin.getDataFolder().getName()),
|
||||
plugin.getDataFolder(), SonarPlatform.BUKKIT);
|
||||
super(plugin, SonarPlatform.BUKKIT, plugin.getDataFolder(),
|
||||
new BukkitLibraryManager(plugin, plugin.getDataFolder().getName()));
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
@@ -116,7 +115,9 @@ public final class SonarBukkit extends SonarBootstrap<SonarBukkitPlugin> {
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
// Make sure to properly shutdown bStats metrics
|
||||
metrics.shutdown();
|
||||
if (metrics != null) {
|
||||
// Make sure to properly shutdown bStats metrics
|
||||
metrics.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ bungee {
|
||||
version = rootProject.version.toString().split("-")[0]
|
||||
main = "xyz.jonesdev.sonar.bungee.SonarBungeePlugin"
|
||||
author = "Jones Development, Sonar Contributors"
|
||||
softDepends = setOf("Geyser-BungeeCord", "floodgate", "Protocolize", "ViaVersion")
|
||||
softDepends = setOf("Geyser-BungeeCord", "floodgate", "Protocolize", "ViaVersion", "packetevents", "FastLogin")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -23,12 +23,8 @@ dependencies {
|
||||
implementation("net.kyori:adventure-platform-bungeecord:4.3.2")
|
||||
implementation("net.kyori:adventure-platform-api:4.3.2")
|
||||
implementation("net.kyori:adventure-platform-facet:4.3.2")
|
||||
|
||||
// adventure minimessage
|
||||
compileOnly("net.kyori:adventure-text-minimessage:4.16.0")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.16.0")
|
||||
// adventure nbt
|
||||
implementation("net.kyori:adventure-nbt:4.16.0")
|
||||
implementation("net.kyori:adventure-nbt:4.17.0")
|
||||
|
||||
// Implement bStats.org for metrics
|
||||
implementation("org.bstats:bstats-bungeecord:3.0.2")
|
||||
|
||||
@@ -41,7 +41,7 @@ public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
|
||||
public static SonarBungee INSTANCE;
|
||||
|
||||
public SonarBungee(final @NotNull SonarBungeePlugin plugin) {
|
||||
super(plugin, new BungeeLibraryManager(plugin), plugin.getDataFolder(), SonarPlatform.BUNGEE);
|
||||
super(plugin, SonarPlatform.BUNGEE, plugin.getDataFolder(), new BungeeLibraryManager(plugin));
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,9 @@ public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
// Make sure to properly shutdown bStats metrics
|
||||
metrics.shutdown();
|
||||
if (metrics != null) {
|
||||
// Make sure to properly shutdown bStats metrics
|
||||
metrics.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -22,19 +22,21 @@ import io.netty.channel.ChannelInitializer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xyz.jonesdev.sonar.api.ReflectiveOperationException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static net.md_5.bungee.netty.PipelineUtils.PACKET_DECODER;
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_HANDLER;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackChannelInitializer extends ChannelInitializer<Channel> {
|
||||
private static final Method INIT_CHANNEL_METHOD;
|
||||
private static final MethodHandle INIT_CHANNEL_METHOD;
|
||||
|
||||
static {
|
||||
try {
|
||||
INIT_CHANNEL_METHOD = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
INIT_CHANNEL_METHOD.setAccessible(true);
|
||||
INIT_CHANNEL_METHOD = MethodHandles.privateLookupIn(ChannelInitializer.class, MethodHandles.lookup())
|
||||
.findVirtual(ChannelInitializer.class, "initChannel", MethodType.methodType(void.class, Channel.class));
|
||||
} catch (Throwable throwable) {
|
||||
throw new ReflectiveOperationException(throwable);
|
||||
}
|
||||
@@ -46,7 +48,7 @@ public final class FallbackChannelInitializer extends ChannelInitializer<Channel
|
||||
protected void initChannel(final Channel channel) throws Exception {
|
||||
// Invoke the original method
|
||||
try {
|
||||
INIT_CHANNEL_METHOD.invoke(originalChannelInitializer, channel);
|
||||
INIT_CHANNEL_METHOD.invokeExact(originalChannelInitializer, channel);
|
||||
} catch (Throwable throwable) {
|
||||
throw new ReflectiveOperationException(throwable);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ dependencies {
|
||||
compileOnly(project(":api"))
|
||||
|
||||
// adventure nbt for packets
|
||||
compileOnly("net.kyori:adventure-nbt:4.16.0")
|
||||
compileOnly("net.kyori:adventure-nbt:4.17.0")
|
||||
|
||||
// CAPTCHA image generation
|
||||
implementation("xyz.jonesdev.capja:capja:0.1.2")
|
||||
implementation("xyz.jonesdev:capja:1.0.3")
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
|
||||
@@ -21,12 +21,11 @@ import com.alessiodp.libby.Library;
|
||||
import com.alessiodp.libby.LibraryManager;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.SonarPlatform;
|
||||
|
||||
@UtilityClass
|
||||
class LibraryLoader {
|
||||
void loadLibraries(final @NotNull LibraryManager libraryManager) {
|
||||
void loadLibraries(final @NotNull LibraryManager libraryManager, final @NotNull SonarPlatform platform) {
|
||||
libraryManager.addMavenCentral();
|
||||
libraryManager.addJitPack();
|
||||
libraryManager.loadLibraries(
|
||||
@@ -74,19 +73,19 @@ class LibraryLoader {
|
||||
.build()
|
||||
);
|
||||
|
||||
// Only load adventure dependencies if needed
|
||||
if (Sonar.get().getPlatform() != SonarPlatform.VELOCITY) {
|
||||
// Only load adventure if not on Velocity
|
||||
if (platform != SonarPlatform.VELOCITY) {
|
||||
libraryManager.loadLibraries(
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-minimessage")
|
||||
.version("4.16.0")
|
||||
.version("4.17.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-serializer-gson")
|
||||
.version("4.16.0")
|
||||
.version("4.17.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build()
|
||||
);
|
||||
|
||||
@@ -54,27 +54,22 @@ public abstract class SonarBootstrap<T> implements Sonar {
|
||||
private Notification notificationHandler;
|
||||
private SonarConfiguration config;
|
||||
private VerifiedPlayerController verifiedPlayerController;
|
||||
private File dataDirectory;
|
||||
private final LibraryManager libraryManager;
|
||||
private final SonarStatistics statistics;
|
||||
private final SonarPlatform platform;
|
||||
private final SubcommandRegistry subcommandRegistry;
|
||||
private final SystemTimer launchTimer = new SystemTimer();
|
||||
|
||||
public SonarBootstrap(final @NotNull T plugin,
|
||||
final LibraryManager libraryManager,
|
||||
final File dataDirectory,
|
||||
final SonarPlatform platform) {
|
||||
final @NotNull SonarPlatform platform,
|
||||
final @NotNull File dataDirectory,
|
||||
final @NotNull LibraryManager libraryManager) {
|
||||
// Load all libraries before anything else
|
||||
LibraryLoader.loadLibraries(libraryManager, platform);
|
||||
// Set the Sonar API
|
||||
SonarSupplier.set(this);
|
||||
// Store our library manager for the API
|
||||
this.libraryManager = libraryManager;
|
||||
// Set the plugin instance
|
||||
this.plugin = plugin;
|
||||
this.dataDirectory = dataDirectory;
|
||||
this.platform = platform;
|
||||
// Load all libraries before anything else
|
||||
LibraryLoader.loadLibraries(libraryManager);
|
||||
// Load the rest of the components
|
||||
this.statistics = new GlobalSonarStatistics();
|
||||
this.verboseHandler = new Verbose();
|
||||
@@ -136,6 +131,7 @@ public abstract class SonarBootstrap<T> implements Sonar {
|
||||
}
|
||||
|
||||
// Prepare cached packets
|
||||
getLogger().info("Taking cached snapshots of all packets...");
|
||||
FallbackPreparer.prepare();
|
||||
|
||||
// Update ratelimiter caches
|
||||
@@ -177,8 +173,10 @@ public abstract class SonarBootstrap<T> implements Sonar {
|
||||
getLogger().info("Starting shutdown process...");
|
||||
// Interrupt threads
|
||||
SonarServiceThreadManager.stop();
|
||||
// Close database connection
|
||||
verifiedPlayerController.close();
|
||||
// Close database connection if present
|
||||
if (verifiedPlayerController != null) {
|
||||
verifiedPlayerController.close();
|
||||
}
|
||||
// Run the per-platform disable method
|
||||
disable();
|
||||
// Thank the user for using Sonar
|
||||
|
||||
+3
-4
@@ -28,9 +28,8 @@ import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.Fallback;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.utility.geyser.GeyserUtil;
|
||||
import xyz.jonesdev.sonar.common.util.GeyserDetection;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -154,7 +153,7 @@ public class FallbackChannelHandlerAdapter extends ChannelInboundHandlerAdapter
|
||||
}
|
||||
|
||||
// Completely skip Geyser connections if configured
|
||||
final boolean geyser = GeyserUtil.isGeyserConnection(channel, socketAddress);
|
||||
final boolean geyser = GeyserDetection.isGeyserConnection(channel, socketAddress);
|
||||
if (geyser && !Sonar.get().getConfig().getVerification().isCheckGeyser()) {
|
||||
initialLogin(ctx, loginPacket, encoder, handler);
|
||||
return;
|
||||
@@ -235,7 +234,7 @@ public class FallbackChannelHandlerAdapter extends ChannelInboundHandlerAdapter
|
||||
// Check if the number of online players using the same IP address as
|
||||
// the connecting player is greater than the configured amount
|
||||
if (Sonar.get().hasTooManyAccounts(inetAddress, maxOnlinePerIp)) {
|
||||
customDisconnect(channel, protocolVersion, FallbackPreparer.tooManyOnlinePerIP, encoder, handler);
|
||||
customDisconnect(channel, protocolVersion, tooManyOnlinePerIP, encoder, handler);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -36,8 +36,7 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketDecoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginSuccessPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.DisconnectPacket;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
|
||||
@@ -47,6 +46,8 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.*;
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_20_2;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.CONFIG;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.GAME;
|
||||
|
||||
@Getter
|
||||
@ToString(of = {"protocolVersion", "inetAddress"})
|
||||
@@ -116,11 +117,10 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
}
|
||||
|
||||
// Send LoginSuccess packet to make the client think they are joining the server
|
||||
write(new LoginSuccessPacket(username, uuid));
|
||||
write(FallbackPreparer.LOGIN_SUCCESS);
|
||||
|
||||
// The LoginSuccess packet has been sent, now we can change the registry state
|
||||
newEncoder.updateRegistry(protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0
|
||||
? FallbackPacketRegistry.CONFIG : FallbackPacketRegistry.GAME);
|
||||
newEncoder.updateRegistry(protocolVersion.compareTo(MINECRAFT_1_20_2) >= 0 ? CONFIG : GAME);
|
||||
|
||||
try {
|
||||
// Prepare custom packet decoder and verification handler
|
||||
|
||||
+38
-40
@@ -21,7 +21,6 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import lombok.val;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
@@ -32,14 +31,14 @@ import xyz.jonesdev.sonar.api.fallback.FallbackUserState;
|
||||
import xyz.jonesdev.sonar.api.model.VerifiedPlayer;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.*;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.ItemType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.MapCaptchaInfo;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.captcha.ItemType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.captcha.MapCaptchaInfo;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.entity.EntityType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.config.FinishConfigurationPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginAcknowledgedPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.*;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.vehicle.EntityType;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
@@ -52,6 +51,8 @@ import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_PACKET_
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackUserState.*;
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.*;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.BRAND_CHANNEL;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.BRAND_CHANNEL_LEGACY;
|
||||
|
||||
public final class FallbackVerificationHandler implements FallbackPacketListener {
|
||||
private static final Random RANDOM = new Random();
|
||||
@@ -72,10 +73,8 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
private boolean receivedSteerBoat, receivedPlayerInput;
|
||||
|
||||
// CAPTCHA
|
||||
private final SystemTimer keepAlive = new SystemTimer();
|
||||
private final SystemTimer actionBar = new SystemTimer();
|
||||
private @Nullable MapCaptchaInfo captcha;
|
||||
private int captchaTriesLeft;
|
||||
private int captchaTriesLeft, lastCountdownIndex;
|
||||
|
||||
// Cached options to make sure the original values don't change throughout the verification
|
||||
private final boolean performVehicle, performCaptcha, performGravity, performCollisions, transfer;
|
||||
@@ -259,38 +258,35 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
|
||||
// Handle incoming chat messages
|
||||
if (packet instanceof UniversalChatPacket) {
|
||||
checkFrame(captcha != null, "Captcha not sent yet");
|
||||
final UniversalChatPacket chat = (UniversalChatPacket) packet;
|
||||
if (!chat.getMessage().equals(captcha.getAnswer())) {
|
||||
// Captcha is incorrect
|
||||
checkFrame(captchaTriesLeft-- > 0, "failed captcha too often");
|
||||
user.write(incorrectCaptcha);
|
||||
final String answer = Objects.requireNonNull(captcha).getAnswer();
|
||||
|
||||
if (chat.getMessage().equals(answer)) {
|
||||
// Captcha is correct
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
// Captcha is correct
|
||||
finish();
|
||||
|
||||
// Captcha is incorrect
|
||||
checkFrame(captchaTriesLeft-- > 0, "failed captcha too often");
|
||||
user.write(incorrectCaptcha);
|
||||
return;
|
||||
}
|
||||
|
||||
// Every second
|
||||
if (actionBar.elapsed(user.getProtocolVersion().compareTo(MINECRAFT_1_8) < 0 ? 10_000L : 1_000L)) {
|
||||
final String actionBarMessage = Sonar.get().getConfig().getVerification().getMap().getEnterCodeActionBar();
|
||||
// Only send action bar if the message is actually supposed to be sent
|
||||
if (!actionBarMessage.isEmpty()) {
|
||||
final String timeLeft = String.format("%.0f", (maxDuration - login.delay()) / 1000D);
|
||||
user.write(new UniversalChatPacket(MiniMessage.miniMessage().deserialize(
|
||||
actionBarMessage.replace("%time-left%", timeLeft)), UniversalChatPacket.GAME_INFO_TYPE));
|
||||
// Make sure to reset the timer
|
||||
actionBar.reset();
|
||||
// Only expect idle (position) packets
|
||||
if (packet instanceof PlayerPositionPacket
|
||||
|| packet instanceof PlayerPositionLookPacket) {
|
||||
// A position packet is sent every second
|
||||
final long difference = maxDuration - login.delay();
|
||||
final int index = (int) (difference / 1000D);
|
||||
// Make sure we can actually safely get and send the packet
|
||||
if (lastCountdownIndex != index && index >= 0 && xpCountdown.length > index) {
|
||||
// Send the countdown using the experience bar
|
||||
user.write(xpCountdown[index]);
|
||||
// Send a KeepAlive packet to prevent timeout
|
||||
user.write(CAPTCHA_KEEP_ALIVE);
|
||||
}
|
||||
}
|
||||
|
||||
// Every 10 seconds
|
||||
if (keepAlive.elapsed(10_000L)) {
|
||||
// Send a KeepAlive packet to prevent timeout
|
||||
user.write(CAPTCHA_KEEP_ALIVE);
|
||||
// Make sure to reset the timer
|
||||
keepAlive.reset();
|
||||
lastCountdownIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +400,7 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
checkFrame(validateClientLocale(user, clientSettings.getLocale()), "invalid locale");
|
||||
|
||||
// Clients sometimes mess up the ClientSettings or PluginMessage packet.
|
||||
// Probably caused by some weird race condition in Minecraft 1.13+
|
||||
// Probably caused by some race condition in Minecraft 1.13+
|
||||
if (user.getState() == CLIENT_SETTINGS) {
|
||||
user.setState(PLUGIN_MESSAGE);
|
||||
}
|
||||
@@ -417,9 +413,11 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
if (packet instanceof PluginMessagePacket) {
|
||||
final PluginMessagePacket pluginMessage = (PluginMessagePacket) packet;
|
||||
|
||||
final boolean usingModernChannel = pluginMessage.getChannel().equals(BRAND_CHANNEL);
|
||||
final boolean usingLegacyChannel = pluginMessage.getChannel().equals(BRAND_CHANNEL_LEGACY);
|
||||
|
||||
// Only the brand channel is important, drop the rest
|
||||
if (pluginMessage.getChannel().equals("MC|Brand")
|
||||
|| pluginMessage.getChannel().equals("minecraft:brand")) {
|
||||
if (usingModernChannel || usingLegacyChannel) {
|
||||
// Check if the brand packet was sent twice,
|
||||
// which is not possible when using a vanilla Minecraft client.
|
||||
checkFrame(!resolvedClientBrand, "duplicate client brand packet");
|
||||
@@ -428,7 +426,7 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
// system ('minecraft:' + channel) and anything below 1.13 uses
|
||||
// the legacy namespace system ('MC|' + channel).
|
||||
final boolean v1_13 = user.getProtocolVersion().compareTo(MINECRAFT_1_13) >= 0;
|
||||
checkFrame(pluginMessage.getChannel().equals("MC|Brand") || v1_13, "invalid channel");
|
||||
checkFrame(usingLegacyChannel || v1_13, "invalid channel");
|
||||
|
||||
// Validate the client branding using a regex to filter unwanted characters.
|
||||
if (Sonar.get().getConfig().getVerification().getBrand().isEnabled()) {
|
||||
@@ -456,7 +454,7 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
// The transaction should always be accepted
|
||||
checkFrame(transaction.isAccepted(), "transaction not accepted?!");
|
||||
// Check if the transaction ID is valid
|
||||
checkFrame(transaction.getId() == expectedTransactionId, "invalid transaction id");
|
||||
checkFrame(transaction.getTransactionId() == expectedTransactionId, "invalid transaction id");
|
||||
|
||||
// First, send an Abilities packet to the client to make
|
||||
// sure the player falls even in spectator mode.
|
||||
@@ -506,8 +504,8 @@ public final class FallbackVerificationHandler implements FallbackPacketListener
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof PlayerTickPacket) {
|
||||
final PlayerTickPacket player = (PlayerTickPacket) packet;
|
||||
if (packet instanceof PlayerPositionIdlePacket) {
|
||||
final PlayerPositionIdlePacket player = (PlayerPositionIdlePacket) packet;
|
||||
handlePositionUpdate(posX, posY, posZ, player.isOnGround());
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -20,7 +20,10 @@ package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface FallbackPacket {
|
||||
UUID EMPTY_UUID = new UUID(0L, 0L);
|
||||
|
||||
/**
|
||||
* Encodes the packet sent by the server
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.Direction.SERVERBOUND;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.GAME;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.LOGIN;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.readVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readVarInt;
|
||||
|
||||
public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
private final FallbackUser user;
|
||||
|
||||
+6
-4
@@ -25,7 +25,7 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.Direction.CLIENTBOUND;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.LOGIN;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
public final class FallbackPacketEncoder extends MessageToByteEncoder<FallbackPacket> {
|
||||
private final ProtocolVersion protocolVersion;
|
||||
@@ -42,10 +42,12 @@ public final class FallbackPacketEncoder extends MessageToByteEncoder<FallbackPa
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx,
|
||||
final FallbackPacket msg,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final ByteBuf out) throws Exception {
|
||||
final int packetId = registry.getPacketId(msg);
|
||||
final FallbackPacket originalPacket = packet instanceof FallbackPacketSnapshot
|
||||
? ((FallbackPacketSnapshot) packet).getOriginalPacket() : packet;
|
||||
final int packetId = registry.getPacketId(originalPacket);
|
||||
writeVarInt(out, packetId);
|
||||
msg.encode(out, protocolVersion);
|
||||
packet.encode(out, protocolVersion);
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -33,7 +33,7 @@ import java.util.function.Supplier;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
|
||||
// Most of this is taken from
|
||||
// Mostly taken from
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
|
||||
public enum FallbackPacketRegistry {
|
||||
LOGIN {
|
||||
@@ -281,6 +281,21 @@ public enum FallbackPacketRegistry {
|
||||
map(0x12, MINECRAFT_1_19_3, true),
|
||||
map(0x14, MINECRAFT_1_19_4, true),
|
||||
map(0x15, MINECRAFT_1_20_2, true));
|
||||
clientbound.register(SetExperiencePacket.class, SetExperiencePacket::new,
|
||||
map(0x1F, MINECRAFT_1_7_2, true),
|
||||
map(0x3D, MINECRAFT_1_9, true),
|
||||
map(0x3F, MINECRAFT_1_12, true),
|
||||
map(0x40, MINECRAFT_1_12_1, true),
|
||||
map(0x43, MINECRAFT_1_13, true),
|
||||
map(0x47, MINECRAFT_1_14, true),
|
||||
map(0x48, MINECRAFT_1_15, true),
|
||||
map(0x51, MINECRAFT_1_17, true),
|
||||
map(0x54, MINECRAFT_1_19_1, true),
|
||||
map(0x52, MINECRAFT_1_19_3, true),
|
||||
map(0x56, MINECRAFT_1_19_4, true),
|
||||
map(0x58, MINECRAFT_1_20_2, true),
|
||||
map(0x5A, MINECRAFT_1_20_3, true),
|
||||
map(0x5C, MINECRAFT_1_20_5, true));
|
||||
clientbound.register(UniversalChatPacket.class, UniversalChatPacket::new,
|
||||
map(0x02, MINECRAFT_1_7_2, false),
|
||||
map(0x0F, MINECRAFT_1_9, false),
|
||||
@@ -416,7 +431,7 @@ public enum FallbackPacketRegistry {
|
||||
map(0x16, MINECRAFT_1_20_2, false),
|
||||
map(0x17, MINECRAFT_1_20_3, false),
|
||||
map(0x1A, MINECRAFT_1_20_5, false));
|
||||
serverbound.register(PlayerTickPacket.class, PlayerTickPacket::new,
|
||||
serverbound.register(PlayerPositionIdlePacket.class, PlayerPositionIdlePacket::new,
|
||||
map(0x03, MINECRAFT_1_7_2, false),
|
||||
map(0x0F, MINECRAFT_1_9, false),
|
||||
map(0x0D, MINECRAFT_1_12, false),
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.ID_TO_PROTOCOL_CONSTANT;
|
||||
|
||||
// Mostly taken from
|
||||
// https://github.com/Nan1t/NanoLimbo/blob/main/src/main/java/ua/nanit/limbo/protocol/PacketSnapshot.java
|
||||
@Getter
|
||||
public final class FallbackPacketSnapshot implements FallbackPacket {
|
||||
private final Map<Integer, Integer> mappings = new HashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
private final Map<Integer, byte[]> cachedBytes = new HashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
private final FallbackPacket originalPacket;
|
||||
|
||||
public FallbackPacketSnapshot(final @NotNull FallbackPacket originalPacket) {
|
||||
final Map<Integer, Integer> hashes = new HashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
|
||||
for (final ProtocolVersion protocolVersion : ID_TO_PROTOCOL_CONSTANT.values()) {
|
||||
// Allocate a buffer for each protocol version
|
||||
final ByteBuf byteBuf = Unpooled.buffer();
|
||||
try {
|
||||
originalPacket.encode(byteBuf, protocolVersion);
|
||||
} catch (Exception exception) {
|
||||
Sonar.get().getLogger().error("Could not encode packet {} for version {}: {}",
|
||||
originalPacket.toString(), protocolVersion, exception);
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure we don't unnecessarily fill the RAM
|
||||
final int protocol = protocolVersion.getProtocol();
|
||||
final int hash = byteBuf.hashCode();
|
||||
final int hashed = hashes.getOrDefault(hash, -1);
|
||||
if (hashed != -1) {
|
||||
mappings.put(protocol, hashed);
|
||||
} else {
|
||||
hashes.put(hash, protocol);
|
||||
mappings.put(protocol, protocol);
|
||||
// Cache the raw bytes of the encoded packet
|
||||
final byte[] bytes = new byte[byteBuf.readableBytes()];
|
||||
byteBuf.readBytes(bytes);
|
||||
cachedBytes.put(protocol, bytes);
|
||||
}
|
||||
// Make sure to release the buffer to avoid memory leaks
|
||||
byteBuf.release();
|
||||
}
|
||||
this.originalPacket = originalPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf,
|
||||
final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
final int hash = mappings.get(protocolVersion.getProtocol());
|
||||
final byte[] bytes = cachedBytes.get(hash);
|
||||
|
||||
if (bytes != null) {
|
||||
byteBuf.writeBytes(bytes);
|
||||
} else {
|
||||
Sonar.get().getLogger().error("Could not find cached packet {} for version {}",
|
||||
toString(), protocolVersion);
|
||||
throw new IllegalStateException("Unable to find cached packet. Contact the developer!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
+62
-43
@@ -20,36 +20,38 @@ package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockPosition;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.ChangedBlock;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockUpdate;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.captcha.CaptchaPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.CaptchaPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.config.FinishConfigurationPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.config.RegistryDataPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginSuccessPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@UtilityClass
|
||||
public class FallbackPreparer {
|
||||
|
||||
// LoginSuccess
|
||||
public final FallbackPacket LOGIN_SUCCESS = new FallbackPacketSnapshot(new LoginSuccessPacket(new UUID(1L, 1L), "Sonar"));
|
||||
// Abilities
|
||||
public final FallbackPacket DEFAULT_ABILITIES = new ClientAbilitiesPacket(0x00, 0f, 0f);
|
||||
public final FallbackPacket CAPTCHA_ABILITIES = new ClientAbilitiesPacket(0x02, 0f, 0f);
|
||||
public final FallbackPacket CAPTCHA_ABILITIES_BEDROCK = new ClientAbilitiesPacket(0x06, 0f, 0f);
|
||||
public final FallbackPacket DEFAULT_ABILITIES = new FallbackPacketSnapshot(new ClientAbilitiesPacket(0x00, 0f, 0f));
|
||||
public final FallbackPacket CAPTCHA_ABILITIES = new FallbackPacketSnapshot(new ClientAbilitiesPacket(0x02, 0f, 0f));
|
||||
public final FallbackPacket CAPTCHA_ABILITIES_BEDROCK = new FallbackPacketSnapshot(new ClientAbilitiesPacket(0x06, 0f, 0f));
|
||||
// Chunks
|
||||
public final FallbackPacket EMPTY_CHUNK_DATA = new ChunkDataPacket(0, 0);
|
||||
public final FallbackPacket EMPTY_CHUNK_DATA = new FallbackPacketSnapshot(new ChunkDataPacket(0, 0));
|
||||
// Finish Configuration
|
||||
public final FallbackPacket FINISH_CONFIGURATION = new FinishConfigurationPacket();
|
||||
public final FallbackPacket FINISH_CONFIGURATION = new FinishConfigurationPacket(); // No snapshot needed because it's empty either way
|
||||
// Synchronize Registry
|
||||
public final FallbackPacket REGISTRY_SYNC_LEGACY = new RegistryDataPacket(DimensionRegistry.CODEC_1_20, null, null);
|
||||
public final List<FallbackPacket> REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20);
|
||||
public final FallbackPacket REGISTRY_SYNC_LEGACY = new FallbackPacketSnapshot(new RegistryDataPacket(DimensionRegistry.CODEC_1_20, null, null));
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20);
|
||||
// Keep Alive
|
||||
public final FallbackPacket CAPTCHA_KEEP_ALIVE = new KeepAlivePacket(0L);
|
||||
public final FallbackPacket CAPTCHA_KEEP_ALIVE = new FallbackPacketSnapshot(new KeepAlivePacket(-1337L));
|
||||
// Game Event (1.20.3+)
|
||||
public final FallbackPacket START_WRITING_CHUNKS = new GameEventPacket(13, 0);
|
||||
public final FallbackPacket START_WRITING_CHUNKS = new FallbackPacketSnapshot(new GameEventPacket(13, 0));
|
||||
// Chat
|
||||
public FallbackPacket enterCodeMessage;
|
||||
public FallbackPacket incorrectCaptcha;
|
||||
@@ -84,13 +86,13 @@ public class FallbackPreparer {
|
||||
public final int DEFAULT_Y_COLLIDE_POSITION = 255; // 255 is the maximum Y position allowed
|
||||
|
||||
// Captcha position
|
||||
public final FallbackPacket CAPTCHA_POSITION = new PlayerPositionLookPacket(
|
||||
SPAWN_X_POSITION, 1337, SPAWN_Z_POSITION, 0f, 90f, 0, false);
|
||||
public final FallbackPacket CAPTCHA_SPAWN_POSITION = new DefaultSpawnPositionPacket(
|
||||
SPAWN_X_POSITION, 1337, SPAWN_Z_POSITION);
|
||||
public final FallbackPacket CAPTCHA_POSITION = new FallbackPacketSnapshot(new PlayerPositionLookPacket(
|
||||
SPAWN_X_POSITION, 1337, SPAWN_Z_POSITION, 0f, 90f, 0, false));
|
||||
public final FallbackPacket CAPTCHA_SPAWN_POSITION = new FallbackPacketSnapshot(new DefaultSpawnPositionPacket(
|
||||
SPAWN_X_POSITION, 1337, SPAWN_Z_POSITION));
|
||||
|
||||
// Blocks
|
||||
private final ChangedBlock[] CHANGED_BLOCKS = new ChangedBlock[BLOCKS_PER_ROW * BLOCKS_PER_ROW];
|
||||
private final BlockUpdate[] CHANGED_BLOCKS = new BlockUpdate[BLOCKS_PER_ROW * BLOCKS_PER_ROW];
|
||||
public BlockType blockType = BlockType.BARRIER;
|
||||
|
||||
public int maxMovementTick, dynamicSpawnYPosition;
|
||||
@@ -100,13 +102,18 @@ public class FallbackPreparer {
|
||||
// CAPTCHA
|
||||
public final CaptchaPreparer MAP_INFO_PREPARER = new CaptchaPreparer();
|
||||
|
||||
// XP packets
|
||||
public FallbackPacket[] xpCountdown;
|
||||
|
||||
public void prepare() {
|
||||
// Prepare JoinGame packet
|
||||
joinGame = new JoinGamePacket(PLAYER_ENTITY_ID,
|
||||
Sonar.get().getConfig().getVerification().getGravity().getGamemode().getId(),
|
||||
0, false, 0,
|
||||
true, false, false,
|
||||
new String[]{"minecraft:overworld"}, "minecraft:overworld");
|
||||
|
||||
// Prepare cached motions for the gravity check
|
||||
maxFallDistance = 0;
|
||||
maxMovementTick = Sonar.get().getConfig().getVerification().getGravity().getMaxMovementTicks();
|
||||
preparedCachedYMotions = new double[maxMovementTick + 8];
|
||||
@@ -119,49 +126,61 @@ public class FallbackPreparer {
|
||||
|
||||
// Set the dynamic block and collide Y position based on the maximum fall distance
|
||||
dynamicSpawnYPosition = DEFAULT_Y_COLLIDE_POSITION + (int) Math.ceil(maxFallDistance);
|
||||
dynamicSpawnPosition = new DefaultSpawnPositionPacket(SPAWN_X_POSITION, dynamicSpawnYPosition, SPAWN_Z_POSITION);
|
||||
dynamicSpawnPosition = new FallbackPacketSnapshot(new DefaultSpawnPositionPacket(
|
||||
SPAWN_X_POSITION, dynamicSpawnYPosition, SPAWN_Z_POSITION));
|
||||
|
||||
// Prepare collision platform positions
|
||||
int index = 0;
|
||||
for (int x = 0; x < BLOCKS_PER_ROW; x++) {
|
||||
for (int z = 0; z < BLOCKS_PER_ROW; z++) {
|
||||
final BlockPosition position = new BlockPosition(
|
||||
final BlockUpdate.BlockPosition position = new BlockUpdate.BlockPosition(
|
||||
x + (BLOCKS_PER_ROW / 2),
|
||||
DEFAULT_Y_COLLIDE_POSITION,
|
||||
z + (BLOCKS_PER_ROW / 2),
|
||||
0, 0);
|
||||
CHANGED_BLOCKS[index++] = new ChangedBlock(position, blockType);
|
||||
CHANGED_BLOCKS[index++] = new BlockUpdate(position, blockType);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare UpdateSectionBlocks packet
|
||||
updateSectionBlocks = new UpdateSectionBlocksPacket(0, 0, CHANGED_BLOCKS);
|
||||
updateSectionBlocks = new FallbackPacketSnapshot(new UpdateSectionBlocksPacket(0, 0, CHANGED_BLOCKS));
|
||||
|
||||
// Prepare disconnect packets during login
|
||||
blacklisted = DisconnectPacket.create(Sonar.get().getConfig().getVerification().getBlacklisted(), true);
|
||||
alreadyVerifying = DisconnectPacket.create(Sonar.get().getConfig().getVerification().getAlreadyVerifying(), true);
|
||||
alreadyQueued = DisconnectPacket.create(Sonar.get().getConfig().getVerification().getAlreadyQueued(), true);
|
||||
protocolBlacklisted = DisconnectPacket.create(Sonar.get().getConfig().getVerification().getProtocolBlacklisted(), true);
|
||||
reconnectedTooFast = DisconnectPacket.create(Sonar.get().getConfig().getVerification().getTooFastReconnect(), true);
|
||||
invalidUsername = DisconnectPacket.create(Sonar.get().getConfig().getVerification().getInvalidUsername(), true);
|
||||
tooManyOnlinePerIP = DisconnectPacket.create(Sonar.get().getConfig().getTooManyOnlinePerIp(), true);
|
||||
blacklisted = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getBlacklisted(), true));
|
||||
alreadyVerifying = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getAlreadyVerifying(), true));
|
||||
alreadyQueued = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
invalidUsername = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getInvalidUsername(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getTooManyOnlinePerIp(), true));
|
||||
|
||||
// Precompute captcha answers
|
||||
if (Sonar.get().getConfig().getVerification().getMap().getTiming() != SonarConfiguration.Verification.Timing.NEVER
|
||||
|| Sonar.get().getConfig().getVerification().getGravity().isCaptchaOnFail()) {
|
||||
enterCodeMessage = new UniversalChatPacket(Sonar.get().getConfig().getVerification().getMap().getEnterCode(), UniversalChatPacket.SYSTEM_TYPE);
|
||||
incorrectCaptcha = new UniversalChatPacket(
|
||||
Sonar.get().getConfig().getVerification().getMap().getFailedCaptcha(), UniversalChatPacket.SYSTEM_TYPE);
|
||||
|
||||
MAP_INFO_PREPARER.prepare();
|
||||
}
|
||||
|
||||
transferToOrigin = new TransferPacket(
|
||||
// Prepare transfer packet
|
||||
transferToOrigin = new FallbackPacketSnapshot(new TransferPacket(
|
||||
Sonar.get().getConfig().getVerification().getTransfer().getHost(),
|
||||
Sonar.get().getConfig().getVerification().getTransfer().getPort());
|
||||
Sonar.get().getConfig().getVerification().getTransfer().getPort()));
|
||||
|
||||
// Prepare packets for the vehicle check
|
||||
removeEntities = new RemoveEntitiesPacket(VEHICLE_ENTITY_ID);
|
||||
setPassengers = new SetPassengersPacket(VEHICLE_ENTITY_ID, PLAYER_ENTITY_ID);
|
||||
removeEntities = new FallbackPacketSnapshot(new RemoveEntitiesPacket(VEHICLE_ENTITY_ID));
|
||||
setPassengers = new FallbackPacketSnapshot(new SetPassengersPacket(VEHICLE_ENTITY_ID, PLAYER_ENTITY_ID));
|
||||
|
||||
if (Sonar.get().getConfig().getVerification().getMap().getTiming() != SonarConfiguration.Verification.Timing.NEVER
|
||||
|| Sonar.get().getConfig().getVerification().getGravity().isCaptchaOnFail()) {
|
||||
// Prepare CAPTCHA messages
|
||||
enterCodeMessage = new FallbackPacketSnapshot(new UniversalChatPacket(
|
||||
Sonar.get().getConfig().getVerification().getMap().getEnterCode(), UniversalChatPacket.SYSTEM_TYPE));
|
||||
incorrectCaptcha = new FallbackPacketSnapshot(new UniversalChatPacket(
|
||||
Sonar.get().getConfig().getVerification().getMap().getFailedCaptcha(), UniversalChatPacket.SYSTEM_TYPE));
|
||||
|
||||
// Prepare countdown
|
||||
xpCountdown = new FallbackPacket[Sonar.get().getConfig().getVerification().getMap().getMaxDuration() / 1000];
|
||||
|
||||
for (int i = 0; i < xpCountdown.length; i++) {
|
||||
final float bar = (float) i / xpCountdown.length;
|
||||
xpCountdown[i] = new FallbackPacketSnapshot(new SetExperiencePacket(bar, i, i));
|
||||
}
|
||||
|
||||
// Prepare CAPTCHA answers
|
||||
MAP_INFO_PREPARER.prepare();
|
||||
}
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.block;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class BlockPosition {
|
||||
private final int x, y, z;
|
||||
private final int chunkX, chunkZ;
|
||||
}
|
||||
+12
-2
@@ -18,15 +18,17 @@
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.block;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Getter
|
||||
public final class ChangedBlock {
|
||||
public final class BlockUpdate {
|
||||
private final @NotNull BlockPosition position;
|
||||
private final BlockType type;
|
||||
private final int legacyBlockState, blockState;
|
||||
|
||||
public ChangedBlock(final @NotNull BlockPosition position, final BlockType type) {
|
||||
public BlockUpdate(final @NotNull BlockPosition position, final BlockType type) {
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
final int x = position.getX() - (position.getChunkX() << 4);
|
||||
@@ -35,4 +37,12 @@ public final class ChangedBlock {
|
||||
this.legacyBlockState = x << 12 | z << 8 | y;
|
||||
this.blockState = x << 8 | z << 4 | y - ((y >> 4) << 4);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public static final class BlockPosition {
|
||||
private final int x, y, z;
|
||||
private final int chunkX, chunkZ;
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.captcha;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.capja.SimpleCaptchaGenerator;
|
||||
import xyz.jonesdev.capja.filter.SimpleRippleFilter;
|
||||
import xyz.jonesdev.capja.filter.SimpleScratchFilter;
|
||||
import xyz.jonesdev.capja.libs.jhlabs.image.AbstractBufferedImageOp;
|
||||
import xyz.jonesdev.capja.libs.jhlabs.image.BumpFilter;
|
||||
import xyz.jonesdev.capja.libs.jhlabs.image.SmearFilter;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class CaptchaPreparer {
|
||||
private static final ExecutorService PREPARATION_SERVICE = Executors.newSingleThreadExecutor();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private MapCaptchaInfo[] cached;
|
||||
private int preparedAmount;
|
||||
|
||||
public void prepare() {
|
||||
// Make sure we're not preparing when Sonar is already preparing answers
|
||||
if (cached != null && preparedAmount != cached.length) return;
|
||||
preparedAmount = 0;
|
||||
|
||||
final SystemTimer timer = new SystemTimer();
|
||||
Sonar.get().getLogger().info("Asynchronously preparing CAPTCHA answers...");
|
||||
Sonar.get().getLogger().info("Players will be able to join even if the preparation isn't finished");
|
||||
|
||||
// Prepare cache
|
||||
final SonarConfiguration.Verification.Map config = Sonar.get().getConfig().getVerification().getMap();
|
||||
cached = new MapCaptchaInfo[config.getPrecomputeAmount()];
|
||||
|
||||
// Prepare everything asynchronously
|
||||
PREPARATION_SERVICE.execute(() -> {
|
||||
// Create the images using capja
|
||||
final @Nullable File backgroundImage = Sonar.get().getConfig().getVerification().getMap().getBackgroundImage();
|
||||
final SimpleCaptchaGenerator generator = new SimpleCaptchaGenerator(128, 128, backgroundImage);
|
||||
final char[] dictionary = config.getDictionary().toCharArray();
|
||||
|
||||
// Prepare the filters for the CAPTCHA
|
||||
final List<AbstractBufferedImageOp> filters = new ArrayList<>();
|
||||
if (Sonar.get().getConfig().getVerification().getMap().isScratches()) {
|
||||
filters.add(new SimpleScratchFilter(5));
|
||||
}
|
||||
if (Sonar.get().getConfig().getVerification().getMap().isRipple()) {
|
||||
final SimpleRippleFilter rippleFilter = new SimpleRippleFilter();
|
||||
rippleFilter.setXAmplitude(0);
|
||||
float yAmplitude = 10 - ThreadLocalRandom.current().nextInt(20);
|
||||
if (Math.abs(yAmplitude) < 3) {
|
||||
yAmplitude = yAmplitude >= 0 ? 3 : -3;
|
||||
}
|
||||
rippleFilter.setYAmplitude(yAmplitude);
|
||||
filters.add(rippleFilter);
|
||||
}
|
||||
if (Sonar.get().getConfig().getVerification().getMap().getDistortion().isEnabled()) {
|
||||
final SmearFilter smearFilter = new SmearFilter();
|
||||
smearFilter.setShape(Sonar.get().getConfig().getVerification().getMap().getDistortion().getShape());
|
||||
smearFilter.setMix(Sonar.get().getConfig().getVerification().getMap().getDistortion().getMix());
|
||||
smearFilter.setDensity(Sonar.get().getConfig().getVerification().getMap().getDistortion().getDensity());
|
||||
smearFilter.setDistance(Sonar.get().getConfig().getVerification().getMap().getDistortion().getDistance());
|
||||
filters.add(smearFilter);
|
||||
}
|
||||
if (Sonar.get().getConfig().getVerification().getMap().isBump()) {
|
||||
filters.add(new BumpFilter());
|
||||
}
|
||||
|
||||
for (preparedAmount = 0; preparedAmount < config.getPrecomputeAmount(); preparedAmount++) {
|
||||
if (!Sonar.get().getConfig().getVerification().getMap().isAutoColor()) {
|
||||
// Generate a random gradient color if automatic coloring is disabled
|
||||
final Color color0 = Color.getHSBColor((float) Math.random(), 1, 1);
|
||||
final Color color1 = Color.getHSBColor((float) Math.random(), 1, 0.5f);
|
||||
final GradientPaint gradient = new GradientPaint(0, 0, color0,
|
||||
generator.getWidth(), generator.getHeight(), color1);
|
||||
generator.setGradient(gradient);
|
||||
}
|
||||
// Generate CAPTCHA answer
|
||||
final char[] answer = new char[5];
|
||||
for (int j = 0; j < answer.length; j++) {
|
||||
answer[j] = dictionary[ThreadLocalRandom.current().nextInt(dictionary.length)];
|
||||
}
|
||||
final BufferedImage image = generator.createImage(answer, filters);
|
||||
// Convert and cache converted Minecraft map bytes
|
||||
final int[] buffer = MapColorPalette.getBufferFromImage(image);
|
||||
cached[preparedAmount] = new MapCaptchaInfo(new String(answer), buffer);
|
||||
}
|
||||
|
||||
Sonar.get().getLogger().info("Finished preparing {} CAPTCHA answers ({}s)!", preparedAmount, timer);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isCaptchaAvailable() {
|
||||
return cached != null && cached[0] != null;
|
||||
}
|
||||
|
||||
public MapCaptchaInfo getRandomCaptcha() {
|
||||
// Give the player a random CAPTCHA out of the ones that we've already prepared
|
||||
return cached[RANDOM.nextInt(preparedAmount)];
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.map;
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.captcha;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
+15
-16
@@ -15,11 +15,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.map;
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.captcha;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.MapDataPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_8;
|
||||
@@ -27,22 +28,20 @@ import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT
|
||||
@Getter
|
||||
public final class MapCaptchaInfo {
|
||||
private final String answer;
|
||||
private final byte[] buffer;
|
||||
|
||||
private final MapDataPacket[] legacy;
|
||||
private final MapDataPacket modern;
|
||||
private final FallbackPacket[] legacy;
|
||||
private final FallbackPacket modern;
|
||||
|
||||
public MapCaptchaInfo(final @NotNull String answer, final byte @NotNull [] buffer) {
|
||||
public MapCaptchaInfo(final @NotNull String answer, final int @NotNull [] buffer) {
|
||||
this.answer = answer;
|
||||
this.buffer = buffer;
|
||||
|
||||
// Prepare 1.7 map data using a grid
|
||||
final byte[][] grid = new byte[128][128];
|
||||
final int[][] grid = new int[128][128];
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
final byte buf = buffer[i];
|
||||
final int buf = buffer[i];
|
||||
grid[i & Byte.MAX_VALUE][i >> 7] = buf;
|
||||
}
|
||||
this.legacy = new MapDataPacket[grid.length];
|
||||
this.legacy = new FallbackPacket[grid.length];
|
||||
for (int i = 0; i < grid.length; i++) {
|
||||
this.legacy[i] = new MapDataPacket(grid[i], i, 0);
|
||||
}
|
||||
@@ -52,14 +51,14 @@ public final class MapCaptchaInfo {
|
||||
}
|
||||
|
||||
public void delayedWrite(final @NotNull FallbackUser user) {
|
||||
if (user.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) {
|
||||
user.delayedWrite(modern);
|
||||
if (user.getProtocolVersion().compareTo(MINECRAFT_1_8) < 0) {
|
||||
// 1.7.2-1.7.10 needs separate packets for each axis
|
||||
for (final FallbackPacket legacyPacket : legacy) {
|
||||
user.delayedWrite(legacyPacket);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 1.7.2-1.7.10
|
||||
for (final MapDataPacket legacyPacket : legacy) {
|
||||
user.delayedWrite(legacyPacket);
|
||||
}
|
||||
// Send modern packet
|
||||
user.delayedWrite(modern);
|
||||
}
|
||||
}
|
||||
+44
-28
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.map;
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.captcha;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,10 +26,10 @@ import java.awt.image.BufferedImage;
|
||||
public class MapColorPalette {
|
||||
// https://minecraft.wiki/w/Map_item_format#Full_color_tables
|
||||
public static final int[] COLOR_MAP = {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
-16777216,
|
||||
-16777216,
|
||||
-16777216,
|
||||
-16777216,
|
||||
-10912473,
|
||||
-9594576,
|
||||
-8408520,
|
||||
@@ -38,10 +38,10 @@ public class MapColorPalette {
|
||||
-2766452,
|
||||
-530013,
|
||||
-8225962,
|
||||
-7697782,
|
||||
-5658199,
|
||||
-3815995,
|
||||
-9934744,
|
||||
-7566196,
|
||||
-5526613,
|
||||
-3684409,
|
||||
-9868951,
|
||||
-4980736,
|
||||
-2359296,
|
||||
-65536,
|
||||
@@ -66,22 +66,22 @@ public class MapColorPalette {
|
||||
-7499618,
|
||||
-5986120,
|
||||
-11118495,
|
||||
-8304095,
|
||||
-6464728,
|
||||
-4756945,
|
||||
-10471400,
|
||||
-9810890,
|
||||
-8233406,
|
||||
-6853299,
|
||||
-11585240,
|
||||
-11579569,
|
||||
-10461088,
|
||||
-9408400,
|
||||
-12895429,
|
||||
-10136525,
|
||||
-8689858,
|
||||
-7375032,
|
||||
-11780314,
|
||||
-13816396,
|
||||
-13158436,
|
||||
-12566273,
|
||||
-14605945,
|
||||
-10202062,
|
||||
-8690114,
|
||||
-7375032,
|
||||
-11845850,
|
||||
-4935252,
|
||||
-2303533,
|
||||
-779,
|
||||
@@ -153,19 +153,34 @@ public class MapColorPalette {
|
||||
-12543338,
|
||||
-11551561,
|
||||
-10691627,
|
||||
-13601936,
|
||||
-13346124,
|
||||
-12620068,
|
||||
-11894529,
|
||||
-14204025,
|
||||
-16738008,
|
||||
-16729294,
|
||||
-16721606,
|
||||
-16748002,
|
||||
-10798046,
|
||||
-9483734,
|
||||
-8301007,
|
||||
-12309223,
|
||||
-11599616,
|
||||
-10485504,
|
||||
-9436672,
|
||||
-12910336,
|
||||
};
|
||||
|
||||
public byte[] getBufferFromImage(final @NotNull BufferedImage bufferedImage) {
|
||||
final int width = bufferedImage.getWidth();
|
||||
final int height = bufferedImage.getHeight();
|
||||
public int[] getBufferFromImage(final @NotNull BufferedImage bufferedImage) {
|
||||
final int[] buffer = new int[128 * 128];
|
||||
|
||||
final int[] pixels = new int[128 * 128];
|
||||
final byte[] buffer = new byte[128 * 128];
|
||||
bufferedImage.getRGB(0, 0,
|
||||
bufferedImage.getWidth(), bufferedImage.getHeight(),
|
||||
buffer, 0, bufferedImage.getWidth());
|
||||
|
||||
bufferedImage.getRGB(0, 0, width, height, pixels, 0, width);
|
||||
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
buffer[i] = mapColorToMinecraft(pixels[i]);
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
buffer[i] = mapColorToMinecraft(buffer[i]);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
@@ -173,11 +188,12 @@ public class MapColorPalette {
|
||||
private byte mapColorToMinecraft(final int argb) {
|
||||
int minDistance = Integer.MAX_VALUE;
|
||||
byte closestIndex = 0;
|
||||
for (byte i = 0; i < COLOR_MAP.length; i++) {
|
||||
for (int i = 0; i < COLOR_MAP.length; i++) {
|
||||
final byte index = (byte) (i < 128 ? i : -129 + (i - 127));
|
||||
final int distance = calculateColorDistance(argb, COLOR_MAP[i]);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestIndex = i;
|
||||
closestIndex = index;
|
||||
}
|
||||
}
|
||||
return closestIndex;
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.vehicle;
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.entity;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.map;
|
||||
|
||||
import xyz.jonesdev.capja.CaptchaGenerator;
|
||||
import xyz.jonesdev.capja.CaptchaHolder;
|
||||
import xyz.jonesdev.capja.config.CaptchaConfiguration;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public final class CaptchaPreparer {
|
||||
private static final ExecutorService PREPARATION_SERVICE = Executors.newSingleThreadExecutor();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private MapCaptchaInfo[] cached;
|
||||
private int preparedAmount;
|
||||
|
||||
public void prepare() {
|
||||
// Make sure we're not preparing when Sonar is already preparing answers
|
||||
if (cached != null && preparedAmount != cached.length) return;
|
||||
preparedAmount = 0;
|
||||
|
||||
final SystemTimer timer = new SystemTimer();
|
||||
Sonar.get().getLogger().info("Asynchronously preparing CAPTCHA answers...");
|
||||
Sonar.get().getLogger().info("Players will be able to join even if the preparation isn't finished");
|
||||
|
||||
// Prepare cache
|
||||
final SonarConfiguration.Verification.Map config = Sonar.get().getConfig().getVerification().getMap();
|
||||
cached = new MapCaptchaInfo[config.getPrecomputeAmount()];
|
||||
|
||||
// Prepare everything asynchronously
|
||||
PREPARATION_SERVICE.execute(() -> {
|
||||
final List<String> fonts = config.getFonts();
|
||||
if (fonts.isEmpty()) {
|
||||
throw new IllegalArgumentException("No fonts specified!");
|
||||
}
|
||||
|
||||
// Create the configuration for the image generation
|
||||
final String[] fontNames = fonts.toArray(new String[0]);
|
||||
final CaptchaConfiguration configuration = new CaptchaConfiguration(
|
||||
128, 128, config.getDictionary().toCharArray(), 5,
|
||||
config.isFlare(), config.isScratches(), config.isRipple(), config.isSmear(), config.isPinch(),
|
||||
config.getSaturation(), config.getDistortion(), new int[]{Font.PLAIN, Font.BOLD}, fontNames);
|
||||
|
||||
for (int i = 0; i < config.getPrecomputeAmount(); i++) {
|
||||
final CaptchaGenerator captchaGenerator = new CaptchaGenerator(configuration);
|
||||
final CaptchaHolder captchaHolder = captchaGenerator.generate();
|
||||
final byte[] buffer = MapColorPalette.getBufferFromImage(captchaHolder.getImage());
|
||||
cached[i] = new MapCaptchaInfo(captchaHolder.getAnswer(), buffer);
|
||||
preparedAmount++;
|
||||
}
|
||||
|
||||
Sonar.get().getLogger().info("Finished preparing {} CAPTCHA answers ({}s)!", preparedAmount, timer);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isCaptchaAvailable() {
|
||||
return cached != null && cached[0] != null;
|
||||
}
|
||||
|
||||
public MapCaptchaInfo getRandomCaptcha() {
|
||||
// Give the player a random CAPTCHA out of the ones that we've already prepared
|
||||
return cached[RANDOM.nextInt(preparedAmount)];
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -18,11 +18,9 @@
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.config;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
@ToString
|
||||
public final class FinishConfigurationPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
@@ -35,6 +33,7 @@ public final class FinishConfigurationPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public int expectedMaxLength(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
// This packet is always empty; see https://wiki.vg/Protocol#Finish_Configuration
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+8
-9
@@ -25,16 +25,14 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketSnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeNamelessCompoundTag;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeString;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.*;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class RegistryDataPacket implements FallbackPacket {
|
||||
@@ -43,10 +41,10 @@ public final class RegistryDataPacket implements FallbackPacket {
|
||||
private List<RegistryDataPacket.Bundle> bundles;
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_5) < 0) {
|
||||
writeNamelessCompoundTag(byteBuf, tag);
|
||||
} else {
|
||||
} else if (type != null) {
|
||||
writeString(byteBuf, type);
|
||||
writeVarInt(byteBuf, bundles.size());
|
||||
|
||||
@@ -69,15 +67,16 @@ public final class RegistryDataPacket implements FallbackPacket {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static @NotNull List<FallbackPacket> of(final @NotNull CompoundBinaryTag rootTag) {
|
||||
final List<FallbackPacket> packets = new ArrayList<>();
|
||||
public static FallbackPacket @NotNull [] of(final @NotNull CompoundBinaryTag rootTag) {
|
||||
final FallbackPacket[] packets = new FallbackPacket[rootTag.size()];
|
||||
int index = 0;
|
||||
for (final String type : rootTag.keySet()) {
|
||||
final ArrayList<RegistryDataPacket.Bundle> bundles = new ArrayList<>();
|
||||
for (final BinaryTag binaryTag : rootTag.getCompound(type).getList("value")) {
|
||||
final CompoundBinaryTag tag = (CompoundBinaryTag) binaryTag;
|
||||
bundles.add(new Bundle(tag.getString("name"), tag.getCompound("element")));
|
||||
}
|
||||
packets.add(new RegistryDataPacket(rootTag, type, bundles));
|
||||
packets[index++] = new FallbackPacketSnapshot(new RegistryDataPacket(rootTag, type, bundles));
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
+2
-1
@@ -25,6 +25,7 @@ public final class LoginAcknowledgedPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,7 +34,7 @@ public final class LoginAcknowledgedPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public int expectedMaxLength(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java#L41
|
||||
// This packet is always empty; see https://wiki.vg/Protocol#Login_Acknowledged
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -24,25 +24,24 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FastUUID;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.util.FastUuidSansHyphens;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.*;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class LoginSuccessPacket implements FallbackPacket {
|
||||
private String username;
|
||||
private UUID uuid;
|
||||
private String username;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19) >= 0) {
|
||||
writeUUID(byteBuf, uuid);
|
||||
} else if (protocolVersion.compareTo(MINECRAFT_1_16) >= 0) {
|
||||
@@ -50,7 +49,7 @@ public final class LoginSuccessPacket implements FallbackPacket {
|
||||
} else if (protocolVersion.compareTo(MINECRAFT_1_7_6) >= 0) {
|
||||
writeString(byteBuf, uuid.toString());
|
||||
} else {
|
||||
writeString(byteBuf, FastUUID.toString(uuid));
|
||||
writeString(byteBuf, FastUuidSansHyphens.toString(uuid));
|
||||
}
|
||||
|
||||
writeString(byteBuf, username);
|
||||
|
||||
+2
-3
@@ -29,8 +29,7 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.*;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -67,7 +66,7 @@ public final class ChunkDataPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeInt(x);
|
||||
byteBuf.writeInt(z);
|
||||
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ public final class ClientAbilitiesPacket implements FallbackPacket {
|
||||
private float flySpeed, walkSpeed;
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeByte(encodedFlags);
|
||||
byteBuf.writeFloat(flySpeed);
|
||||
byteBuf.writeFloat(walkSpeed);
|
||||
|
||||
+4
-4
@@ -27,8 +27,8 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.readString;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.readVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readString;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -39,7 +39,7 @@ public final class ClientSettingsPacket implements FallbackPacket {
|
||||
private byte viewDistance;
|
||||
private int chatVisibility;
|
||||
private boolean chatColors;
|
||||
private byte difficulty; // 1.7 Protocol
|
||||
private byte difficulty; // 1.7
|
||||
private short skinParts;
|
||||
private int mainHand;
|
||||
private boolean chatFilteringEnabled; // Added in 1.17
|
||||
@@ -51,7 +51,7 @@ public final class ClientSettingsPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
locale = readString(byteBuf, 16);
|
||||
viewDistance = byteBuf.readByte();
|
||||
chatVisibility = readVarInt(byteBuf);
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public final class DefaultSpawnPositionPacket implements FallbackPacket {
|
||||
private int x, y, z;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0) {
|
||||
byteBuf.writeInt(x);
|
||||
byteBuf.writeInt(y);
|
||||
|
||||
+4
-5
@@ -26,7 +26,7 @@ import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.utility.component.ComponentHolder;
|
||||
import xyz.jonesdev.sonar.common.util.ComponentHolder;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -37,7 +37,7 @@ public final class DisconnectPacket implements FallbackPacket {
|
||||
private boolean login;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
componentHolder.write(byteBuf, login ? ProtocolVersion.MINECRAFT_1_20_2 : protocolVersion);
|
||||
}
|
||||
|
||||
@@ -46,8 +46,7 @@ public final class DisconnectPacket implements FallbackPacket {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static @NotNull DisconnectPacket create(final @NotNull Component component,
|
||||
final boolean login) {
|
||||
return new DisconnectPacket(new ComponentHolder(component), login);
|
||||
public static @NotNull DisconnectPacket create(final @NotNull Component component, final boolean duringLogin) {
|
||||
return new DisconnectPacket(new ComponentHolder(component), duringLogin);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -33,7 +33,7 @@ public final class GameEventPacket implements FallbackPacket {
|
||||
private float value;
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeByte(type);
|
||||
byteBuf.writeFloat(value);
|
||||
}
|
||||
|
||||
+2
-3
@@ -27,8 +27,7 @@ import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionRegistry.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.*;
|
||||
|
||||
// Mostly taken from
|
||||
// https://github.com/Nan1t/NanoLimbo/blob/main/src/main/java/ua/nanit/limbo/protocol/packets/play/PacketJoinGame.java
|
||||
@@ -48,7 +47,7 @@ public final class JoinGamePacket implements FallbackPacket {
|
||||
private String levelName;
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeInt(entityId);
|
||||
|
||||
if (protocolVersion.inBetween(MINECRAFT_1_7_2, MINECRAFT_1_7_6)) {
|
||||
|
||||
+4
-4
@@ -28,8 +28,8 @@ import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_12_2;
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_8;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.readVarInt;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -39,7 +39,7 @@ public final class KeepAlivePacket implements FallbackPacket {
|
||||
private long id;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) >= 0) {
|
||||
byteBuf.writeLong(id);
|
||||
} else if (protocolVersion.compareTo(MINECRAFT_1_8) >= 0) {
|
||||
@@ -50,7 +50,7 @@ public final class KeepAlivePacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) >= 0) {
|
||||
id = byteBuf.readLong();
|
||||
} else if (protocolVersion.compareTo(MINECRAFT_1_8) >= 0) {
|
||||
|
||||
+10
-7
@@ -21,19 +21,17 @@ import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class MapDataPacket implements FallbackPacket {
|
||||
private byte[] buffer;
|
||||
private int[] buffer;
|
||||
private int x, y;
|
||||
|
||||
@Override
|
||||
@@ -45,8 +43,7 @@ public final class MapDataPacket implements FallbackPacket {
|
||||
byteBuf.writeByte(0); // scaling
|
||||
byteBuf.writeByte(x);
|
||||
byteBuf.writeByte(y);
|
||||
|
||||
byteBuf.writeBytes(buffer);
|
||||
writeArray(byteBuf, buffer);
|
||||
} else {
|
||||
byteBuf.writeByte(0); // scaling
|
||||
|
||||
@@ -71,7 +68,13 @@ public final class MapDataPacket implements FallbackPacket {
|
||||
byteBuf.writeByte(y);
|
||||
|
||||
writeVarInt(byteBuf, buffer.length);
|
||||
byteBuf.writeBytes(buffer);
|
||||
writeArray(byteBuf, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeArray(final ByteBuf byteBuf, final int @NotNull [] array) {
|
||||
for (final int i : array) {
|
||||
byteBuf.writeByte(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public final class PaddleBoatPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
leftPaddle = byteBuf.readBoolean();
|
||||
rightPaddle = byteBuf.readBoolean();
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PlayerInputPacket implements FallbackPacket {
|
||||
public final class PlayerInputPacket implements FallbackPacket {
|
||||
private float sideways, forward;
|
||||
private boolean jump, unmount;
|
||||
|
||||
@@ -40,7 +40,7 @@ public class PlayerInputPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
sideways = byteBuf.readFloat();
|
||||
forward = byteBuf.readFloat();
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0) {
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class PlayerTickPacket implements FallbackPacket {
|
||||
public final class PlayerPositionIdlePacket implements FallbackPacket {
|
||||
private boolean onGround;
|
||||
|
||||
@Override
|
||||
@@ -39,7 +39,7 @@ public final class PlayerTickPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
|
||||
onGround = byteBuf.readBoolean();
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -27,7 +27,7 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -64,10 +64,10 @@ public final class PlayerPositionLookPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
x = byteBuf.readDouble();
|
||||
y = byteBuf.readDouble();
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0) {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_8) < 0) {
|
||||
y = byteBuf.readDouble(); // Account for weird y positions on 1.7
|
||||
}
|
||||
z = byteBuf.readDouble();
|
||||
@@ -78,7 +78,7 @@ public final class PlayerPositionLookPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public int expectedMaxLength(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
return protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 ? 41 : 33;
|
||||
return protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 41 : 33;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-3
@@ -26,6 +26,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_8;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@@ -40,10 +42,10 @@ public final class PlayerPositionPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
x = byteBuf.readDouble();
|
||||
y = byteBuf.readDouble();
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0) {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_8) < 0) {
|
||||
y = byteBuf.readDouble(); // Account for weird y positions on 1.7
|
||||
}
|
||||
z = byteBuf.readDouble();
|
||||
@@ -52,7 +54,7 @@ public final class PlayerPositionPacket implements FallbackPacket {
|
||||
|
||||
@Override
|
||||
public int expectedMaxLength(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
return protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 ? 33 : 25;
|
||||
return protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 33 : 25;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-8
@@ -24,9 +24,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_13;
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_8;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.*;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readRetainedByteBufSlice17;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -40,12 +40,8 @@ public final class PluginMessagePacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
channel = readString(byteBuf, 512);
|
||||
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13) >= 0) {
|
||||
channel = transformLegacyToModernChannel(channel);
|
||||
}
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
channel = readString(byteBuf, 64);
|
||||
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_8) >= 0) {
|
||||
slicedBuffer = byteBuf.readRetainedSlice(byteBuf.readableBytes());
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -36,7 +36,7 @@ public final class RemoveEntitiesPacket implements FallbackPacket {
|
||||
private int entityId; // We only need one entityId
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
// No idea why Mojang decided that this is a good idea, but whatever
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_17) != 0) {
|
||||
writeVarInt(byteBuf, 1); // size
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.packets.play;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class SetExperiencePacket implements FallbackPacket {
|
||||
private float experienceBar;
|
||||
private int level;
|
||||
private int totalExperience;
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeFloat(experienceBar);
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) < 0) {
|
||||
byteBuf.writeShort(level);
|
||||
byteBuf.writeShort(totalExperience);
|
||||
} else {
|
||||
writeVarInt(byteBuf, level);
|
||||
writeVarInt(byteBuf, totalExperience);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -26,18 +26,17 @@ import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class SetPassengersPacket implements FallbackPacket {
|
||||
private int entityId;
|
||||
private int passengerId;
|
||||
private int entityId, passengerId;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
// You can find this in the EntityAttach packet,
|
||||
// which was later replaced by SetPassengers in 1.9+
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_9) < 0) {
|
||||
|
||||
+4
-7
@@ -29,18 +29,14 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeCompoundTag;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeNamelessCompoundTag;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.*;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class SetSlotPacket implements FallbackPacket {
|
||||
private int slot;
|
||||
private int count;
|
||||
private int itemId;
|
||||
private int slot, count, itemId;
|
||||
private CompoundBinaryTag compoundBinaryTag;
|
||||
|
||||
public static final CompoundBinaryTag MAP_NBT = CompoundBinaryTag.builder()
|
||||
@@ -48,7 +44,7 @@ public final class SetSlotPacket implements FallbackPacket {
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
byteBuf.writeByte(0); // windowId
|
||||
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_17_1) >= 0) {
|
||||
@@ -91,6 +87,7 @@ public final class SetSlotPacket implements FallbackPacket {
|
||||
} else if (protocolVersion.compareTo(MINECRAFT_1_20_5) < 0) {
|
||||
writeNamelessCompoundTag(byteBuf, compoundBinaryTag);
|
||||
} else { // 1.20.5
|
||||
// TODO: find a way to improve this
|
||||
// component
|
||||
writeVarInt(byteBuf, 1); // component count to add
|
||||
writeVarInt(byteBuf, 0); // component count to remove
|
||||
|
||||
+3
-4
@@ -27,9 +27,8 @@ import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.fallback.netty.FastUUID.EMPTY_UUID;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeUUID;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeUUID;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -40,7 +39,7 @@ public final class SpawnEntityPacket implements FallbackPacket {
|
||||
private double x, y, z;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
writeVarInt(byteBuf, entityId);
|
||||
|
||||
final boolean v1_9orHigher = protocolVersion.compareTo(MINECRAFT_1_8) > 0;
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.readVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@@ -40,7 +40,7 @@ public final class TeleportConfirmPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
public void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception {
|
||||
teleportId = readVarInt(byteBuf);
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -33,17 +33,17 @@ import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class TransactionPacket implements FallbackPacket {
|
||||
private int windowId, id;
|
||||
private int windowId, transactionId;
|
||||
private boolean accepted;
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_17) < 0) {
|
||||
windowId = byteBuf.readByte();
|
||||
id = byteBuf.readShort();
|
||||
transactionId = byteBuf.readShort();
|
||||
accepted = byteBuf.readBoolean();
|
||||
} else {
|
||||
id = byteBuf.readInt();
|
||||
transactionId = byteBuf.readInt();
|
||||
// Always set accepted to true since 1.17 or higher don't use
|
||||
// transactions for inventory confirmation anymore.
|
||||
accepted = true;
|
||||
@@ -51,15 +51,15 @@ public final class TransactionPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_17) < 0) {
|
||||
byteBuf.writeByte(windowId);
|
||||
byteBuf.writeShort((short) id);
|
||||
byteBuf.writeShort((short) transactionId);
|
||||
// The "accepted" field is actually really unnecessary since
|
||||
// it's never even used in the client.
|
||||
byteBuf.writeBoolean(accepted);
|
||||
} else {
|
||||
byteBuf.writeInt(id);
|
||||
byteBuf.writeInt(transactionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -26,21 +26,21 @@ import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeString;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeString;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class TransferPacket implements FallbackPacket {
|
||||
private String host;
|
||||
private int port;
|
||||
private String destinationHost;
|
||||
private int destinationPort;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
writeString(byteBuf, host);
|
||||
writeVarInt(byteBuf, port);
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
writeString(byteBuf, destinationHost);
|
||||
writeVarInt(byteBuf, destinationPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+18
-29
@@ -26,15 +26,10 @@ import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.utility.component.ComponentHolder;
|
||||
|
||||
import java.time.Instant;
|
||||
import xyz.jonesdev.sonar.common.util.ComponentHolder;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.fallback.netty.FastUUID.EMPTY_UUID;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.readVarInt;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.*;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@@ -49,16 +44,9 @@ public final class UniversalChatPacket implements FallbackPacket {
|
||||
private ComponentHolder componentHolder;
|
||||
private String message;
|
||||
private byte type;
|
||||
private boolean signedPreview;
|
||||
private boolean unsigned = false;
|
||||
private Instant timestamp;
|
||||
private Instant expiry;
|
||||
private long salt;
|
||||
private boolean signed;
|
||||
private byte[] signature;
|
||||
|
||||
public UniversalChatPacket(final @NotNull Component component,
|
||||
final byte type) {
|
||||
public UniversalChatPacket(final @NotNull Component component, final byte type) {
|
||||
this(new ComponentHolder(component), type);
|
||||
}
|
||||
|
||||
@@ -68,7 +56,7 @@ public final class UniversalChatPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
// Serialized message
|
||||
componentHolder.write(byteBuf, protocolVersion);
|
||||
|
||||
@@ -89,31 +77,31 @@ public final class UniversalChatPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) {
|
||||
public void decode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
message = readString(byteBuf, 256);
|
||||
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) {
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19_1) <= 0) {
|
||||
final long expiresAt = byteBuf.readLong();
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19) >= 0) {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
byteBuf.readLong(); // expiresAt
|
||||
final long saltLong = byteBuf.readLong();
|
||||
final byte[] signatureBytes = readByteArray(byteBuf);
|
||||
boolean unsigned = false;
|
||||
|
||||
if (saltLong != 0L && signatureBytes.length > 0) {
|
||||
signature = signatureBytes;
|
||||
expiry = Instant.ofEpochMilli(expiresAt);
|
||||
} else if ((protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19_1) >= 0
|
||||
} else if ((protocolVersion.compareTo(MINECRAFT_1_19_1) >= 0
|
||||
|| saltLong == 0L) && signatureBytes.length == 0) {
|
||||
unsigned = true;
|
||||
} else {
|
||||
throw new CorruptedFrameException("Invalid signature");
|
||||
}
|
||||
|
||||
signedPreview = byteBuf.readBoolean();
|
||||
final boolean signedPreview = byteBuf.readBoolean();
|
||||
if (signedPreview && unsigned) {
|
||||
throw new CorruptedFrameException("Signature missing");
|
||||
}
|
||||
|
||||
if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_19_1) >= 0) {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) >= 0) {
|
||||
final int size = readVarInt(byteBuf);
|
||||
if (size < 0 || size > 5) {
|
||||
throw new CorruptedFrameException("Invalid previous messages");
|
||||
@@ -130,11 +118,12 @@ public final class UniversalChatPacket implements FallbackPacket {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
timestamp = Instant.ofEpochMilli(byteBuf.readLong());
|
||||
salt = byteBuf.readLong();
|
||||
signed = byteBuf.readBoolean();
|
||||
byteBuf.readLong(); // timestamp
|
||||
byteBuf.readLong(); // salt
|
||||
final boolean signed = byteBuf.readBoolean();
|
||||
|
||||
if (signed) {
|
||||
byte[] sign = new byte[256];
|
||||
final byte[] sign = new byte[256];
|
||||
byteBuf.readBytes(sign);
|
||||
signature = sign;
|
||||
} else {
|
||||
@@ -142,7 +131,7 @@ public final class UniversalChatPacket implements FallbackPacket {
|
||||
}
|
||||
|
||||
readVarInt(byteBuf);
|
||||
byte[] bytes = new byte[DIV_FLOOR];
|
||||
final byte[] bytes = new byte[DIV_FLOOR];
|
||||
byteBuf.readBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -25,19 +25,19 @@ 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.fallback.protocol.block.ChangedBlock;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockUpdate;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.*;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.writeVarLong;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarLong;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString(exclude = {"changedBlocks"})
|
||||
@ToString(exclude = {"blockUpdates"})
|
||||
public final class UpdateSectionBlocksPacket implements FallbackPacket {
|
||||
private int sectionX, sectionZ;
|
||||
private ChangedBlock[] changedBlocks;
|
||||
private BlockUpdate[] blockUpdates;
|
||||
|
||||
@Override
|
||||
public void encode(final ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
@@ -46,13 +46,13 @@ public final class UpdateSectionBlocksPacket implements FallbackPacket {
|
||||
byteBuf.writeInt(sectionZ);
|
||||
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_8) < 0) {
|
||||
byteBuf.writeShort(changedBlocks.length);
|
||||
byteBuf.writeInt(4 * changedBlocks.length);
|
||||
byteBuf.writeShort(blockUpdates.length);
|
||||
byteBuf.writeInt(4 * blockUpdates.length);
|
||||
} else {
|
||||
writeVarInt(byteBuf, changedBlocks.length);
|
||||
writeVarInt(byteBuf, blockUpdates.length);
|
||||
}
|
||||
|
||||
for (final ChangedBlock block : changedBlocks) {
|
||||
for (final BlockUpdate block : blockUpdates) {
|
||||
byteBuf.writeShort(block.getLegacyBlockState());
|
||||
final int blockId = block.getType().getId(protocolVersion);
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13) >= 0) {
|
||||
@@ -68,7 +68,7 @@ public final class UpdateSectionBlocksPacket implements FallbackPacket {
|
||||
}
|
||||
} else {
|
||||
// We only need one Y position
|
||||
final int sectionY = changedBlocks[0].getPosition().getY() >> 4;
|
||||
final int sectionY = blockUpdates[0].getPosition().getY() >> 4;
|
||||
|
||||
// https://wiki.vg/Protocol#Update_Section_Blocks
|
||||
byteBuf.writeLong(((sectionX & 0x3FFFFFL) << 42) | (sectionY & 0xFFFFF) | ((sectionZ & 0x3FFFFFL) << 20));
|
||||
@@ -78,9 +78,9 @@ public final class UpdateSectionBlocksPacket implements FallbackPacket {
|
||||
byteBuf.writeBoolean(true); // suppress light updates
|
||||
}
|
||||
|
||||
writeVarInt(byteBuf, changedBlocks.length);
|
||||
writeVarInt(byteBuf, blockUpdates.length);
|
||||
|
||||
for (final ChangedBlock block : changedBlocks) {
|
||||
for (final BlockUpdate block : blockUpdates) {
|
||||
// https://wiki.vg/Protocol#Update_Section_Blocks
|
||||
final int shiftedBlockId = block.getType().getId(protocolVersion) << 12;
|
||||
final long positionIdValue = shiftedBlockId | block.getBlockState();
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.utility.component;
|
||||
package xyz.jonesdev.sonar.common.util;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.internal.LazilyParsedNumber;
|
||||
@@ -31,8 +31,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeNamelessCompoundTag;
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.ProtocolUtil.writeString;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeNamelessCompoundTag;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeString;
|
||||
|
||||
// Mostly taken from
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java
|
||||
+48
-17
@@ -15,50 +15,81 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
package xyz.jonesdev.sonar.common.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Jon Chambers
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
// Taken from
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/api/src/main/java/com/velocitypowered/api/util/FastUuidSansHyphens.java
|
||||
public final class FastUUID {
|
||||
public static final UUID EMPTY_UUID = new UUID(0L, 0L);
|
||||
/**
|
||||
* This is a modified FastUUID implementation. The primary difference is that it does not dash its
|
||||
* UUIDs. As the native Java 9+ UUID.toString() implementation dashes its UUIDs, we use the FastUUID
|
||||
* methods, which ought to be faster than a String.replace().
|
||||
*/
|
||||
@UtilityClass
|
||||
public class FastUuidSansHyphens {
|
||||
private static final int MOJANG_BROKEN_UUID_LENGTH = 32;
|
||||
|
||||
private static final char[] HEX_DIGITS =
|
||||
new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||
|
||||
/**
|
||||
* Returns a string representation of the given UUID. The returned string is formatted as a
|
||||
* Mojang-style UUID.
|
||||
*
|
||||
* @param uuid the UUID to represent as a string
|
||||
*
|
||||
* @return a string representation of the given UUID
|
||||
*/
|
||||
public static String toString(final @NotNull UUID uuid) {
|
||||
public static @NotNull String toString(final @NotNull UUID uuid) {
|
||||
final long mostSignificantBits = uuid.getMostSignificantBits();
|
||||
final long leastSignificantBits = uuid.getLeastSignificantBits();
|
||||
|
||||
final char[] uuidChars = new char[MOJANG_BROKEN_UUID_LENGTH];
|
||||
|
||||
uuidChars[0] = HEX_DIGITS[(int) ((mostSignificantBits & 0xf000000000000000L) >>> 60)];
|
||||
uuidChars[1] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0f00000000000000L) >>> 56)];
|
||||
uuidChars[2] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00f0000000000000L) >>> 52)];
|
||||
uuidChars[3] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000f000000000000L) >>> 48)];
|
||||
uuidChars[4] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000f00000000000L) >>> 44)];
|
||||
uuidChars[5] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000f0000000000L) >>> 40)];
|
||||
uuidChars[6] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000f000000000L) >>> 36)];
|
||||
uuidChars[7] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000f00000000L) >>> 32)];
|
||||
uuidChars[8] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000f0000000L) >>> 28)];
|
||||
uuidChars[9] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000f000000L) >>> 24)];
|
||||
uuidChars[0] = HEX_DIGITS[(int) ((mostSignificantBits & 0xf000000000000000L) >>> 60)];
|
||||
uuidChars[1] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0f00000000000000L) >>> 56)];
|
||||
uuidChars[2] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00f0000000000000L) >>> 52)];
|
||||
uuidChars[3] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000f000000000000L) >>> 48)];
|
||||
uuidChars[4] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000f00000000000L) >>> 44)];
|
||||
uuidChars[5] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000f0000000000L) >>> 40)];
|
||||
uuidChars[6] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000f000000000L) >>> 36)];
|
||||
uuidChars[7] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000f00000000L) >>> 32)];
|
||||
uuidChars[8] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000f0000000L) >>> 28)];
|
||||
uuidChars[9] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000f000000L) >>> 24)];
|
||||
uuidChars[10] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000000f00000L) >>> 20)];
|
||||
uuidChars[11] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000000f0000L) >>> 16)];
|
||||
uuidChars[12] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000000f000L) >>> 12)];
|
||||
uuidChars[13] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000000000f00L) >>> 8)];
|
||||
uuidChars[14] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000000000f0L) >>> 4)];
|
||||
uuidChars[15] = HEX_DIGITS[(int) (mostSignificantBits & 0x000000000000000fL)];
|
||||
uuidChars[15] = HEX_DIGITS[(int) (mostSignificantBits & 0x000000000000000fL)];
|
||||
uuidChars[16] = HEX_DIGITS[(int) ((leastSignificantBits & 0xf000000000000000L) >>> 60)];
|
||||
uuidChars[17] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0f00000000000000L) >>> 56)];
|
||||
uuidChars[18] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00f0000000000000L) >>> 52)];
|
||||
@@ -74,7 +105,7 @@ public final class FastUUID {
|
||||
uuidChars[28] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000000000f000L) >>> 12)];
|
||||
uuidChars[29] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000000000f00L) >>> 8)];
|
||||
uuidChars[30] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000000000f0L) >>> 4)];
|
||||
uuidChars[31] = HEX_DIGITS[(int) (leastSignificantBits & 0x000000000000000fL)];
|
||||
uuidChars[31] = HEX_DIGITS[(int) (leastSignificantBits & 0x000000000000000fL)];
|
||||
|
||||
return new String(uuidChars);
|
||||
}
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.utility.geyser;
|
||||
package xyz.jonesdev.sonar.common.util;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.util.AttributeKey;
|
||||
@@ -28,7 +28,7 @@ import java.net.InetSocketAddress;
|
||||
* Simple utility to determine if someone joins using GeyserMC
|
||||
*/
|
||||
@UtilityClass
|
||||
public class GeyserUtil {
|
||||
public class GeyserDetection {
|
||||
// https://github.com/GeyserMC/Floodgate/blob/master/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java#L206
|
||||
private final AttributeKey<Object> PLAYER_ATTRIBUTE = AttributeKey.valueOf("floodgate-player");
|
||||
|
||||
+131
-39
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.utility.protocol;
|
||||
package xyz.jonesdev.sonar.common.util;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
@@ -31,26 +31,138 @@ import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.utility.protocol.VarIntUtil.readVarInt;
|
||||
|
||||
// Taken from
|
||||
// Mostly taken from
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
|
||||
@UtilityClass
|
||||
public class ProtocolUtil {
|
||||
private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A;
|
||||
|
||||
private static final String BRAND_CHANNEL_LEGACY = "MC|Brand";
|
||||
private static final String BRAND_CHANNEL = "minecraft:brand";
|
||||
private static final String REGISTER_CHANNEL_LEGACY = "REGISTER";
|
||||
private static final String REGISTER_CHANNEL = "minecraft:register";
|
||||
private static final String UNREGISTER_CHANNEL_LEGACY = "UNREGISTER";
|
||||
private static final String UNREGISTER_CHANNEL = "minecraft:unregister";
|
||||
private static final Pattern INVALID_IDENTIFIER_REGEX = Pattern.compile("[^a-z0-9\\-_]*");
|
||||
public static final String BRAND_CHANNEL_LEGACY = "MC|Brand";
|
||||
public static final String BRAND_CHANNEL = "minecraft:brand";
|
||||
|
||||
public static @NotNull UUID readUUID(final @NotNull ByteBuf byteBuf) {
|
||||
return new UUID(byteBuf.readLong(), byteBuf.readLong());
|
||||
public static int readVarInt(final ByteBuf byteBuf) {
|
||||
int read = readVarIntSafely(byteBuf);
|
||||
if (read == Integer.MIN_VALUE) {
|
||||
throw new CorruptedFrameException("Corrupt VarInt");
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
public static int readVarIntSafely(final @NotNull ByteBuf byteBuf) {
|
||||
int i = 0;
|
||||
int maxRead = Math.min(5, byteBuf.readableBytes());
|
||||
for (int j = 0; j < maxRead; j++) {
|
||||
int k = byteBuf.readByte();
|
||||
i |= (k & 0x7F) << j * 7;
|
||||
if ((k & 0x80) != 128) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
public static void writeVarInt(final ByteBuf byteBuf, final int value) {
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
// that the proxy will write, to improve inlining.
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
byteBuf.writeByte(value);
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else {
|
||||
writeVarIntFull(byteBuf, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeVarIntFull(final ByteBuf byteBuf, final int value) {
|
||||
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
byteBuf.writeByte(value);
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
|
||||
byteBuf.writeMedium(w);
|
||||
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21);
|
||||
byteBuf.writeInt(w);
|
||||
} else {
|
||||
int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80);
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeByte(value >>> 28);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeVarLong(final ByteBuf byteBuf, final long value) {
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarLong sizes
|
||||
// that the proxy will write, to improve inlining.
|
||||
if ((value & 0xFFFFFFFFFFFFFF80L) == 0L) {
|
||||
byteBuf.writeByte((byte) value);
|
||||
} else if ((value & 0xFFFFFFFFFFFFC000L) == 0L) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 8 | value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else {
|
||||
writeVarLongFull(byteBuf, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeVarLongFull(final ByteBuf byteBuf, final long value) {
|
||||
if ((value & 0xFFFFFFFFFFFFFF80L) == 0L) {
|
||||
byteBuf.writeByte((byte) value);
|
||||
} else if ((value & 0xFFFFFFFFFFFFC000L) == 0L) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 8 | value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else if ((value & 0xFFFFFFFFFFE00000L) == 0L) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 16 | (value >>> 7 & 0x7FL | 0x80L) << 8 | value >>> 14);
|
||||
byteBuf.writeMedium(w);
|
||||
} else if ((value & 0xFFFFFFFFF0000000L) == 0L) {
|
||||
int w =
|
||||
(int) ((value & 0x7FL | 0x80L) << 24 | (value >>> 7 & 0x7FL | 0x80L) << 16 | (value >>> 14 & 0x7FL | 0x80L) << 8 | value >>> 21);
|
||||
byteBuf.writeInt(w);
|
||||
} else {
|
||||
long l =
|
||||
(value & 0x7FL | 0x80L) << 24 | (value >>> 7 & 0x7FL | 0x80L) << 16 | (value >>> 14 & 0x7FL | 0x80L) << 8 | (value >>> 21 & 0x7FL | 0x80L);
|
||||
if ((value & 0xFFFFFFF800000000L) == 0L) {
|
||||
int w =
|
||||
(int) l;
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeByte((int) (value >>> 28));
|
||||
} else if ((value & 0xFFFFFC0000000000L) == 0L) {
|
||||
int w =
|
||||
(int) l;
|
||||
int w2 = (int) ((value >>> 28 & 0x7FL | 0x80L) << 8 | value >>> 35);
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeShort(w2);
|
||||
} else if ((value & 0xFFFE000000000000L) == 0L) {
|
||||
int w =
|
||||
(int) l;
|
||||
int w2 = (int) ((value >>> 28 & 0x7FL | 0x80L) << 16 | (value >>> 35 & 0x7FL | 0x80L) << 8 | value >>> 42);
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeMedium(w2);
|
||||
} else {
|
||||
long w =
|
||||
(value & 0x7FL | 0x80L) << 56 | (value >>> 7 & 0x7FL | 0x80L) << 48 | (value >>> 14 & 0x7FL | 0x80L) << 40 | (value >>> 21 & 0x7FL | 0x80L) << 32 | (value >>> 28 & 0x7FL | 0x80L) << 24 | (value >>> 35 & 0x7FL | 0x80L) << 16 | (value >>> 42 & 0x7FL | 0x80L) << 8 | value >>> 49;
|
||||
if ((value & 0xFF00000000000000L) == 0L) {
|
||||
byteBuf.writeLong(w);
|
||||
} else if ((value & Long.MIN_VALUE) == 0L) {
|
||||
byteBuf.writeLong(w);
|
||||
byteBuf.writeByte((byte) (value >>> 56));
|
||||
} else {
|
||||
int w2 = (int) ((value >>> 56 & 0x7FL | 0x80L) << 8 | value >>> 63);
|
||||
byteBuf.writeLong(w);
|
||||
byteBuf.writeShort(w2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void readUUID(final @NotNull ByteBuf byteBuf) {
|
||||
byteBuf.readLong(); // least
|
||||
byteBuf.readLong(); // most
|
||||
}
|
||||
|
||||
public static byte @NotNull [] readByteArray(final ByteBuf byteBuf) {
|
||||
@@ -82,7 +194,7 @@ public class ProtocolUtil {
|
||||
|
||||
public static @NotNull String readString(final ByteBuf byteBuf,
|
||||
final int cap) throws CorruptedFrameException {
|
||||
final int length = VarIntUtil.readVarInt(byteBuf);
|
||||
final int length = readVarInt(byteBuf);
|
||||
return readString(byteBuf, cap, length);
|
||||
}
|
||||
|
||||
@@ -100,7 +212,7 @@ public class ProtocolUtil {
|
||||
|
||||
public static void writeString(final ByteBuf byteBuf, final @NotNull CharSequence str) {
|
||||
final int size = ByteBufUtil.utf8Bytes(str);
|
||||
VarIntUtil.writeVarInt(byteBuf, size);
|
||||
writeVarInt(byteBuf, size);
|
||||
byteBuf.writeCharSequence(str, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@@ -118,18 +230,18 @@ public class ProtocolUtil {
|
||||
|
||||
public static void writeArray(final ByteBuf byteBuf, final byte @NotNull [] bytes) {
|
||||
checkFrame(bytes.length < Short.MAX_VALUE, "Too long array");
|
||||
VarIntUtil.writeVarInt(byteBuf, bytes.length);
|
||||
writeVarInt(byteBuf, bytes.length);
|
||||
byteBuf.writeBytes(bytes);
|
||||
}
|
||||
|
||||
public static void writeStringArray(final ByteBuf byteBuf, final String @NotNull [] stringArray) {
|
||||
VarIntUtil.writeVarInt(byteBuf, stringArray.length);
|
||||
writeVarInt(byteBuf, stringArray.length);
|
||||
for (final String s : stringArray) {
|
||||
writeString(byteBuf, s);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeCompoundTag(final ByteBuf byteBuf, final CompoundBinaryTag compoundTag) {
|
||||
public static void writeCompoundTag(final @NotNull ByteBuf byteBuf, final @NotNull CompoundBinaryTag compoundTag) {
|
||||
try {
|
||||
BinaryTagIO.writer().write(compoundTag, (DataOutput) new ByteBufOutputStream(byteBuf));
|
||||
} catch (IOException exception) {
|
||||
@@ -192,26 +304,6 @@ public class ProtocolUtil {
|
||||
return byteBuf.readRetainedSlice(length);
|
||||
}
|
||||
|
||||
public static @NotNull String transformLegacyToModernChannel(@NotNull final String name) {
|
||||
if (name.indexOf(':') != -1) {
|
||||
return name;
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case REGISTER_CHANNEL_LEGACY:
|
||||
return REGISTER_CHANNEL;
|
||||
case UNREGISTER_CHANNEL_LEGACY:
|
||||
return UNREGISTER_CHANNEL;
|
||||
case BRAND_CHANNEL_LEGACY:
|
||||
return BRAND_CHANNEL;
|
||||
case "BungeeCord":
|
||||
return "bungeecord:main";
|
||||
default:
|
||||
final String lower = name.toLowerCase();
|
||||
return "legacy:" + INVALID_IDENTIFIER_REGEX.matcher(lower).replaceAll("");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkFrame(final boolean expression, final String message) {
|
||||
if (!expression) {
|
||||
throw new CorruptedFrameException(message);
|
||||
-145
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.utility.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.CorruptedFrameException;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@UtilityClass
|
||||
public class VarIntUtil {
|
||||
public static int readVarInt(final ByteBuf byteBuf) {
|
||||
int read = readVarIntSafely(byteBuf);
|
||||
if (read == Integer.MIN_VALUE) {
|
||||
throw new CorruptedFrameException("Corrupt VarInt");
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
public static int readVarIntSafely(final @NotNull ByteBuf byteBuf) {
|
||||
int i = 0;
|
||||
int maxRead = Math.min(5, byteBuf.readableBytes());
|
||||
for (int j = 0; j < maxRead; j++) {
|
||||
int k = byteBuf.readByte();
|
||||
i |= (k & 0x7F) << j * 7;
|
||||
if ((k & 0x80) != 128) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
public static void writeVarInt(final ByteBuf byteBuf, final int value) {
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
// that the proxy will write, to improve inlining.
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
byteBuf.writeByte(value);
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else {
|
||||
writeVarIntFull(byteBuf, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeVarIntFull(final ByteBuf byteBuf, final int value) {
|
||||
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||
if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
byteBuf.writeByte(value);
|
||||
} else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else if ((value & (0xFFFFFFFF << 21)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
|
||||
byteBuf.writeMedium(w);
|
||||
} else if ((value & (0xFFFFFFFF << 28)) == 0) {
|
||||
int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16)
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21);
|
||||
byteBuf.writeInt(w);
|
||||
} else {
|
||||
int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16
|
||||
| ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80);
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeByte(value >>> 28);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeVarLong(final ByteBuf byteBuf, final long value) {
|
||||
// Peel the one and two byte count cases explicitly as they are the most common VarLong sizes
|
||||
// that the proxy will write, to improve inlining.
|
||||
if ((value & 0xFFFFFFFFFFFFFF80L) == 0L) {
|
||||
byteBuf.writeByte((byte) value);
|
||||
} else if ((value & 0xFFFFFFFFFFFFC000L) == 0L) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 8 | value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else {
|
||||
writeVarLongFull(byteBuf, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeVarLongFull(final ByteBuf byteBuf, final long value) {
|
||||
if ((value & 0xFFFFFFFFFFFFFF80L) == 0L) {
|
||||
byteBuf.writeByte((byte) value);
|
||||
} else if ((value & 0xFFFFFFFFFFFFC000L) == 0L) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 8 | value >>> 7);
|
||||
byteBuf.writeShort(w);
|
||||
} else if ((value & 0xFFFFFFFFFFE00000L) == 0L) {
|
||||
int w = (int) ((value & 0x7FL | 0x80L) << 16 | (value >>> 7 & 0x7FL | 0x80L) << 8 | value >>> 14);
|
||||
byteBuf.writeMedium(w);
|
||||
} else if ((value & 0xFFFFFFFFF0000000L) == 0L) {
|
||||
int w =
|
||||
(int) ((value & 0x7FL | 0x80L) << 24 | (value >>> 7 & 0x7FL | 0x80L) << 16 | (value >>> 14 & 0x7FL | 0x80L) << 8 | value >>> 21);
|
||||
byteBuf.writeInt(w);
|
||||
} else {
|
||||
long l =
|
||||
(value & 0x7FL | 0x80L) << 24 | (value >>> 7 & 0x7FL | 0x80L) << 16 | (value >>> 14 & 0x7FL | 0x80L) << 8 | (value >>> 21 & 0x7FL | 0x80L);
|
||||
if ((value & 0xFFFFFFF800000000L) == 0L) {
|
||||
int w =
|
||||
(int) l;
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeByte((int) (value >>> 28));
|
||||
} else if ((value & 0xFFFFFC0000000000L) == 0L) {
|
||||
int w =
|
||||
(int) l;
|
||||
int w2 = (int) ((value >>> 28 & 0x7FL | 0x80L) << 8 | value >>> 35);
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeShort(w2);
|
||||
} else if ((value & 0xFFFE000000000000L) == 0L) {
|
||||
int w =
|
||||
(int) l;
|
||||
int w2 = (int) ((value >>> 28 & 0x7FL | 0x80L) << 16 | (value >>> 35 & 0x7FL | 0x80L) << 8 | value >>> 42);
|
||||
byteBuf.writeInt(w);
|
||||
byteBuf.writeMedium(w2);
|
||||
} else {
|
||||
long w =
|
||||
(value & 0x7FL | 0x80L) << 56 | (value >>> 7 & 0x7FL | 0x80L) << 48 | (value >>> 14 & 0x7FL | 0x80L) << 40 | (value >>> 21 & 0x7FL | 0x80L) << 32 | (value >>> 28 & 0x7FL | 0x80L) << 24 | (value >>> 35 & 0x7FL | 0x80L) << 16 | (value >>> 42 & 0x7FL | 0x80L) << 8 | value >>> 49;
|
||||
if ((value & 0xFF00000000000000L) == 0L) {
|
||||
byteBuf.writeLong(w);
|
||||
} else if ((value & Long.MIN_VALUE) == 0L) {
|
||||
byteBuf.writeLong(w);
|
||||
byteBuf.writeByte((byte) (value >>> 56));
|
||||
} else {
|
||||
int w2 = (int) ((value >>> 56 & 0x7FL | 0x80L) << 8 | value >>> 63);
|
||||
byteBuf.writeLong(w);
|
||||
byteBuf.writeShort(w2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,39 +105,51 @@ verification:
|
||||
# - DURING_ATTACK: Noví hráči dostanou map captchu jenom při útoku
|
||||
# - NEVER: Noví hráči nikdy nedostanou map CAPTCHU (Doporučeno)
|
||||
timing: NEVER
|
||||
# Možnosti efektů na obrázek zobrazený přehrávači
|
||||
# Možnosti pro efekty na zobrazeném obrázku
|
||||
# Toto byste měli upravovat, pouze pokud víte, co děláte
|
||||
effects:
|
||||
# Přidá do obrázku efekt záře
|
||||
flare: true
|
||||
# Přidá do obrázku náhodné čáry
|
||||
scratches: true
|
||||
# Přidá filtr zvlnění (sinus) zkreslení
|
||||
# Přidá filtr zvlnění (vlnitý efekt)
|
||||
ripple: true
|
||||
# Přidá horizontální filtr zkreslení
|
||||
smear: true
|
||||
# Dodává obrazu trochu rozmazání/zkreslení
|
||||
pinch: true
|
||||
# Použije korekci barev (sytost barev)
|
||||
saturation: 0.15
|
||||
# Přidá horizontální trojúhelníkový filtr zvlnění
|
||||
distortion: 2
|
||||
# Přidá nárazový filtr (zaostřený text)
|
||||
bump: true
|
||||
# Filtr zkreslení
|
||||
distortion:
|
||||
# Měl by Sonar použít filtr zkreslení?
|
||||
enabled: true
|
||||
# Jaký tvar by měl Sonar použít pro filtr zkreslení?
|
||||
# Typy: 0, 1, 2, 3
|
||||
# - 0: Kříže
|
||||
# - 1: Čáry
|
||||
# - 2: Kruhy
|
||||
# - 3: Čtverce
|
||||
shape: 2
|
||||
# Vzdálenost mezi zkreslenými pixely/objekty
|
||||
distance: 5
|
||||
# Hustota zkreslených pixelů/objektů
|
||||
density: 0.1
|
||||
# Míra prolnutí mezi barvami objektů
|
||||
mix: 0.15
|
||||
# Cesta k obrázku na pozadí, který Sonar používá pro CAPTCHA
|
||||
# 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: ''
|
||||
# Měl by Sonar automaticky detekovat barvu pozadí?
|
||||
# To se provádí za účelem vytvoření kontrastu mezi obrázkem na pozadí a textem
|
||||
# Pokud je toto zakázáno, Sonar použije pro barvy náhodný přechod
|
||||
auto-color: false
|
||||
# Kolik odpovědí by měl Sonar předgenerovat?
|
||||
# Tento úkol běží souběžně v pozadí
|
||||
precompute: 500
|
||||
# Jak dlouho by měl Sonar čekat než hráč selže CAPTCHU?
|
||||
# (Hodnota udávaná v milisekundách: 1 sekunda = 1000 milisekund)
|
||||
max-duration: 45000
|
||||
max-duration: 30000
|
||||
# Kolikrát musí hráč selhat CAPTCHU před celkovém selhání verifikace?
|
||||
max-tries: 3
|
||||
# Znaky (čísla a písmena), které jsou povoleny k zobrazování v CAPTCHE
|
||||
# Nedoporučuje se přidávat čísla nebo písmena, která by se mohla navzájem podobat
|
||||
dictionary: '1235689'
|
||||
# Jaké typy fontů by měl Sonar používat pro map CAPTCHU?
|
||||
font-names:
|
||||
- Dialog
|
||||
- DialogInput
|
||||
- SansSerif
|
||||
- Monospaced
|
||||
|
||||
# Zkouší pokuď hráč posílá správný "client brand packet" serveru
|
||||
client-brand:
|
||||
|
||||
@@ -102,39 +102,51 @@ verification:
|
||||
# - DURING_ATTACK: Neue Spieler erhalten nur während eines Angriffs ein CAPTCHA
|
||||
# - NEVER: Neue Spieler erhalten nie ein CAPTCHA (Empfohlen)
|
||||
timing: NEVER
|
||||
# Optionen für die Effekte auf das dem Player angezeigte Bild
|
||||
# Optionen für die Effekte auf dem angezeigten Bild
|
||||
# Sie sollten dies nur bearbeiten, wenn Sie wissen, was Sie tun
|
||||
effects:
|
||||
# Fügt dem Bild einen Leuchteffekt hinzu
|
||||
flare: true
|
||||
# Fügt dem Bild zufällige Linien hinzu
|
||||
scratches: true
|
||||
# Wendet einen Sinus-Verzerrungsfilter an
|
||||
# Wendet einen Ripple-Filter an (Welleneffekt)
|
||||
ripple: true
|
||||
# Wendet einen horizontalen Verzerrungsfilter an
|
||||
smear: true
|
||||
# Fügt dem Bild etwas Unschärfe/Verzerrung hinzu
|
||||
pinch: true
|
||||
# Wendet eine Farbkorrektur an (Farbsättigung)
|
||||
saturation: 0.15
|
||||
# Wendet einen horizontalen dreieckigen Wellenfilter an
|
||||
distortion: 2
|
||||
# Wendet einen Bump-Filter an (geschärfter Text)
|
||||
bump: true
|
||||
# Verzerrungsfilter
|
||||
distortion:
|
||||
# Sollte Sonar einen Verzerrungsfilter anwenden?
|
||||
enabled: true
|
||||
# Welche Form sollte Sonar für den Verzerrungsfilter verwenden?
|
||||
# Mögliche Typen: 0, 1, 2, 3
|
||||
# - 0: Kreuze
|
||||
# - 1: Linien
|
||||
# - 2: Kreise
|
||||
# - 3: Quadrate
|
||||
shape: 2
|
||||
# Abstand zwischen verzerrten Pixeln/Objekten
|
||||
distance: 5
|
||||
# Dichte der verzerrten Pixel/Objekte
|
||||
density: 0.1
|
||||
# Ausmaß der Vermischung zwischen den Farben von Objekten
|
||||
mix: 0.15
|
||||
# Pfad zum Hintergrundbild, das Sonar für das CAPTCHA verwendet
|
||||
# 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: ''
|
||||
# Sollte Sonar die Hintergrundfarbe automatisch erkennen?
|
||||
# Dies geschieht, um einen Kontrast zwischen dem Hintergrundbild und dem Text zu erzeugen
|
||||
# Wenn dies deaktiviert ist, verwendet Sonar einen zufälligen Farbverlauf für die Farben
|
||||
auto-color: false
|
||||
# Wie viele Antworten soll Sonar vorbereiten?
|
||||
# Dieser Vorgang erfolgt asynchron im Hintergrund
|
||||
precompute: 500
|
||||
# Wie lange soll Sonar warten, bis der Spieler das CAPTCHA nicht besteht?
|
||||
# (Dieser Wert stellt die Zeit in Millisekunden dar: 1 Sekunde = 1000 Millisekunden)
|
||||
max-duration: 45000
|
||||
max-duration: 30000
|
||||
# Wie oft muss ein Spieler das CAPTCHA nicht bestehen, bevor er die Überprüfung nicht besteht?
|
||||
max-tries: 3
|
||||
# Zeichen (Buchstaben und Zahlen), die im Antwort-CAPTCHA erscheinen dürfen
|
||||
# Es wird nicht empfohlen, Zahlen oder Buchstaben hinzuzufügen, die einander ähneln könnten
|
||||
dictionary: '1235689'
|
||||
# Welche Schriftarten soll Sonar für die Map-CAPTCHA-Codes verwenden?
|
||||
font-names:
|
||||
- Dialog
|
||||
- DialogInput
|
||||
- SansSerif
|
||||
- Monospaced
|
||||
|
||||
# Überprüft, ob die Spieler eine gültige Client-Marke an den Server senden
|
||||
client-brand:
|
||||
|
||||
@@ -28,7 +28,7 @@ attack-tracker:
|
||||
# Amount of time that has to pass in order for an attack to be over
|
||||
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
|
||||
min-attack-duration: 30000
|
||||
# Number of times an incident has to be reported in order to be acknowledged as an attack
|
||||
# Number of times an incident has to be reported to be acknowledged as an attack
|
||||
# This number acts as a buffer to filter out false attack notifications
|
||||
min-attack-threshold: 2
|
||||
# Amount of time that has to pass in order for a new attack to be detected
|
||||
@@ -71,7 +71,7 @@ verification:
|
||||
timing: ALWAYS
|
||||
checks:
|
||||
# Checks if the players' falling motion is following Minecraft's gravity formula
|
||||
# All predicted motions are precalculated in order to save performance
|
||||
# All predicted motions are precalculated to save performance
|
||||
gravity:
|
||||
# Should Sonar check for valid client gravity? (Recommended)
|
||||
enabled: true
|
||||
@@ -79,7 +79,7 @@ verification:
|
||||
check-collisions: true
|
||||
# Should Sonar make the player solve a CAPTCHA if they fail the gravity check?
|
||||
captcha-on-fail: false
|
||||
# Maximum number of ticks the player has to fall in order to be allowed to hit the platform
|
||||
# Maximum number of ticks the player has to fall to be allowed to hit the platform
|
||||
max-movement-ticks: 8
|
||||
# The gamemode of the player during verification
|
||||
# Possible types: SURVIVAL, CREATIVE, ADVENTURE
|
||||
@@ -105,40 +105,52 @@ verification:
|
||||
# - NEVER: New players will never receive a CAPTCHA (Recommended)
|
||||
timing: NEVER
|
||||
# Options for the effects on the image shown to the player
|
||||
# You should only edit this if you know what you're doing
|
||||
effects:
|
||||
# Adds a glow effect to the image
|
||||
flare: true
|
||||
# Adds random lines to the image
|
||||
scratches: true
|
||||
# Applies a ripple (sine) distortion filter
|
||||
# Applies a ripple filter (wavy effect)
|
||||
ripple: true
|
||||
# Applies a horizontal distortion filter
|
||||
smear: true
|
||||
# Adds a bit of blurriness/distortion to the image
|
||||
pinch: true
|
||||
# Applies color correction (color saturation)
|
||||
saturation: 0.15
|
||||
# Applies a horizontal triangular ripple filter
|
||||
distortion: 2
|
||||
# Applies a bump filter (sharpened text)
|
||||
bump: true
|
||||
# Distortion filter
|
||||
distortion:
|
||||
# Should Sonar apply a distortion filter?
|
||||
enabled: true
|
||||
# What shape should Sonar use for the distortion filter?
|
||||
# Possible types: 0, 1, 2, 3
|
||||
# - 0: Crosses
|
||||
# - 1: Lines
|
||||
# - 2: Circles
|
||||
# - 3: Squares
|
||||
shape: 2
|
||||
# Distance between distorted pixels/objects
|
||||
distance: 5
|
||||
# Density of the distorted pixels/objects
|
||||
density: 0.1
|
||||
# Amount of blending between the colors of objects
|
||||
mix: 0.15
|
||||
# Path to the background image Sonar uses for the CAPTCHA
|
||||
# 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 the plugin directory
|
||||
background: ''
|
||||
# Should Sonar automatically detect the background color?
|
||||
# This is done to create a contrast between the background image and the text
|
||||
# If this is disabled, Sonar will use a random gradient for the colors
|
||||
auto-color: false
|
||||
# How many answers should Sonar prepare?
|
||||
# This task happens asynchronously in the background
|
||||
precompute: 500
|
||||
# How long should Sonar wait until the player fails the CAPTCHA?
|
||||
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
|
||||
max-duration: 45000
|
||||
max-duration: 30000
|
||||
# How many times must a player fail the CAPTCHA before failing the verification?
|
||||
max-tries: 3
|
||||
# Characters (letters and numbers) that are allowed to appear in the answer to the CAPTCHA
|
||||
# It is not recommended to add numbers or letters that might look like one another
|
||||
dictionary: '1235689'
|
||||
# Which fonts should Sonar use for the map CAPTCHA codes?
|
||||
font-names:
|
||||
- Dialog
|
||||
- DialogInput
|
||||
- SansSerif
|
||||
- Monospaced
|
||||
|
||||
# Checks if the players is sending a valid client brand to the server
|
||||
# Checks if the players are sending a valid client brand to the server
|
||||
client-brand:
|
||||
# Should Sonar check for valid client brands? (Recommended)
|
||||
enabled: true
|
||||
@@ -151,7 +163,7 @@ verification:
|
||||
valid-name-regex: ^[a-zA-Z0-9_]+$
|
||||
# Regex for validating client locale during verification
|
||||
valid-locale-regex: ^[a-zA-Z_]+$
|
||||
# Ping a player has to have in order to timeout
|
||||
# Ping a player has to have to timeout
|
||||
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
|
||||
max-ping: 10000
|
||||
# Maximum number of login packets the player has to send in order to be kicked
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
#
|
||||
# /$$$$$$
|
||||
# /$$__ $$
|
||||
# | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$
|
||||
# | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$
|
||||
# \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/
|
||||
# /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$
|
||||
# | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$
|
||||
# \______/ \______/ |__/ |__/ \_______/|__/
|
||||
#
|
||||
# Besoin d'aide ou d'autres questions ? https://jonesdev.xyz/discord
|
||||
# Code source : https://github.com/jonesdevelopment/sonar
|
||||
# Droit d'auteur Jones Development, un contributeur Sonar, licence sous GPL-3.0
|
||||
#
|
||||
|
||||
# Paramètre général de Sonar
|
||||
general:
|
||||
# Devrait Sonar enregistrer les adresses IP des joueurs dans la console ?
|
||||
log-player-addresses: true
|
||||
# Nombre maximum de joueurs en ligne avec la même IP
|
||||
max-online-per-ip: 3
|
||||
|
||||
# Paramètre de détection d'attaque
|
||||
# Modifier uniquement si vous savez ce que vous faites
|
||||
attack-tracker:
|
||||
# Nombre minimum de nouveaux joueurs pour qu'une attaque soit détectée
|
||||
min-players-for-attack: 8
|
||||
# Durée nécessaire pour qu'une attaque soit considérée comme terminée
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
min-attack-duration: 30000
|
||||
# Nombre de fois qu'un incident doit être signalé pour être reconnu comme une attaque
|
||||
# Ce nombre sert de tampon pour filtrer les fausses notifications d'attaque
|
||||
min-attack-threshold: 2
|
||||
# Durée nécessaire pour qu'une nouvelle attaque soit détectée
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
attack-cooldown-delay: 3000
|
||||
|
||||
# Vous pouvez connecter Sonar à une base de données pour conserver les joueurs vérifiés même après le redémarrage de votre serveur
|
||||
# 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
|
||||
type: NONE
|
||||
# Adresse de l'hôte pour l'authentification avec la base de données SQL
|
||||
host: localhost
|
||||
# Port pour l'authentification avec la base de données SQL
|
||||
port: 3306
|
||||
# Nom de la base de données SQL
|
||||
name: sonar
|
||||
# Nom d'utilisateur pour l'authentification avec la base de données SQL
|
||||
username: ''
|
||||
# Mot de passe pour l'authentification avec la base de données SQL
|
||||
password: ''
|
||||
# Pendant combien de jours Sonar doit-il conserver les joueurs vérifiés dans la base de données ?
|
||||
maximum-age: 5
|
||||
|
||||
# Chaque nouvelle demande de connexion sera mise en file d'attente pour éviter les attaques d'inscription par spam
|
||||
# La file d'attente est mise à jour toutes les 1 seconde (20 ticks)
|
||||
queue:
|
||||
# Nombre maximum de demandes de connexion en file d'attente simultanées par seconde
|
||||
max-polls: 30
|
||||
|
||||
# Chaque nouveau joueur qui se connecte pour la première fois sera envoyé à
|
||||
# un serveur limbo léger où des vérifications avancées de bot sont effectuées
|
||||
verification:
|
||||
# Quand Sonar devrait-il vérifier les nouveaux joueurs ?
|
||||
# Types possibles : ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS : Les nouveaux joueurs seront toujours vérifiés (Recommandé)
|
||||
# - DURING_ATTACK : Les nouveaux joueurs ne seront vérifiés que pendant une attaque
|
||||
# - NEVER : Les nouveaux joueurs ne seront jamais vérifiés
|
||||
timing: ALWAYS
|
||||
checks:
|
||||
# Vérifie si le mouvement de chute des joueurs suit la formule de la gravité de Minecraft
|
||||
# Tous les mouvements prévus sont précalculés afin d'économiser les performances
|
||||
gravity:
|
||||
# Sonar devrait-il vérifier la gravité du client ? (Recommandé)
|
||||
enabled: true
|
||||
# Sonar devrait-il vérifier si le joueur entre en collision avec des blocs ? (Recommandé)
|
||||
check-collisions: true
|
||||
# Sonar devrait-il faire résoudre un CAPTCHA au joueur s'il échoue à la vérification de la gravité ?
|
||||
captcha-on-fail: false
|
||||
# Nombre maximum de ticks que le joueur a pour tomber avant de pouvoir toucher la plateforme
|
||||
max-movement-ticks: 8
|
||||
# Le mode de jeu du joueur pendant la vérification
|
||||
# Types possibles : SURVIVAL, CREATIVE, ADVENTURE
|
||||
# - SURVIVAL : tous les composants de l'interface utilisateur sont visibles
|
||||
# - CREATIVE : la santé et la faim sont cachées
|
||||
# - ADVENTURE : tous les composants de l'interface utilisateur sont visibles
|
||||
gamemode: ADVENTURE
|
||||
|
||||
# Vérifie si le client envoie les paquets appropriés lorsqu'il monte dans un véhicule
|
||||
vehicle:
|
||||
# Types possibles : ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS : Les nouveaux joueurs seront toujours montés dans un véhicule (Recommandé)
|
||||
# - DURING_ATTACK : Les nouveaux joueurs ne seront montés dans un véhicule que pendant une attaque
|
||||
# - NEVER : Les nouveaux joueurs ne seront jamais montés dans un véhicule
|
||||
timing: ALWAYS
|
||||
|
||||
# Fait taper au joueur un code à partir d'une carte virtuelle dans le chat
|
||||
map-captcha:
|
||||
# Quand Sonar devrait-il faire résoudre un CAPTCHA au joueur ?
|
||||
# Types possibles : ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS : Les nouveaux joueurs recevront toujours un CAPTCHA
|
||||
# - DURING_ATTACK : Les nouveaux joueurs ne recevront un CAPTCHA que pendant une attaque
|
||||
# - NEVER : Les nouveaux joueurs ne recevront jamais de CAPTCHA (Recommandé)
|
||||
timing: NEVER
|
||||
# Options pour les effets sur l'image montrée au joueur
|
||||
# Vous ne devriez modifier cela que si vous savez ce que vous faites
|
||||
effects:
|
||||
# Ajoute des lignes aléatoires à l'image
|
||||
scratches: true
|
||||
# Applique un filtre d'ondulation (effet ondulé)
|
||||
ripple: true
|
||||
# Applique un filtre de bosse (texte accentué)
|
||||
bump: true
|
||||
# Filtre de distorsion
|
||||
distortion:
|
||||
# Sonar devrait-il appliquer un filtre de distorsion ?
|
||||
enabled: true
|
||||
# Quelle forme Sonar devrait-il utiliser pour le filtre de distorsion ?
|
||||
# Types possibles : 0, 1, 2, 3
|
||||
# - 0 : Croix
|
||||
# - 1 : Lignes
|
||||
# - 2 : Cercles
|
||||
# - 3 : Carrés
|
||||
shape: 2
|
||||
# Distance entre les pixels/objets déformés
|
||||
distance: 5
|
||||
# Densité des pixels/objets déformés
|
||||
density: 0.1
|
||||
# Quantité de mélange entre les couleurs des objets
|
||||
mix: 0.15
|
||||
# Chemin vers l'image d'arrière-plan que Sonar utilise pour le CAPTCHA
|
||||
# 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: ''
|
||||
# Sonar devrait-il détecter automatiquement la couleur de fond ?
|
||||
# Cela est fait pour créer un contraste entre l'image d'arrière-plan et le texte
|
||||
# Si cela est désactivé, Sonar utilisera un dégradé aléatoire pour les couleurs
|
||||
auto-color: false
|
||||
# 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
|
||||
# Combien de temps Sonar devrait-il attendre jusqu'à ce que le joueur échoue le CAPTCHA ?
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
max-duration: 30000
|
||||
# Combien de fois un joueur doit-il échouer au CAPTCHA avant d'échouer la vérification ?
|
||||
max-tries: 3
|
||||
# Caractères (lettres et chiffres) autorisés à apparaître dans la réponse au CAPTCHA
|
||||
# Il n'est pas recommandé d'ajouter des chiffres ou des lettres qui pourraient se ressembler
|
||||
dictionary: '1235689'
|
||||
|
||||
# Vérifie si le joueur envoie une marque client valide au serveur
|
||||
client-brand:
|
||||
# Sonar devrait-il vérifier les marques client valides ? (Recommandé)
|
||||
enabled: true
|
||||
# Regex pour valider les marques client lors de la vérification
|
||||
valid-regex: ^[!-~ ]+$
|
||||
# Longueur maximale de la marque client lors de la vérification
|
||||
max-length: 64
|
||||
|
||||
# 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_]+$
|
||||
# Le ping qu'un joueur doit avoir pour dépasser le délai d'attente
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
max-ping: 10000
|
||||
# Nombre maximal de paquets de connexion que le joueur doit envoyer pour être expulsé
|
||||
max-login-packets: 256
|
||||
|
||||
# S'il est activé, le joueur sera renvoyé au serveur d'origine
|
||||
# après avoir passé avec succès la vérification du bot.
|
||||
# Cette fonctionnalité a été introduite par Mojang dans la version Minecraft 1.20.5
|
||||
transfer:
|
||||
# Sonar devrait-il transférer le joueur au serveur d'origine (au lieu de l'expulser) ?
|
||||
# Pour que cela fonctionne, vous devez activer la fonctionnalité dans la configuration de votre serveur
|
||||
# De plus, vous voudrez peut-être réduire la quantité de limitation de débit de connexion
|
||||
# effectuée par Velocity ou d'autres proxys/plugins, car cela pourrait empêcher le
|
||||
# joueur d'être transféré correctement.
|
||||
enabled: false
|
||||
# Quel serveur Sonar devrait-il utiliser pour transférer le joueur une fois la vérification réussie ?
|
||||
# Veuillez entrer l'adresse IP du serveur que les joueurs utilisent normalement pour se connecter à votre serveur.
|
||||
# Par exemple, vous pouvez mettre "mc.hypixel.net" ou une IP directe comme "1.1.1.1"
|
||||
destination-host: "play.my-server.com"
|
||||
# Quel port Sonar devrait-il utiliser pour transférer le joueur au serveur d'origine ?
|
||||
# Si votre serveur n'a pas besoin d'un port pour se connecter, vous pouvez laisser celui-ci comme 25565.
|
||||
destination-port: 25565
|
||||
|
||||
# Sonar devrait-il journaliser les nouvelles tentatives de vérification ?
|
||||
log-connections: true
|
||||
# Sonar devrait-il journaliser les nouvelles tentatives de vérification pendant les attaques ?
|
||||
log-during-attack: false
|
||||
# Sonar devrait-il journaliser chaque changement de position/mouvement pendant la vérification ?
|
||||
# Ce n'est pas recommandé pour les serveurs de production mais peut être utile pour repérer les erreurs.
|
||||
debug-xyz-positions: false
|
||||
# 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
|
||||
# Durée avant qu'un joueur ne soit déconnecté
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
read-timeout: 8000
|
||||
# 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: 8000
|
||||
# Combien de temps Sonar doit-il se souvenir du nombre de vérifications échouées pour un joueur ?
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
remember-time: 120000
|
||||
# Combien de temps une adresse IP doit-elle être interdite de connexion en cas d'échec trop fréquent de la vérification ?
|
||||
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
|
||||
blacklist-time: 600000
|
||||
# Combien de fois un joueur doit-il échouer à la vérification pour être placé sur liste noire ?
|
||||
# (Réglez cette valeur à 0 pour désactiver la liste noire entièrement)
|
||||
blacklist-threshold: 2
|
||||
# Liste des identifiants de protocole qui ne sont pas vérifiés par Sonar (bypass de vérification)
|
||||
# Vous pouvez trouver la liste complète de tous les identifiants de protocole ici :
|
||||
# https://wiki.vg/Protocol_version_numbers
|
||||
# Par exemple, Minecraft 1.20 a l'ID 763.
|
||||
whitelisted-protocols: []
|
||||
# Liste des identifiants de protocole qui ne peuvent pas du tout rejoindre le serveur
|
||||
blacklisted-protocols: []
|
||||
@@ -66,7 +66,7 @@ verification:
|
||||
# როდის უნდა გადაამოწმოს Sonar-მა ახალი მოთამაშეები?
|
||||
# შესაძლო ტიპები: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: ახალი მოთამაშეები ყოველთვის მოწმდება (რეკომენდებულია)
|
||||
# - DURING_ATTACK: ახალი მოთამაშეები შემოწმდებიან მხოლოდ შეტევის დროს
|
||||
# - DURING_ATTACK: ახალი მოთამაშეები შემოწმდებიან მხოლოდ შეტევის დროსდროს
|
||||
# - NEVER: ახალი მოთამაშეები არასოდეს შემოწმდებიან
|
||||
timing: ALWAYS
|
||||
checks:
|
||||
@@ -88,12 +88,12 @@ verification:
|
||||
# - ADVENTURE: ყველა UI კომპონენტი ჩანს
|
||||
gamemode: ADVENTURE
|
||||
|
||||
# Checks if the client sends proper packets when mounting a vehicle
|
||||
# ამოწმებს, აგზავნის თუ არა კლიენტი შესაბამის პაკეტებს სატრანსპორტო საშუალებაზე დაჯდომის დროს
|
||||
vehicle:
|
||||
# Possible types: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: New players will always be mounted on a vehicle (Recommended)
|
||||
# - DURING_ATTACK: New players will only be mounted on a vehicle during an attack
|
||||
# - NEVER: New players will never be mounted on a vehicle
|
||||
# შესაძლო ტიპები: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: ახალი მოთამაშეები ყოველთვის დაჯდებიან სატრანსპორტო საშუალებაზე
|
||||
# - DURING_ATTACK: ახალი მოთამაშეები მხოლოდ ბოტების შემოტევის დროს დაჯდებიან სატრანსპორტო საშუალებაზე
|
||||
# - NEVER: ახალი მოთამაშეები არასოდეს დაჯდებიან სატრანსპორტო საშუალებაზე (რეკომენდებულია)
|
||||
timing: ALWAYS
|
||||
|
||||
# დააწერინეთ მოთამაშეს კოდი ჩატში, რომელიც იქნება ნაჩვენები ვირტუალურ მაპზე, რომელიც ხელში ეჭირებად
|
||||
@@ -104,41 +104,53 @@ verification:
|
||||
# - DURING_ATTACK: ახალი მოთამაშებს მოუწევთ CAPTCHA-ს გაკეთება მხოლოდ შეტევის დროს
|
||||
# - NEVER: ახალ მოთამაშეებს არასდროს მოუწევთ CAPTCHA-ს გაკეთება (Recommended)
|
||||
timing: NEVER
|
||||
# Options for the effects on the image shown to the player
|
||||
# ეფექტების პარამეტრები გამოსახულებაზე, რომელიც აჩვენა მოთამაშეს
|
||||
# თქვენ უნდა შეცვალოთ ეს მხოლოდ იმ შემთხვევაში, თუ იცით, რას აკეთებთ
|
||||
effects:
|
||||
# Adds a glow effect to the image
|
||||
flare: true
|
||||
# Adds random lines to the image
|
||||
# მატებს შემთხვევითი ხაზების ეფექტს გამოსახულებაზე
|
||||
scratches: true
|
||||
# Applies a ripple (sine) distortion filter
|
||||
# აყენებს ტალღური ეფექტის ფილტრს (ტალღისებური ეფექტი)
|
||||
ripple: true
|
||||
# Applies a horizontal distortion filter
|
||||
smear: true
|
||||
# Adds a bit of blurriness/distortion to the image
|
||||
pinch: true
|
||||
# Applies color correction (color saturation)
|
||||
saturation: 0.15
|
||||
# Applies a horizontal triangular ripple filter
|
||||
distortion: 2
|
||||
# აყენებს ამობურცული ტექსტის ფილტრს (გამხრწნილი ტექსტი)
|
||||
bump: true
|
||||
# დამახინჯების ფილტრი
|
||||
distortion:
|
||||
# უნდა დაამატოს თუ არა Sonar-მა დამახინჯების ფილტრი?
|
||||
enabled: true
|
||||
# რა ფორმას უნდა გამოიყენოს Sonar-მა დამახინჯების ფილტრისთვის?
|
||||
# შესაძლო ტიპები: 0, 1, 2, 3
|
||||
# - 0: ჯვრები
|
||||
# - 1: ხაზები
|
||||
# - 2: წრეები
|
||||
# - 3: კვადრატები
|
||||
shape: 2
|
||||
# მანძილი დამახინჯებულ პიქსელებს/ობიექტებს შორის
|
||||
distance: 5
|
||||
# დამახინჯებული პიქსელების/ობიექტების სიხშირე
|
||||
density: 0.1
|
||||
# შერევის ხარისხი ობიექტების ფერებს შორის
|
||||
mix: 0.15
|
||||
# CAPTCHA-სთვის Sonar-ის მიერ გამოყენებული ფონური გამოსახულების ბილიკი
|
||||
# თუ გამოსახულება არ მოიძებნა, ფონად გამოყენებული იქნება noise ი
|
||||
# შეგიძლიათ უბრალოდ ჩაწეროთ ფაილის სახელი, თუ ის პლაგინის დირექტორიაშია
|
||||
background: ''
|
||||
# უნდა განსაზღვროს თუ არა Sonar-მა ავტომატურად ფონის ფერი?
|
||||
# ეს კეთდება იმისთვის, რომ შეიქმნას კონტრასტი ფონის გამოსახულებასა და ტექსტს შორის
|
||||
# თუ ეს გამორთულია, Sonar-ი გამოიყენებს შემთხვევით გრადიენტს ფერებისთვის
|
||||
auto-color: false
|
||||
# რამდენი პასუხი უნდა მოამზადოს Sonar-მა?
|
||||
# ეს ხდება ასინქრონულად უკანა ფონზე
|
||||
precompute: 500
|
||||
# რამდენ ხანს უნდა დაელოდოს Sonar-ი, სანამ მოთამაშე ვერ გააკეთებს წარმატებულად CAPTCHA-ს?
|
||||
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
|
||||
max-duration: 45000
|
||||
max-duration: 30000
|
||||
# რამდენჯერ ვერ უდნა გაიაროს CAPTCHA მოთამაშემ სანამ ვერიფიკაციას ვერ გაივლის?
|
||||
max-tries: 3
|
||||
# სიმბოლოები (ასოები და რიცხვები), რომლებიც დაშვებულია გამოჩნდეს CAPTCHA-ს პასუხში
|
||||
# It is not recommended to add numbers or letters that might look like one another
|
||||
# არ არის რეკომენდებული რიცხვების ან ასოების დამატება, რომლებიც შეიძლება ერთმანეთს ჰგავდეს
|
||||
dictionary: '1235689'
|
||||
# Which fonts should Sonar use for the map CAPTCHA codes?
|
||||
font-names:
|
||||
- Dialog
|
||||
- DialogInput
|
||||
- SansSerif
|
||||
- Monospaced
|
||||
|
||||
#ამოწმებს, აგზავნიან თუ არა მოთამაშეები სერვერზე რეალურ კლიენტის სახელს
|
||||
# ამოწმებს, აგზავნიან თუ არა მოთამაშეები სერვერზე რეალურ კლიენტის სახელს
|
||||
client-brand:
|
||||
# უნდა შეამოწმოს თუ არა Sonar-მა ნამდვილია თუ არა მოთამაშის კლიენტის სახელი? (რეკომენდებულია)
|
||||
enabled: true
|
||||
@@ -157,22 +169,21 @@ verification:
|
||||
# მაქსიმალური რაოდენობა ლოგინ პაკეტების, რომელიც მოთამაშემ უნდა გააგზავნოს სანამ გაიკიკება სერვერიდან
|
||||
max-login-packets: 256
|
||||
|
||||
# If enabled, the player will be transferred back to the origin server
|
||||
# after successfully passing the bot verification.
|
||||
# This feature was introduced by Mojang in Minecraft version 1.20.5
|
||||
# თუ ჩართულია, მოთამაშე გადავა საწყისი სერვერში ერიფიკაციის წარმატებით გავლის შემდეგ
|
||||
# ეს ფუნქცია დაემატა Mojang-ის მიერ Minecraft-ის 1.20.5 ვერსიაში
|
||||
transfer:
|
||||
# Should Sonar transfer the player to the origin server (instead of kicking them)?
|
||||
# For this to work, you must enable the feature in your server's configuration
|
||||
# Additionally, you might want to reduce the amount of login rate-limiting
|
||||
# performed by Velocity or other proxies/plugins, as this might prevent the
|
||||
# player from being transferred correctly.
|
||||
# უნდა გადაიყვანოს თუ არა Sonar-მა მოთამაშე საწყის სერვერზე (მათი გაკიკვის ნაცვლად)?
|
||||
# ამისთვის, თქვენ უნდა ჩართოთ ეს ფუნქცია თქვენი სერვერის კონფიგურაციაში
|
||||
# დამატებით, შეიძლება გინდოდეთ შეამციროთ შესვლის rate-limiting ი
|
||||
# რომელსაც ახორციელებს Velocity ან სხვა პროქსები/პლაგინები, რადგან ეს შეიძლება ხელს უშლიდეს
|
||||
# მოთამაშის სწორად გადაყვანას
|
||||
enabled: false
|
||||
# Which server should Sonar transfer the player to when the verification is passed?
|
||||
# Please enter the server IP that is used by players to normally connect to your server.
|
||||
# For example, you can put "mc.hypixel.net" or a direct IP like "1.1.1.1"
|
||||
# რომელ სერვერზე უნდა გადაიყვანოს Sonar-მა მოთამაშე ვერიფიკაციის გავლის შემდეგ?
|
||||
# გთხოვთ, შეიყვანოთ სერვერის IP მისამართი, რომლითაც მოთამაშეები ჩვეულებრივ უერთდებიან თქვენს სერვერს
|
||||
# მაგალითად, შეგიძლიათ ჩაწეროთ "mc.hypixel.net" ან პირდაპირი IP როგორიცაა "1.1.1.1"
|
||||
destination-host: "play.my-server.com"
|
||||
# Which port should Sonar use when transferring the player to the origin server?
|
||||
# If your server does not need a port to connect to, you can leave this as 25565.
|
||||
# რომელი პორტი უნდა გამოიყენოს Sonar-მა მოთამაშის საწყის სერვერზე გადაყვანისას?
|
||||
# თუ თქვენს სერვერს არ სჭირდება პორტი შესასვლელად, შეგიძლიათ დატოვოთ ეს 25565-ზე
|
||||
destination-port: 25565
|
||||
|
||||
# ჩაიწეროს თუ არა Sonar-მა ახალი ვერიფიკაციის მცდელობები?
|
||||
@@ -182,9 +193,9 @@ verification:
|
||||
# ჩაიწეროს თუ არა Sonar-მა ყოველი მოძრაობა/პოზიცია ვერიფიკაციის დროს?
|
||||
# ეს არ არის რეკომენდირებული აქტიურ სერვერებისთვის, მაგრამ შეიძლება გამოსადეგი იყოს ცრუ პოსიტივების გამოსასწორებლად.
|
||||
debug-xyz-positions: false
|
||||
# Should Sonar also check Geyser (Bedrock) players?
|
||||
# This feature is experimental and might cause issues
|
||||
# If this is disabled, Bedrock players will be skipped
|
||||
# უნდა შეამოწმოს თუ არა Sonar-მა Geyser (Bedrock) მოთამაშეები?
|
||||
# ეს ფუნქცია ექსპერიმენტულია და შეიძლება გამოიწვიოს პრობლემები
|
||||
# თუ ეს გამორთულია, Bedrock მოთამაშეები გამოვლენილი იქნება
|
||||
check-geyser-players: true
|
||||
# დროის ოდენობა, რომელიც უნდა გავიდეს, სანამ მოთამაშე ტაიმაუტდება სერვერიდან.
|
||||
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
|
||||
@@ -192,7 +203,7 @@ verification:
|
||||
# რამდენ ხანს უნდა დაელოდოს მოთამაშე ვერიფიკაციის დროს ხელახლა დაკავშირებამდე?
|
||||
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
|
||||
rejoin-delay: 8000
|
||||
# How long should Sonar remember the amount of failed verifications for a player?
|
||||
# რამდენ ხანს უნდა ახსოვდეს Sonar-ს მოთამაშე რამდენჯერ იყო წარუმატებელი ვერიფიკაციის დროს?
|
||||
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
|
||||
remember-time: 120000
|
||||
# რამდენ ხნით უნდა აეკრძალოს IP მისამართს შესვლა, როდესაც ვერიფიკაციას ძალიან ხშირად ვერ აკეთებს?
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
#
|
||||
# /$$$$$$
|
||||
# /$$__ $$
|
||||
# | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$
|
||||
# | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$
|
||||
# \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/
|
||||
# /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$
|
||||
# | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$
|
||||
# \______/ \______/ |__/ |__/ \_______/|__/
|
||||
#
|
||||
# Hulp nodig of vragen? https://jonesdev.xyz/discord
|
||||
# Broncode: https://github.com/jonesdevelopment/sonar
|
||||
# Copyright Jones Development and Sonar Contributors, licensed under GPL-3.0
|
||||
#
|
||||
|
||||
# Algemene instellingen voor Sonar
|
||||
general:
|
||||
# Moet Sonar de IP-adressen van spelers in de console registreren?
|
||||
log-player-addresses: true
|
||||
# Maximaal aantal spelers online met hetzelfde IP-adres
|
||||
max-online-per-ip: 3
|
||||
|
||||
# Gevoeligheidsinstellingen voor de aanvalstracker
|
||||
# Bewerk dit alleen als je weet wat je doet
|
||||
attack-tracker:
|
||||
# Minimumaantal nieuwe spelers om een aanval te kunnen detecteren
|
||||
min-players-for-attack: 8
|
||||
# De hoeveelheid tijd die moet verstrijken voordat een aanval voorbij is
|
||||
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
|
||||
min-attack-duration: 30000
|
||||
# Aantal keren dat een incident moet worden gemeld om als aanval te worden erkend
|
||||
# Dit nummer fungeert als buffer om valse aanvalsmeldingen eruit te filteren
|
||||
min-attack-threshold: 2
|
||||
# De hoeveelheid tijd die moet verstrijken voordat een nieuwe aanval wordt gedetecteerd
|
||||
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
|
||||
attack-cooldown-delay: 3000
|
||||
|
||||
# U kunt Sonar verbinden met een database om geverifieerde spelers te behouden, zelfs nadat u uw server opnieuw hebt opgestart
|
||||
# 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
|
||||
type: NONE
|
||||
# Adres voor authenticatie met de SQL-database
|
||||
host: localhost
|
||||
# Poort voor authenticatie met de SQL-database
|
||||
port: 3306
|
||||
# Naam van de SQL-database
|
||||
name: sonar
|
||||
# Gebruikersnaam voor authenticatie met de SQL-database
|
||||
username: ''
|
||||
# Wachtwoord voor authenticatie met de SQL-database
|
||||
password: ''
|
||||
# Hoeveel dagen moet Sonar geverifieerde spelers in de database bewaren?
|
||||
maximum-age: 5
|
||||
|
||||
# Elk nieuw inlogverzoek wordt in de wachtrij geplaatst om spam-join-aanvallen te voorkomen
|
||||
# De wachtrij wordt elke seconde bijgewerkt (20 ticks)
|
||||
queue:
|
||||
# Maximaal aantal gelijktijdige peilingen per seconde
|
||||
max-polls: 30
|
||||
|
||||
# Elke nieuwe speler die voor de eerste keer meedoet, wordt naar gestuurd
|
||||
# een lichtgewicht limbo-server waar geavanceerde bot-controles worden uitgevoerd
|
||||
verification:
|
||||
# Wanneer moet Sonar nieuwe spelers verifiëren?
|
||||
# Mogelijke typen: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: Nieuwe spelers worden altijd gecontroleerd (Aanbevolen)
|
||||
# - DURING_ATTACK: Nieuwe spelers worden alleen gecontroleerd tijdens een aanval
|
||||
# - NEVER: Nieuwe spelers worden nooit gecontroleerd
|
||||
timing: ALWAYS
|
||||
checks:
|
||||
# Controleert of de valbeweging van de spelers de zwaartekrachtformule van Minecraft volgt
|
||||
# Alle voorspelde bewegingen worden vooraf berekend om prestaties te besparen
|
||||
gravity:
|
||||
# Moet Sonar controleren op geldige zwaartekracht van de cliënt? (Aanbevolen)
|
||||
enabled: true
|
||||
# Moet Sonar controleren of de speler tegen blokken botst? (Aanbevolen)
|
||||
check-collisions: true
|
||||
# Moet Sonar de speler een CAPTCHA laten oplossen als hij niet slaagt voor de zwaartekracht controle?
|
||||
captcha-on-fail: false
|
||||
# Maximaal aantal ticks dat de speler moet laten vallen om het platform te mogen raken
|
||||
max-movement-ticks: 8
|
||||
# De spelmodus van de speler tijdens verificatie
|
||||
# Mogelijke typen: SURVIVAL, CREATIVE, ADVENTURE
|
||||
# - SURVIVAL: alle UI-componenten zijn zichtbaar
|
||||
# - CREATIVE: gezondheid en honger zijn verborgen
|
||||
# - ADVENTURE: alle UI-componenten zijn zichtbaar
|
||||
gamemode: ADVENTURE
|
||||
|
||||
# Controleert of de klant de juiste pakketten verzendt bij het monteren van een voertuig
|
||||
vehicle:
|
||||
# Mogelijke typen: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: Nieuwe spelers worden altijd op een voertuig gemonteerd (Aanbevolen)
|
||||
# - DURING_ATTACK: Nieuwe spelers worden alleen tijdens een aanval op een voertuig gemonteerd
|
||||
# - NEVER: Nieuwe spelers zullen nooit op een voertuig worden gemonteerd
|
||||
timing: ALWAYS
|
||||
|
||||
# Laat de speler een code van een virtuele kaart in de chat typen
|
||||
map-captcha:
|
||||
# Wanneer moet Sonar de speler een CAPTCHA laten oplossen?
|
||||
# Mogelijke typen: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: Nieuwe spelers ontvangen altijd een CAPTCHA
|
||||
# - DURING_ATTACK: Nieuwe spelers ontvangen alleen een CAPTCHA tijdens een aanval
|
||||
# - NEVER: Nieuwe spelers zullen nooit een CAPTCHA ontvangen (Aanbevolen)
|
||||
timing: NEVER
|
||||
# Opties voor de effecten op de afbeelding die aan de speler wordt getoond
|
||||
# Je moet dit alleen bewerken als je weet wat je doet
|
||||
effects:
|
||||
# Voegt willekeurige lijnen toe aan de afbeelding
|
||||
scratches: true
|
||||
# Past een ripple-filter toe (golfeffect)
|
||||
ripple: true
|
||||
# Past een bump-filter toe (verscherpte tekst)
|
||||
bump: true
|
||||
# Vervormingsfilter
|
||||
distortion:
|
||||
# Moet Sonar een vervormingsfilter toepassen?
|
||||
enabled: true
|
||||
# Welke vorm moet Sonar gebruiken voor het vervormingsfilter?
|
||||
# Mogelijke typen: 0, 1, 2, 3
|
||||
# - 0: Kruisen
|
||||
# - 1: Lijnen
|
||||
# - 2: Cirkels
|
||||
# - 3: Vierkantjes
|
||||
shape: 2
|
||||
# Afstand tussen vervormde pixels/objecten
|
||||
distance: 5
|
||||
# Dichtheid van de vervormde pixels/objecten
|
||||
density: 0.1
|
||||
# Hoeveelheid overvloeiing tussen de kleuren van objecten
|
||||
mix: 0.15
|
||||
# Pad naar de achtergrondafbeelding die Sonar gebruikt voor de CAPTCHA
|
||||
# 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: ''
|
||||
# Moet Sonar automatisch de achtergrondkleur detecteren?
|
||||
# Dit wordt gedaan om een contrast te creëren tussen de achtergrondafbeelding en de tekst
|
||||
# Als dit is uitgeschakeld, gebruikt Sonar een willekeurig verloop voor de kleuren
|
||||
auto-color: false
|
||||
# Hoeveel antwoorden moet Sonar voorbereiden?
|
||||
# Deze taak gebeurt asynchroon op de achtergrond
|
||||
precompute: 500
|
||||
# Hoe lang moet Sonar wachten totdat de speler de CAPTCHA niet haalt?
|
||||
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
|
||||
max-duration: 30000
|
||||
# Hoe vaak moet een speler de CAPTCHA niet halen voordat de verificatie mislukt?
|
||||
max-tries: 3
|
||||
# Tekens (letters en cijfers) die mogen voorkomen in het antwoord op de CAPTCHA
|
||||
# Het wordt niet aanbevolen om cijfers of letters toe te voegen die op elkaar lijken
|
||||
dictionary: '1235689'
|
||||
|
||||
# Controleert of de speler een geldig Minecraft-klantmerk naar de server verzendt
|
||||
client-brand:
|
||||
# Moet Sonar controleren op geldige Minecraft-klantmerk? (Aanbevolen)
|
||||
enabled: true
|
||||
# Regex voor het valideren van Minecraft-klantmerken tijdens verificatie
|
||||
valid-regex: ^[!-~ ]+$
|
||||
# Maximale lengte van het Minecraft-klantmerk tijdens verificatie
|
||||
max-length: 64
|
||||
|
||||
# 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_]+$
|
||||
# Ping moet een speler hebben om een time-out te krijgen
|
||||
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
|
||||
max-ping: 10000
|
||||
# Maximaal aantal loginpakketten dat de speler moet verzenden om te worden geschopt
|
||||
max-login-packets: 256
|
||||
|
||||
# Indien ingeschakeld, wordt de speler teruggestuurd naar de oorspronkelijke server
|
||||
# nadat u de bot-verificatie met succes heeft doorstaan.
|
||||
# Deze functie is geïntroduceerd door Mojang in Minecraft versie 1.20.5
|
||||
transfer:
|
||||
# Moet Sonar de speler overbrengen naar de oorspronkelijke server (in plaats van hem te schoppen)?
|
||||
# Om dit te laten werken, moet u de functie inschakelen in de configuratie van uw server
|
||||
# Bovendien wilt u mogelijk de beperking van de inlegsnelheid verminderen
|
||||
# uitgevoerd door Velocity van andere proxy's/plugins, omdat dit de
|
||||
# speler wordt niet correct weergegeven.
|
||||
enabled: false
|
||||
# Naar welke server moet Sonar de speler overbrengen wanneer de verificatie is geslaagd?
|
||||
# Voer het server-IP in dat door spelers wordt gebruikt om normaal verbinding te maken met uw server.
|
||||
# U kunt bijvoorbeeld "mc.hypixel.net" of een direct IP-adres zoals "1.1.1.1" invoeren
|
||||
destination-host: "play.my-server.com"
|
||||
# Welke poort moet Sonar gebruiken bij het overbrengen van de speler naar de oorspronkelijke server?
|
||||
# Als uw server geen poort nodig heeft om verbinding mee te maken, kunt u dit op 25565 laten staan.
|
||||
destination-port: 25565
|
||||
|
||||
# Moet Sonar nieuwe verificatiepogingen registreren?
|
||||
log-connections: true
|
||||
# Moet Sonar nieuwe verificatiepogingen registreren tijdens aanvallen?
|
||||
log-during-attack: false
|
||||
# Moet Sonar elke beweging/positieverandering tijdens de verificatie registreren?
|
||||
# Dit wordt niet aanbevolen voor productieservers, maar kan nuttig zijn bij het opsporen van fouten.
|
||||
debug-xyz-positions: false
|
||||
# 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
|
||||
# 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
|
||||
# Hoe lang moet een speler wachten voordat hij tijdens de verificatie opnieuw verbinding maakt?
|
||||
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
|
||||
rejoin-delay: 8000
|
||||
# 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
|
||||
# Hoe lang moet een IP-adres worden ontzegd om in te loggen als de verificatie te vaak mislukt?
|
||||
# (Deze waarde vertegenwoordigt de tijd in milliseconden: 1 seconde = 1000 milliseconden)
|
||||
blacklist-time: 600000
|
||||
# Hoe vaak moet een speler de verificatie niet doorstaan om op de zwarte lijst te worden geplaatst?
|
||||
# (Stel deze waarde in op 0 om de zwarte lijst volledig uit te schakelen)
|
||||
blacklist-threshold: 2
|
||||
# Lijst met protocol-ID's die niet door Sonar worden gecontroleerd (verificatie-bypass)
|
||||
# De volledige lijst met alle protocol-ID's vindt u hier:
|
||||
# https://wiki.vg/Protocol_version_numbers
|
||||
# Minecraft 1.20 heeft bijvoorbeeld de ID 763.
|
||||
whitelisted-protocols: []
|
||||
# Lijst met protocol-ID's die helemaal geen verbinding kunnen maken met de server
|
||||
blacklisted-protocols: []
|
||||
@@ -88,12 +88,12 @@ verification:
|
||||
# - ADVENTURE: все компоненты пользовательского интерфейса видны
|
||||
gamemode: ADVENTURE
|
||||
|
||||
# Checks if the client sends proper packets when mounting a vehicle
|
||||
# Проверяет, отправляет ли клиент правильные пакеты при садке на транспортное средство
|
||||
vehicle:
|
||||
# Possible types: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: New players will always be mounted on a vehicle (Recommended)
|
||||
# - DURING_ATTACK: New players will only be mounted on a vehicle during an attack
|
||||
# - NEVER: New players will never be mounted on a vehicle
|
||||
# Возможные типы: ALWAYS, DURING_ATTACK, NEVER
|
||||
# - ALWAYS: Новые игроки всегда будут садиться на транспортное средство (Рекомендуется)
|
||||
# - DURING_ATTACK: Новые игроки будут садиться на транспортное средство только во время атаки
|
||||
# - NEVER: Новые игроки никогда не будут садиться на транспортное средство
|
||||
timing: ALWAYS
|
||||
|
||||
# Заставить игрока ввести код с картинки в чат
|
||||
@@ -105,38 +105,49 @@ verification:
|
||||
# - NEVER: Новые игроки никогда не получат капчу (Рекомендуется)
|
||||
timing: NEVER
|
||||
# Кастомизация эффектов на картинке, которые показываются игроку
|
||||
# Рекомендуется редактировать только если вы знаете, что делаете
|
||||
effects:
|
||||
# Добавляет свечение к изображению
|
||||
flare: true
|
||||
# Добавляет случайные линии к изображению
|
||||
# Добавляет случайные линии на изображение
|
||||
scratches: true
|
||||
# Применяет искажение ряби (синусоидальное)
|
||||
# Применяет эффект волны (ripple)
|
||||
ripple: true
|
||||
# Применяет горизонтальное искажение
|
||||
smear: true
|
||||
# Добавляет немного размытости/искажения к изображению
|
||||
pinch: true
|
||||
# Применяет цветокоррекцию (насыщенность цвета)
|
||||
saturation: 0.15
|
||||
# Применяет горизонтальное треугольное искажение
|
||||
distortion: 2
|
||||
# Применяет фильтр bump (увеличивает резкость текста)
|
||||
bump: true
|
||||
# Фильтр искажения
|
||||
distortion:
|
||||
# Следует ли применять фильтр искажения?
|
||||
enabled: true
|
||||
# Какую форму следует использовать Sonar для фильтра искажения?
|
||||
# Возможные типы: 0, 1, 2, 3
|
||||
# - 0: Кресты
|
||||
# - 1: Линии
|
||||
# - 2: Круги
|
||||
# - 3: Квадраты
|
||||
shape: 2
|
||||
# Расстояние между искаженными пикселями/объектами
|
||||
distance: 5
|
||||
# Плотность искаженных пикселей/объектов
|
||||
density: 0.1
|
||||
# Степень смешивания между цветами объектов
|
||||
mix: 0.15
|
||||
# Путь к фоновому изображению, которое использует Sonar для CAPTCHA
|
||||
# Если изображение не найдено, будет использован шум как фон по умолчанию
|
||||
background: ''
|
||||
# Следует ли Sonar автоматически определять цвет фона?
|
||||
# Это делается для создания контраста между фоновым изображением и текстом
|
||||
# Просто укажите имя файла здесь, если файл находится в каталоге плагина
|
||||
auto-color: false
|
||||
# Сколько капч должен подготовить Sonar?
|
||||
# Эта задача выполняется асинхронно в фоновом режиме
|
||||
precompute: 500
|
||||
# Как долго Sonar должен ждать, пока игрок не пройдет капча?
|
||||
# (Это значение представляет время в миллисекундах: 1 секунда = 1000 миллисекунд)
|
||||
max-duration: 45000
|
||||
max-duration: 30000
|
||||
# Сколько раз игрок должен завалить капчу, чтобы не пройти проверку?
|
||||
max-tries: 3
|
||||
# Символы (буквы и цифры), которые разрешено использовать в ответе на капчу
|
||||
# It is not recommended to add numbers or letters that might look like one another
|
||||
# Не рекомендуется добавлять цифры или буквы, которые могут быть похожи друг на друга
|
||||
dictionary: '1235689'
|
||||
# Какие типы шрифтов следует использовать в Sonar для текста в капче?
|
||||
font-names:
|
||||
- Dialog
|
||||
- DialogInput
|
||||
- SansSerif
|
||||
- Monospaced
|
||||
|
||||
# Проверяет, отправляет ли игрок на сервер действительный клиентский бренд.
|
||||
client-brand:
|
||||
@@ -157,22 +168,22 @@ verification:
|
||||
# Максимальное количество пакетов для входа на сервер, которое игрок должен отправить, чтобы быть выгнанным
|
||||
max-login-packets: 256
|
||||
|
||||
# If enabled, the player will be transferred back to the origin server
|
||||
# after successfully passing the bot verification.
|
||||
# This feature was introduced by Mojang in Minecraft version 1.20.5
|
||||
# Если включено, игрок будет возвращен на исходный сервер
|
||||
# после успешного прохождения проверки на бота.
|
||||
# Эта функция была введена Mojang в версии Minecraft 1.20.5
|
||||
transfer:
|
||||
# Should Sonar transfer the player to the origin server (instead of kicking them)?
|
||||
# For this to work, you must enable the feature in your server's configuration
|
||||
# Additionally, you might want to reduce the amount of login rate-limiting
|
||||
# performed by Velocity or other proxies/plugins, as this might prevent the
|
||||
# player from being transferred correctly.
|
||||
# Должен ли Sonar переместить игрока на исходный сервер (вместо выкидывания его)?
|
||||
# Для этого необходимо включить функцию в конфигурации вашего сервера
|
||||
# Кроме того, вы можете пожелать снизить количество ограничений на скорость входа
|
||||
# выполняемых Velocity или другими прокси/плагинами, так как это может помешать
|
||||
# корректному перемещению игрока.
|
||||
enabled: false
|
||||
# Which server should Sonar transfer the player to when the verification is passed?
|
||||
# Please enter the server IP that is used by players to normally connect to your server.
|
||||
# For example, you can put "mc.hypixel.net" or a direct IP like "1.1.1.1"
|
||||
# На какой сервер должен Sonar переместить игрока после прохождения проверки?
|
||||
# Введите IP-адрес сервера, который обычно используется игроками для подключения к вашему серверу.
|
||||
# Например, вы можете указать "mc.hypixel.net" или прямой IP-адрес, например "1.1.1.1"
|
||||
destination-host: "play.my-server.com"
|
||||
# Which port should Sonar use when transferring the player to the origin server?
|
||||
# If your server does not need a port to connect to, you can leave this as 25565.
|
||||
# Какой порт должен использовать Sonar при перемещении игрока на исходный сервер?
|
||||
# Если ваш сервер не требует порта для подключения, вы можете оставить это как 25565.
|
||||
destination-port: 25565
|
||||
|
||||
# Должен ли Sonar регистрировать новые попытки проверки?
|
||||
@@ -182,9 +193,9 @@ verification:
|
||||
# Должен ли Sonar регистрировать каждое движение/изменение положения во время проверки?
|
||||
# Это не рекомендуется для рабочих серверов, но может быть полезно для выявления ошибок.
|
||||
debug-xyz-positions: false
|
||||
# Should Sonar also check Geyser (Bedrock) players?
|
||||
# This feature is experimental and might cause issues
|
||||
# If this is disabled, Bedrock players will be skipped
|
||||
# Следует ли Sonar также проверять игроков Geyser (Bedrock)?
|
||||
# Эта функция экспериментальна и может вызывать проблемы
|
||||
# Если это отключено, игроки Bedrock будут пропущены
|
||||
check-geyser-players: true
|
||||
# Количество времени, которое должно пройти, прежде чем игрока кикнет.
|
||||
# (Это значение представляет время в миллисекундах: 1 секунда = 1000 миллисекунд)
|
||||
|
||||
@@ -103,36 +103,47 @@ verification:
|
||||
# - NEVER: 永远不应用该检查
|
||||
timing: NEVER
|
||||
# 图像效果选项 (用于混淆自动图像识别)
|
||||
# You should only edit this if you know what you're doing
|
||||
effects:
|
||||
# 是否添加局部发光效果
|
||||
flare: true
|
||||
# 是否添加随机的线条
|
||||
# Adds random lines to the image
|
||||
scratches: true
|
||||
# 是否应用波纹失真效果
|
||||
# Applies a ripple filter (wavy effect)
|
||||
ripple: true
|
||||
# 是否应用纵向畸变滤镜
|
||||
smear: true
|
||||
# 是否添加一些失真
|
||||
pinch: true
|
||||
# 图像的色彩饱和度
|
||||
saturation: 0.15
|
||||
# 水平三角形纹波滤镜
|
||||
distortion: 2
|
||||
# Applies a bump filter (sharpened text)
|
||||
bump: true
|
||||
# Distortion filter
|
||||
distortion:
|
||||
# Should Sonar apply a distortion filter?
|
||||
enabled: true
|
||||
# What shape should Sonar use for the distortion filter?
|
||||
# Possible types: 0, 1, 2, 3
|
||||
# - 0: Crosses
|
||||
# - 1: Lines
|
||||
# - 2: Circles
|
||||
# - 3: Squares
|
||||
shape: 2
|
||||
# Distance between distorted pixels/objects
|
||||
distance: 5
|
||||
# Density of the distorted pixels/objects
|
||||
density: 0.1
|
||||
# Amount of blending between the colors of objects
|
||||
mix: 0.15
|
||||
# Path to the background image Sonar uses for the CAPTCHA
|
||||
# If the image isn't found, a noise will be used as the default background
|
||||
background: ''
|
||||
# Should Sonar automatically detect the background color?
|
||||
# This is done to create a contrast between the background image and the text
|
||||
# You can simply put the name of the file here if file is in the plugin directory
|
||||
auto-color: false
|
||||
# Sonar 应该一次准备多少个验证码?
|
||||
precompute: 500
|
||||
# Sonar 应该给玩家多少时间完成验证码? (该值为毫秒. 1秒等于1000毫秒.)
|
||||
max-duration: 45000
|
||||
max-duration: 30000
|
||||
# 玩家最多能输入多少次错误的验证码?
|
||||
max-tries: 3
|
||||
# 允许出现在验证码答案中的字符
|
||||
# 不建议添加可能看起来彼此相似的数字或字母
|
||||
dictionary: '1235689'
|
||||
# Sonar 应该为验证码使用哪些字体?
|
||||
font-names:
|
||||
- Dialog
|
||||
- DialogInput
|
||||
- SansSerif
|
||||
- Monospaced
|
||||
|
||||
# 检查玩家是否正在向服务器发送有效的客户端标识符
|
||||
client-brand:
|
||||
|
||||
@@ -184,9 +184,6 @@ verification:
|
||||
captcha:
|
||||
# Nachricht, die dem Spieler angezeigt wird, wenn er den CAPTCHA-Code im Chat eingeben muss
|
||||
enter-code: '%prefix%<green>Bitte gib den Code im Chat ein, der auf der Karte angezeigt wird.'
|
||||
# Timer, der dem Spieler angezeigt wird, wenn er den CAPTCHA-Code im Chat eingeben muss
|
||||
# (Setze dies auf '' um die Aktionsleisten-Nachricht zu deaktivieren)
|
||||
action-bar: '%prefix%<green>Du hast %time-left% Sekunden Zeit, um den Code im Chat einzugeben'
|
||||
# Nachricht, die dem Spieler angezeigt wird, wenn er den falschen Code im Chat eingibt
|
||||
incorrect: '%prefix%<red>Du hast den falschen Code eingegeben. Bitte versuche es erneut.'
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ header:
|
||||
# Placeholder for every '%footer%' in this configuration file
|
||||
footer:
|
||||
- <gray>If you believe that this is an error, contact an administrator.
|
||||
# Disconnect message that is shown when someone joins but there are too many online players with their IP address
|
||||
# Disconnect message that is shown when someone joins, but there are too many online players with their IP address
|
||||
too-many-online-per-ip:
|
||||
- '%header%'
|
||||
- <red>There are too many players online with your IP address.
|
||||
@@ -32,21 +32,21 @@ too-many-online-per-ip:
|
||||
|
||||
# Translations for commands
|
||||
commands:
|
||||
# Message that is shown when a player tries running /sonar without permission
|
||||
# Message shown when a player tries running /sonar without permission
|
||||
no-permission: '%prefix%<red>You do not have permission to execute this command.'
|
||||
# Message that is shown when someone uses a command incorrectly
|
||||
# Message shown when someone uses a command incorrectly
|
||||
incorrect-usage: '%prefix%<red>Usage: /sonar %usage%'
|
||||
# Message that is shown when someone provides an invalid IP address (Invalid format)
|
||||
# Message shown when someone provides an invalid IP address (Invalid format)
|
||||
invalid-ip-address: '%prefix%The IP address you provided seems to be invalid.'
|
||||
# Message that is shown when the console runs a command that is player-only
|
||||
# Message shown when the console runs a command that is player-only
|
||||
player-only: '%prefix%<red>You can only execute this command as a player.'
|
||||
# Message that is shown when a player runs a command that is console-only
|
||||
# Message shown when a player runs a command that is console-only
|
||||
console-only: '%prefix%<red>For security reasons, you can only execute this command
|
||||
through console.'
|
||||
# Message that is shown when a player executes Sonar commands too quickly
|
||||
# Message shown when a player executes Sonar commands too quickly
|
||||
cool-down: '%prefix%<red>You can only execute this command every 0.5 seconds.'
|
||||
cool-down-left: '%prefix%<red>Please wait another <bold>%time-left%s<reset><red>.'
|
||||
# Message that is shown when a player does not have permission to execute a certain subcommand
|
||||
# Message shown when a player does not have permission to execute a certain subcommand
|
||||
subcommand-no-permission: '%prefix%<red>You do not have permission to execute this
|
||||
subcommand. <gray>(%permission%)'
|
||||
|
||||
@@ -71,73 +71,73 @@ commands:
|
||||
|
||||
# Translations for '/sonar reload'
|
||||
reload:
|
||||
# Message that is shown when someone starts reloading Sonar
|
||||
# Message shown when someone starts reloading Sonar
|
||||
start: '%prefix%Reloading Sonar...'
|
||||
# Message that is shown when Sonar has finished reloading
|
||||
# Message shown when Sonar has finished reloading
|
||||
finish: '%prefix%<green>Successfully reloaded <gray>(%taken%ms)'
|
||||
|
||||
# Translations for '/sonar verbose'
|
||||
verbose:
|
||||
# Message that is shown when a player subscribes to Sonar verbose
|
||||
# Message shown when a player subscribes to Sonar verbose
|
||||
subscribed: '%prefix%You are now viewing Sonar verbose.'
|
||||
# Message that is shown when a player unsubscribes from Sonar verbose
|
||||
# Message shown when a player unsubscribes from Sonar verbose
|
||||
unsubscribed: '%prefix%You are no longer viewing Sonar verbose.'
|
||||
|
||||
# Translations for '/sonar notify'
|
||||
notify:
|
||||
# Message that is shown when a player subscribes to Sonar attack notifications
|
||||
# Message shown when a player subscribes to Sonar attack notifications
|
||||
subscribed: '%prefix%You are now viewing Sonar attack notifications.'
|
||||
# Message that is shown when a player unsubscribes from Sonar attack notifications
|
||||
# Message shown when a player unsubscribes from Sonar attack notifications
|
||||
unsubscribed: '%prefix%You are no longer viewing Sonar attack notifications.'
|
||||
|
||||
# Translations for '/sonar blacklist'
|
||||
blacklist:
|
||||
# Message that is shown when someone tries clearing the blacklist but is is empty
|
||||
# Message shown when someone tries clearing the blacklist but is empty
|
||||
empty: '%prefix%The blacklist is currently empty. Therefore, no IP addresses were
|
||||
removed from the blacklist.'
|
||||
# Message that is shown when someone clears the blacklist
|
||||
# Message shown when someone clears the blacklist
|
||||
cleared: '%prefix%You successfully removed a total of %removed% IP address(es)
|
||||
from the blacklist.'
|
||||
# Message that is shown when someone checks the size of the blacklist
|
||||
# Message shown when someone checks the size of the blacklist
|
||||
size: '%prefix%The blacklist currently contains %amount% IP address(es).'
|
||||
# Message that is shown when someone adds an IP address to the blacklist
|
||||
# Message shown when someone adds an IP address to the blacklist
|
||||
added: '%prefix%Successfully added %ip% to the blacklist.'
|
||||
# Message that is shown when someone adds an IP address to the blacklist that is verified
|
||||
# Message shown when someone adds an IP address to the blacklist that is verified
|
||||
added-warning: '%prefix%<red>Warning: <white>%ip% is currently whitelisted. Consider
|
||||
removing the IP address from the list of verified players to avoid potential
|
||||
issues.'
|
||||
# Message that is shown when someone removes an IP address from the blacklist
|
||||
# Message shown when someone removes an IP address from the blacklist
|
||||
removed: '%prefix%Successfully removed %ip% from the blacklist.'
|
||||
# Message that is shown when someone adds an IP address to the blacklist, but it is already blacklisted
|
||||
# Message shown when someone adds an IP address to the blacklist, but it is already blacklisted
|
||||
duplicate-ip: '%prefix%The IP address you provided is already blacklisted.'
|
||||
# Message that is shown when someone removes an IP address from the blacklist, but it is not blacklisted
|
||||
# Message shown when someone removes an IP address from the blacklist, but it is not blacklisted
|
||||
ip-not-found: '%prefix%The IP address you provided is not blacklisted.'
|
||||
|
||||
# Translations for '/sonar verified'
|
||||
verified:
|
||||
# Message that is shown when someone tries clearing the list of verified players but is empty
|
||||
# Message shown when someone tries clearing the list of verified players but is empty
|
||||
empty: '%prefix%The list of verified players is currently empty. Therefore, no
|
||||
players were unverified.'
|
||||
# Message that is shown when someone clears the list of verified players
|
||||
# Message shown when someone clears the list of verified players
|
||||
cleared: '%prefix%You successfully unverified a total of %removed% unique player(s).'
|
||||
# Message that is shown when someone checks the size of the list of verified players
|
||||
# Message shown when someone checks the size of the list of verified players
|
||||
size: '%prefix%There are currently %amount% unique player(s) verified.'
|
||||
# Message that is shown when someone un-verifies an IP address
|
||||
# Message shown when someone un-verifies an IP address
|
||||
removed: '%prefix%Successfully unverified %ip%.'
|
||||
# Message that is shown when someone verifies an IP address
|
||||
# Message shown when someone verifies an IP address
|
||||
added: '%prefix%Successfully verified %ip%.'
|
||||
# Message that is shown when someone tries to verify an IP address/UUID that are already verified
|
||||
# Message shown when someone tries to verify an IP address/UUID that are already verified
|
||||
already: '%prefix%The IP address and UUID you provided are already verified.'
|
||||
# Message that is shown when someone un-verifies an IP address, but it is not verified
|
||||
# Message shown when someone un-verifies an IP address, but it is not verified
|
||||
ip-not-found: '%prefix%The IP address you provided is not verified.'
|
||||
# Message that is shown when someone tries un-verifying the same IP address twice (double operation)
|
||||
# Message shown when someone tries un-verifying the same IP address twice (double operation)
|
||||
blocked: '%prefix%Please wait for the current operation to finish.'
|
||||
|
||||
# Translations for '/sonar statistics'
|
||||
statistics:
|
||||
# Informational message that is shown above everything when viewing the statistics
|
||||
header: '%prefix%Showing %type% statistics for this session:'
|
||||
# Message that is shown when a player tries viewing an unknown statistic
|
||||
# Message shown when a player tries viewing an unknown statistic
|
||||
unknown-type: '%prefix%<red>Unknown statistics type! Available statistics: <gray>%statistics%'
|
||||
# Format of the general statistics message
|
||||
general:
|
||||
@@ -174,25 +174,21 @@ commands:
|
||||
verification:
|
||||
# Translations for all debug messages during the verification
|
||||
logs:
|
||||
# Message that is logged to console whenever a new player joins the server
|
||||
# Message logged to console whenever a new player joins the server
|
||||
connection: '%name%%ip% (%protocol%) has connected.'
|
||||
# Message that is logged to console whenever a player fails verification
|
||||
# Message logged to console whenever a player fails verification
|
||||
failed: '%ip% (%protocol%) has failed the bot check for: %reason%'
|
||||
# Message that is logged to console whenever a player is blacklisted
|
||||
# Message logged to console whenever a player is blacklisted
|
||||
blacklisted: '%ip% (%protocol%) was blacklisted for too many failed attempts'
|
||||
# Message that is logged to console whenever a player is verified
|
||||
# Message logged to console whenever a player is verified
|
||||
successful: '%name% has been verified successfully (%time%s!).'
|
||||
|
||||
# Messages that are shown to the player when they are supposed to enter the CAPTCHA
|
||||
captcha:
|
||||
# Message that is shown to the player when they have to enter the answer to the captcha
|
||||
# Message shown to the player when they have to enter the answer to the captcha
|
||||
enter-code: '%prefix%<green>Please enter the code in chat that is displayed on
|
||||
the map.'
|
||||
# Timer that is shown to the player when they have to enter the answer to the captcha
|
||||
# (Set this to '' to disable the action bar message)
|
||||
action-bar: '%prefix%<green>You have %time-left% seconds left to enter the code
|
||||
in chat'
|
||||
# Message that is shown to the player when they enter the wrong answer in chat
|
||||
# Message shown to the player when they enter the wrong answer in chat
|
||||
incorrect: '%prefix%<red>You have entered the wrong code. Please try again.'
|
||||
|
||||
# Disconnect message that is shown when someone joins while the captcha hasn't been prepared yet
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
#
|
||||
# /$$$$$$
|
||||
# /$$__ $$
|
||||
# | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$
|
||||
# | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$
|
||||
# \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/
|
||||
# /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$
|
||||
# | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$
|
||||
# \______/ \______/ |__/ |__/ \_______/|__/
|
||||
#
|
||||
# Besoin d'aide ou d'autres questions ? https://jonesdev.xyz/discord
|
||||
# Code source : https://github.com/jonesdevelopment/sonar
|
||||
# Droit d'auteur Jones Development, un contributeur Sonar, licence sous GPL-3.0
|
||||
#
|
||||
|
||||
# Espace réservé pour tout '%prefix%' dans ce fichier de configuration
|
||||
prefix: <b><yellow>Sonar</b> <gray>» <white>
|
||||
# Espace réservé pour tout '%support-url%' dans ce fichier de configuration
|
||||
support-url: https://jonesdev.xyz/discord/
|
||||
# Espace réservé pour tout '%header%' dans ce fichier de configuration
|
||||
header:
|
||||
- <b><yellow>Sonar</b><reset>
|
||||
- ''
|
||||
# Espace réservé pour tout '%footer%' dans ce fichier de configuration
|
||||
footer:
|
||||
- <gray>Si vous pensez que c'est une erreur, veuillez contacter un administrateur.
|
||||
# Message de déconnexion affiché lorsqu'un joueur se connecte mais qu'il y a trop de joueurs en ligne avec leur adresse IP
|
||||
too-many-online-per-ip:
|
||||
- '%header%'
|
||||
- <red>Il y a trop de joueurs en ligne avec votre adresse IP.
|
||||
- '%footer%'
|
||||
|
||||
# Traductions pour les commandes
|
||||
commands:
|
||||
# Message affiché lorsqu'un joueur tente d'exécuter /sonar sans permission
|
||||
no-permission: "%prefix%<red>Vous n'avez pas la permission d'exécuter cette commande."
|
||||
# Message affiché lorsqu'une commande est utilisée de manière incorrecte
|
||||
incorrect-usage: '%prefix%<red>Utilisation : /sonar %usage%'
|
||||
# Message affiché lorsqu'une adresse IP invalide est fournie (format invalide)
|
||||
invalid-ip-address: "%prefix%L'adresse IP que vous avez fournie semble invalide."
|
||||
# Message affiché lorsque la console exécute une commande qui est uniquement pour les joueurs
|
||||
player-only: "%prefix%<red>Vous ne pouvez exécuter cette commande qu'en tant que joueur."
|
||||
# Message affiché lorsqu'un joueur exécute une commande qui est uniquement pour la console
|
||||
console-only: '%prefix%<red>Pour des raisons de sécurité, vous ne pouvez exécuter cette commande que via la console.'
|
||||
# Message affiché lorsqu'un joueur exécute trop rapidement les commandes Sonar
|
||||
cool-down: "%prefix%<red>Vous ne pouvez exécuter cette commande qu'une fois toutes les 0,5 secondes."
|
||||
cool-down-left: '%prefix%<red>Veuillez attendre encore <bold>%time-left%<reset><red>.'
|
||||
# Message affiché lorsqu'un joueur n'a pas la permission d'exécuter une certaine sous-commande
|
||||
subcommand-no-permission: "%prefix%<red>Vous n'avez pas la permission d'exécuter cette sous-commande. <gray>(%permission%)"
|
||||
|
||||
# Traductions pour '/sonar'
|
||||
main:
|
||||
# Message informatif affiché au-dessus de tout lors de l'exécution de la commande principale
|
||||
header:
|
||||
- <yellow>Exécution de <b>Sonar</b> %version% sur %platform%.
|
||||
- <gray><click:open_url:'https://github.com/jonesdevelopment/sonar'>(C) %copyright_year%
|
||||
Jones Development et les contributeurs de Sonar</click>
|
||||
- ''
|
||||
- <gray>Besoin d'aide ou avez-vous des questions ?
|
||||
- <white><click:open_url:'https://jonesdev.xyz/discord/'><hover:show_text:'(Cliquez
|
||||
pour ouvrir Discord)'>Ouvrez un ticket sur Discord </hover></click><click:open_url:'https://github.com/jonesdevelopment/sonar/issues'><hover:show_text:'(Cliquez
|
||||
pour ouvrir GitHub)'>ou ouvrez un nouveau problème sur GitHub.
|
||||
- ''
|
||||
# Format de la liste des sous-commandes affichée lors de l'exécution de la commande principale
|
||||
subcommands: '<click:suggest_command:''/sonar %subcommand% ''><hover:show_text:''<gray>Seulement pour les joueurs : </gray>%only_players%<br><gray>Nécessite la console : </gray>%require_console%<br><gray>Permission : </gray><white>%permission%<br><gray>Alias : </gray>%aliases%''><dark_aqua> ▪ <gray>/sonar %subcommand% <white>%description%'
|
||||
|
||||
# Traductions pour '/sonar reload'
|
||||
reload:
|
||||
# Message affiché lorsque quelqu'un commence à recharger Sonar
|
||||
start: '%prefix%Rechargement de Sonar...'
|
||||
# Message affiché lorsque Sonar a fini de recharger
|
||||
finish: '%prefix%<green>Rechargement réussi <gray>(%taken%ms)'
|
||||
|
||||
# Traductions pour '/sonar verbose'
|
||||
verbose:
|
||||
# Message affiché lorsqu'un joueur s'abonne aux détails verbeux de Sonar
|
||||
subscribed: '%prefix%Vous visualisez maintenant les détails verbeux de Sonar.'
|
||||
# Message affiché lorsqu'un joueur se désabonne des détails verbeux de Sonar
|
||||
unsubscribed: '%prefix%Vous ne visualisez plus les détails verbeux de Sonar.'
|
||||
|
||||
# Traductions pour '/sonar notify'
|
||||
notify:
|
||||
# Message affiché lorsqu'un joueur s'abonne aux notifications d'attaque de Sonar
|
||||
subscribed: "%prefix%Vous visualisez maintenant les notifications d'attaque de Sonar."
|
||||
# Message affiché lorsqu'un joueur se désabonne des notifications d'attaque de Sonar
|
||||
unsubscribed: "%prefix%Vous ne visualisez plus les notifications d'attaque de Sonar."
|
||||
|
||||
# Traductions pour '/sonar blacklist'
|
||||
blacklist:
|
||||
# Message affiché lorsque quelqu'un tente de vider la liste noire mais qu'elle est vide
|
||||
empty: "%prefix%La liste noire est actuellement vide. Par conséquent, aucune adresse IP n'a été supprimée de la liste noire."
|
||||
# Message affiché lorsque quelqu'un vide la liste noire
|
||||
cleared: '%prefix%Vous avez réussi à supprimer un total de %removed% adresse(s) IP de la liste noire.'
|
||||
# Message affiché lorsque quelqu'un vérifie la taille de la liste noire
|
||||
size: '%prefix%La liste noire contient actuellement %amount% adresse(s) IP.'
|
||||
# Message affiché lorsque quelqu'un ajoute une adresse IP à la liste noire
|
||||
added: '%prefix%Adresse IP %ip% ajoutée avec succès à la liste noire.'
|
||||
# Message affiché lorsque quelqu'un ajoute une adresse IP à la liste noire qui est vérifiée
|
||||
added-warning: "%prefix%<red>Avertissement : <white>%ip% est actuellement sur liste blanche. Considérez la suppression de l'adresse IP de la liste des joueurs vérifiés pour éviter des problèmes potentiels."
|
||||
# Message affiché lorsque quelqu'un supprime une adresse IP de la liste noire
|
||||
removed: '%prefix%Adresse IP %ip% supprimée avec succès de la liste noire.'
|
||||
# Message affiché lorsque quelqu'un ajoute une adresse IP à la liste noire, mais qu'elle est déjà en liste noire
|
||||
duplicate-ip: "%prefix%L'adresse IP que vous avez fournie est déjà sur la liste noire."
|
||||
# Message affiché lorsque quelqu'un supprime une adresse IP de la liste noire, mais qu'elle n'est pas en liste noire
|
||||
ip-not-found: "%prefix%L'adresse IP que vous avez fournie ne figure pas sur la liste noire."
|
||||
|
||||
# Traductions pour '/sonar verified'
|
||||
verified:
|
||||
# Message affiché lorsque quelqu'un tente de vider la liste des joueurs vérifiés mais qu'elle est vide
|
||||
empty: "%prefix%La liste des joueurs vérifiés est actuellement vide. Par conséquent, aucun joueur n'a été désapprouvé."
|
||||
# Message affiché lorsque quelqu'un vide la liste des joueurs vérifiés
|
||||
cleared: '%prefix%Vous avez réussi à désapprouver un total de %removed% joueur(s) unique(s).'
|
||||
# Message affiché lorsque quelqu'un vérifie la taille de la liste des joueurs vérifiés
|
||||
size: '%prefix%Il y a actuellement %amount% joueur(s) unique(s) vérifié(s).'
|
||||
# Message affiché lorsque quelqu'un désapprouve une adresse IP
|
||||
removed: '%prefix%Adresse IP %ip% désapprouvée avec succès.'
|
||||
# Message affiché lorsque quelqu'un vérifie une adresse IP
|
||||
added: '%prefix%Adresse IP %ip% vérifiée avec succès.'
|
||||
# Message affiché lorsque quelqu'un tente de vérifier une adresse IP/UUID qui est déjà vérifiée
|
||||
already: "%prefix%L'adresse IP et l'UUID que vous avez fournis sont déjà vérifiés."
|
||||
# Message affiché lorsque quelqu'un désapprouve une adresse IP, mais qu'elle n'est pas vérifiée
|
||||
ip-not-found: "%prefix%L'adresse IP que vous avez fournie n'est pas vérifiée."
|
||||
# Message affiché lorsque quelqu'un tente de désapprouver la même adresse IP deux fois (double opération)
|
||||
blocked: "%prefix%Veuillez attendre la fin de l'opération en cours."
|
||||
|
||||
# Traductions pour '/sonar statistics'
|
||||
statistics:
|
||||
# Message informatif affiché au-dessus de tout lors de la visualisation des statistiques
|
||||
header: '%prefix%Affichage des statistiques %type% pour cette session :'
|
||||
# Message affiché lorsqu'un joueur tente de visualiser une statistique inconnue
|
||||
unknown-type: '%prefix%<red>Type de statistiques inconnu ! Statistiques disponibles : <gray>%statistics%'
|
||||
# Format du message de statistiques général
|
||||
general:
|
||||
- ' <dark_aqua>▪ <gray>Adresses IP vérifiées : <white>%verified%'
|
||||
- ' <dark_aqua>▪ <gray>En train de vérifier les adresses IP : <white>%verifying%'
|
||||
- ' <dark_aqua>▪ <gray>Adresses IP en liste noire : <white>%blacklisted%'
|
||||
- ' <dark_aqua>▪ <gray>Connexions en attente actuelles : <white>%queued%'
|
||||
- ' <dark_aqua>▪ <gray>Total des connexions non uniques : <white>%total_joins%'
|
||||
- ' <dark_aqua>▪ <gray>Total des tentatives de vérification : <white>%total_attempts%'
|
||||
- ' <dark_aqua>▪ <gray>Total des vérifications échouées : <white>%total_failed%'
|
||||
- ' <dark_aqua>▪ <gray>Temps de fonctionnement du serveur : <white>%uptime%'
|
||||
# Format du message de statistiques CPU
|
||||
cpu:
|
||||
- ' <dark_aqua>▪ <gray>Utilisation actuelle du CPU du processus : <white>%process_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>Utilisation actuelle du CPU du système : <white>%system_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>Utilisation du CPU par cœur du processus : <white>%average_process_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>Utilisation du CPU par cœur du système : <white>%average_system_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>Charge système générale : <white>%load_average%%'
|
||||
- ' <dark_aqua>▪ <gray>Nombre total de processeurs virtuels : <white>%virtual_cores%'
|
||||
# Format du message de statistiques de mémoire
|
||||
memory:
|
||||
- ' <dark_aqua>▪ <gray>Mémoire libre totale : <white>%free_memory%'
|
||||
- ' <dark_aqua>▪ <gray>Mémoire utilisée totale : <white>%used_memory%'
|
||||
- ' <dark_aqua>▪ <gray>Mémoire maximale totale : <white>%max_memory%'
|
||||
- ' <dark_aqua>▪ <gray>Mémoire allouée totale : <white>%total_memory%'
|
||||
# Format du message de statistiques réseau
|
||||
network:
|
||||
- ' <dark_aqua>▪ <gray>Bande passante entrante actuelle utilisée : <white>%incoming%'
|
||||
- ' <dark_aqua>▪ <gray>Bande passante sortante actuelle utilisée : <white>%outgoing%'
|
||||
- ' <dark_aqua>▪ <gray>Bande passante entrante totale utilisée : <white>%ttl_incoming%'
|
||||
- ' <dark_aqua>▪ <gray>Bande passante sortante totale utilisée : <white>%ttl_outgoing%'
|
||||
|
||||
# Traductions pour tous les messages pendant le processus de vérification
|
||||
verification:
|
||||
# Traductions pour tous les messages de débogage pendant la vérification
|
||||
logs:
|
||||
# Message enregistré dans la console chaque fois qu'un nouveau joueur rejoint le serveur
|
||||
connection: "%name%%ip% (%protocol%) s'est connecté."
|
||||
# Message enregistré dans la console chaque fois qu'un joueur échoue à la vérification
|
||||
failed: '%ip% (%protocol%) a échoué au test du bot pour : %reason%'
|
||||
# Message enregistré dans la console chaque fois qu'un joueur est sur liste noire
|
||||
blacklisted: '%ip% (%protocol%) a été mis sur liste noire pour trop de tentatives échouées'
|
||||
# Message enregistré dans la console chaque fois qu'un joueur est vérifié
|
||||
successful: '%name% a été vérifié avec succès (%time%s !).'
|
||||
|
||||
# Messages affichés au joueur lorsqu'il doit entrer le CAPTCHA
|
||||
captcha:
|
||||
# Message affiché au joueur lorsqu'il doit entrer la réponse au CAPTCHA
|
||||
enter-code: '%prefix%<green>Veuillez entrer le code affiché sur la carte.'
|
||||
# Message affiché au joueur lorsqu'il entre la mauvaise réponse dans le chat
|
||||
incorrect: '%prefix%<red>Vous avez entré le mauvais code. Veuillez réessayer.'
|
||||
|
||||
# Message de déconnexion affiché lorsque quelqu'un rejoint alors que le CAPTCHA n'a pas été préparé
|
||||
currently-preparing:
|
||||
- '%header%'
|
||||
- <yellow>Vos données anti-bot n'ont pas encore été préparées.
|
||||
- <gray>Veuillez patienter quelques secondes avant d'essayer de vous vérifier à nouveau.
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un se reconnecte trop rapidement pendant la vérification
|
||||
too-fast-reconnect:
|
||||
- '%header%'
|
||||
- <gold>Vous avez rejoint trop rapidement, réessayez plus tard.
|
||||
- <gray>Veuillez patienter quelques secondes avant d'essayer de vous vérifier à nouveau.
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un rejoint mais est déjà en vérification
|
||||
already-verifying:
|
||||
- '%header%'
|
||||
- <red>Votre adresse IP est actuellement en cours de vérification.
|
||||
- <red>Veuillez patienter quelques secondes avant d'essayer de vous vérifier à nouveau.
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un rejoint mais est déjà en attente de vérification
|
||||
already-queued:
|
||||
- '%header%'
|
||||
- <red>Votre adresse IP est actuellement en attente de vérification.
|
||||
- <red>Veuillez patienter quelques minutes avant d'essayer de vous vérifier à nouveau.
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un rejoint mais est temporairement mis sur liste noire
|
||||
blacklisted:
|
||||
- '%header%'
|
||||
- <red>Vous êtes actuellement interdit d'entrer sur le serveur.
|
||||
- <red>Veuillez patienter quelques minutes pour pouvoir rejoindre le serveur à nouveau.
|
||||
- <gold>Erreur ? <gray>%support-url%
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un rejoint avec un nom d'utilisateur non valide
|
||||
invalid-username:
|
||||
- '%header%'
|
||||
- <red>Votre nom d'utilisateur contient des caractères non valides.
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un rejoint avec une version sur liste noire
|
||||
blacklisted-protocol:
|
||||
- '%header%'
|
||||
- <red>Vous utilisez une version non autorisée sur notre serveur.
|
||||
- <gold>Besoin d'aide pour vous connecter ? <gray>%support-url%
|
||||
- '%footer%'
|
||||
# Message de déconnexion affiché lorsque quelqu'un réussit la vérification
|
||||
success:
|
||||
- '%header%'
|
||||
- <green>Vous avez réussi la vérification.
|
||||
- <white>Vous pouvez maintenant jouer sur le serveur lorsque vous vous reconnectez.
|
||||
# Message de déconnexion affiché lorsque quelqu'un échoue à la vérification
|
||||
failed:
|
||||
- '%header%'
|
||||
- <red>Vous avez échoué à la vérification du bot.
|
||||
- <gray>Veuillez patienter quelques secondes avant d'essayer de vous vérifier à nouveau.
|
||||
- <gold>Besoin d'aide ? <gray>%support-url%
|
||||
- '%footer%'
|
||||
|
||||
# Translations for Sonar's actionbar verbose messages
|
||||
verbose:
|
||||
layout:
|
||||
# Mise en page pour le verbeux de la barre d'action de Sonar
|
||||
# Espacements réservés :
|
||||
# - '%queued%' Nombre de connexions en attente
|
||||
# - '%verifying%' Nombre de connexions en cours de vérification
|
||||
# - '%blacklisted%' Nombre d'adresses IP sur liste noire
|
||||
# - '%total-joins%' Nombre total de connexions tentées
|
||||
# - '%verify-total%' Nombre total de tentatives de vérification
|
||||
# - '%verify-success%' Nombre d'adresses IP vérifiées
|
||||
# - '%verify-failed%' Nombre de vérifications échouées
|
||||
# - '%logins-per-second%' Nombre de connexions par seconde
|
||||
# - '%connections-per-second%' Nombre de connexions par seconde
|
||||
# - '%attack-duration%' Durée de l'attaque actuelle
|
||||
# - '%incoming-traffic%' Utilisation de la bande passante entrante par seconde
|
||||
# - '%outgoing-traffic%' Utilisation de la bande passante sortante par seconde
|
||||
# - '%incoming-traffic-ttl%' Utilisation totale de la bande passante entrante
|
||||
# - '%outgoing-traffic-ttl%' Utilisation totale de la bande passante sortante
|
||||
# - '%used-memory%' Quantité de mémoire utilisée par le processus
|
||||
# - '%total-memory%' Quantité de mémoire totale du processus
|
||||
# - '%max-memory%' Quantité de mémoire maximale du processus
|
||||
# - '%free-memory%' Quantité de mémoire libre du processus
|
||||
# - '%animation%' Symbole animé personnalisable
|
||||
# Traductions pour la sortie verbeuse normale de Sonar
|
||||
normal: '%prefix%<gray>CPS <white>%connections-per-second% <dark_aqua>╺ <gray>Logins/s
|
||||
<white>%logins-per-second% <dark_aqua>╺ <gray>Vérification <white>%verifying% <dark_aqua>|
|
||||
<green>⬆ <white>%outgoing-traffic%/s <red>⬇ <white>%incoming-traffic%/s <green><bold>%animation%<reset>'
|
||||
# Traductions pour la sortie verbeuse lors d'une attaque
|
||||
attack: '%prefix%<gray>CPS <white>%connections-per-second% <dark_aqua>╺ <gray>Logins/s
|
||||
<white>%logins-per-second% <dark_aqua>╺ <gray>Queue <white>%queued% <dark_aqua>╺
|
||||
<gray>Vérification <white>%verifying% <dark_aqua>╺ <gray>Durée <white>%attack-duration%
|
||||
<dark_aqua>| <green>⬆ <white>%outgoing-traffic%/s <red>⬇ <white>%incoming-traffic%/s <green><bold>%animation%<reset>'
|
||||
# Animation pour la sortie verbeuse
|
||||
# Alternatives:
|
||||
# - ▙, ▛, ▜, ▟
|
||||
# - ⬈, ⬊, ⬋, ⬉
|
||||
animation:
|
||||
- ◜
|
||||
- ◝
|
||||
- ◞
|
||||
- ◟
|
||||
|
||||
# Traductions pour les messages affichés en cas d'attaque
|
||||
notifications:
|
||||
# Mise en page du titre de la notification d'attaque de Sonar
|
||||
title: <yellow><b>Sonar<reset>
|
||||
# Mise en page du sous-titre de la notification d'attaque de Sonar
|
||||
subtitle: <gray>A bot attack has been detected
|
||||
# Mise en page de la notification d'attaque de Sonar dans le chat
|
||||
chat:
|
||||
- ''
|
||||
- <yellow><b>Sonar<reset>
|
||||
- ''
|
||||
- <gray>Une attaque de bot a été détectée.
|
||||
- ' <dark_aqua>▪ <gray>Connexions par seconde: <white>%logins-per-second%'
|
||||
- ' <dark_aqua>▪ <gray>Vérification des joueurs: <white>%verifying%'
|
||||
- ' <dark_aqua>▪ <gray>Joueurs en file d''attente: <white>%queued%'
|
||||
- ''
|
||||
- <gray>View more information using <white><click:run_command:'/sonar verbose'><hover:show_text:'(Click
|
||||
to run)'>/sonar verbose</hover></click><gray> or <white><click:run_command:'/sonar
|
||||
stats'><hover:show_text:'(Click to run)'>/sonar stats</hover></click><gray>.
|
||||
- ''
|
||||
@@ -0,0 +1,311 @@
|
||||
#
|
||||
# /$$$$$$
|
||||
# /$$__ $$
|
||||
# | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$
|
||||
# | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$
|
||||
# \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/
|
||||
# /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$
|
||||
# | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$
|
||||
# \______/ \______/ |__/ |__/ \_______/|__/
|
||||
#
|
||||
# Hulp nodig of vragen? https://jonesdev.xyz/discord
|
||||
# Broncode: https://github.com/jonesdevelopment/sonar
|
||||
# Copyright Jones Development and Sonar Contributors, licensed under GPL-3.0
|
||||
#
|
||||
|
||||
# Tijdelijke aanduiding voor elke '%prefix%' in dit configuratiebestand
|
||||
prefix: <b><yellow>Sonar</b> <gray>» <white>
|
||||
# Tijdelijke aanduiding voor elke '%support-url%' in dit configuratiebestand
|
||||
support-url: https://jonesdev.xyz/discord/
|
||||
# Tijdelijke aanduiding voor elke '%header%' in dit configuratiebestand
|
||||
header:
|
||||
- <b><yellow>Sonar</b><reset>
|
||||
- ''
|
||||
# Tijdelijke aanduiding voor elke '%footer%' in dit configuratiebestand
|
||||
footer:
|
||||
- <gray>Als u denkt dat dit een fout is, neem dan contact op met een beheerder.
|
||||
# Verbindingsbericht dat wordt weergegeven als iemand zich aansluit, maar er zijn te veel online spelers met hun IP-adres
|
||||
too-many-online-per-ip:
|
||||
- '%header%'
|
||||
- <red>Er zijn te veel spelers online met uw IP-adres.
|
||||
- '%footer%'
|
||||
|
||||
# Vertalingen voor commandos
|
||||
commands:
|
||||
# Bericht dat wordt weergegeven wanneer een speler zonder toestemming /sonar probeert uit te voeren
|
||||
no-permission: '%prefix%<red>U heeft geen toestemming om deze opdracht uit te voeren.'
|
||||
# Bericht dat verschijnt wanneer iemand een commando verkeerd gebruikt
|
||||
incorrect-usage: '%prefix%<red>Gebruik: /sonar %usage%'
|
||||
# Bericht dat wordt weergegeven wanneer iemand een ongeldig IP-adres opgeeft (ongeldig formaat)
|
||||
invalid-ip-address: '%prefix%Het door u opgegeven IP-adres lijkt ongeldig te zijn.'
|
||||
# Bericht dat wordt weergegeven wanneer de console een opdracht uitvoert die alleen voor spelers is
|
||||
player-only: '%prefix%<red>Je kunt dit commando alleen als speler uitvoeren.'
|
||||
# Bericht dat wordt weergegeven wanneer een speler een opdracht uitvoert die alleen voor de console geldt
|
||||
console-only: '%prefix%<red>Om veiligheidsredenen kunt u deze opdracht alleen uitvoeren
|
||||
via console.'
|
||||
# Bericht dat wordt weergegeven wanneer een speler Sonar-opdrachten te snel uitvoert
|
||||
cool-down: '%prefix%<red>U kunt dit commando slechts elke 0,5 seconde uitvoeren.'
|
||||
cool-down-left: '%prefix%<red>Wacht nog <bold>%time-left%s<reset><red>.'
|
||||
# Bericht dat wordt getoond wanneer een speler geen toestemming heeft om een bepaald subcommand uit te voeren
|
||||
subcommand-no-permission: '%prefix%<red>U heeft geen toestemming om dit uit te voeren
|
||||
subcommand. <gray>(%permission%)'
|
||||
|
||||
# Vertalingen voor '/sonar'
|
||||
main:
|
||||
# Informatief bericht dat boven alles wordt weergegeven bij het uitvoeren van de hoofdopdracht
|
||||
header:
|
||||
- <yellow><b>Sonar</b> %version% draaien op %platform%.
|
||||
- <gray><click:open_url:'https://github.com/jonesdevelopment/sonar'>(C) %copyright_year%
|
||||
Jones Development and Sonar Contributors</click>
|
||||
- ''
|
||||
- <gray>Hulp nodig of vragen?
|
||||
- <white><click:open_url:'https://jonesdev.xyz/discord/'><hover:show_text:'(Klik
|
||||
om Discord te openen)'>Open een ticket op de Discord </hover></click><click:open_url:'https://github.com/jonesdevelopment/sonar/issues'><hover:show_text:'(Klik
|
||||
om GitHub te openen)'>of open een nieuw probleem op GitHub.
|
||||
- ''
|
||||
# Opmaak van de lijst met subcommand die wordt weergegeven bij het uitvoeren van de hoofdopdracht
|
||||
subcommands: '<click:suggest_command:''/sonar %subcommand% ''><hover:show_text:''<gray>Alleen
|
||||
spelers: </gray>%only_players%<br><gray>Vereist console: </gray>%require_console%<br><gray>Toestemming:
|
||||
</gray><white>%permission%<br><gray>Aliassen: </gray>%aliases%''><dark_aqua>
|
||||
▪ <gray>/sonar %subcommand% <white>%description%'
|
||||
|
||||
# Vertalingen voor '/sonar reload'
|
||||
reload:
|
||||
# Bericht dat wordt weergegeven wanneer iemand Sonar begint te herladen
|
||||
start: '%prefix%Sonar opnieuw laden...'
|
||||
# Bericht dat wordt weergegeven wanneer Sonar klaar is met herladen
|
||||
finish: '%prefix%<green>Opnieuw geladen <gray>(%taken%ms)'
|
||||
|
||||
# Vertalingen voor '/sonar verbose'
|
||||
verbose:
|
||||
# Bericht dat wordt weergegeven wanneer een speler zich abonneert op Sonar uitgebreid
|
||||
subscribed: '%prefix%U bekijkt nu Sonar uitgebreid.'
|
||||
# Bericht dat wordt weergegeven wanneer een speler zich afmeldt voor Sonar uitgebreid
|
||||
unsubscribed: '%prefix%Je bekijkt Sonar niet langer uitgebreid.'
|
||||
|
||||
# Vertalingen voor '/sonar notify'
|
||||
notify:
|
||||
# Bericht dat wordt weergegeven wanneer een speler zich abonneert op Sonar aanval meldingen
|
||||
subscribed: '%prefix%U bekijkt nu Sonar aanval meldingen.'
|
||||
# Bericht dat wordt weergegeven wanneer een speler zich afmeldt voor Sonar aanval meldingen
|
||||
unsubscribed: '%prefix%Je bekijkt Sonar niet langer Sonar aanval meldingen.'
|
||||
|
||||
# Vertalingen voor '/sonar blacklist'
|
||||
blacklist:
|
||||
# Bericht dat wordt weergegeven wanneer iemand de zwarte lijst probeert te wissen, maar deze leeg is
|
||||
empty: '%prefix%De zwarte lijst is momenteel leeg. Daarom waren er geen IP-adressen
|
||||
verwijderd van de zwarte lijst.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand de zwarte lijst wist
|
||||
cleared: '%prefix%Je hebt in totaal %removed% IP-adres(sen) met succes verwijderd
|
||||
van de zwarte lijst.'
|
||||
# Bericht dat wordt getoond wanneer iemand de omvang van de zwarte lijst controleert
|
||||
size: '%prefix%De zwarte lijst bevat momenteel %amount% IP-adres(sen).'
|
||||
# Bericht dat wordt getoond wanneer iemand een IP-adres aan de zwarte lijst toevoegt
|
||||
added: '%prefix%%ip% is succesvol toegevoegd aan de zwarte lijst.'
|
||||
# Bericht dat wordt getoond wanneer iemand een IP-adres toevoegt aan de zwarte lijst die is geverifieerd
|
||||
added-warning: '%prefix%<red>Attentie: <white>%ip% staat momenteel op de witte lijst. Overwegen
|
||||
het verwijderen van het IP-adres uit de lijst met geverifieerde spelers om potentieel te voorkomen
|
||||
problemen.'
|
||||
# Bericht dat verschijnt wanneer iemand een IP-adres van de zwarte lijst verwijdert
|
||||
removed: '%prefix%%ip% is met succes verwijderd van de zwarte lijst.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand een IP-adres aan de zwarte lijst toevoegt, maar dit al op de zwarte lijst staat
|
||||
duplicate-ip: '%prefix%Het door u opgegeven IP-adres staat al op de zwarte lijst.'
|
||||
# Bericht dat verschijnt wanneer iemand een IP-adres van de zwarte lijst verwijdert, maar dit niet op de zwarte lijst staat
|
||||
ip-not-found: '%prefix%Het door u opgegeven IP-adres staat niet op de zwarte lijst.'
|
||||
|
||||
# Vertalingen voor '/sonar verified'
|
||||
verified:
|
||||
# Bericht dat wordt weergegeven wanneer iemand de lijst met geverifieerde spelers probeert te wissen, maar leeg is
|
||||
empty: '%prefix%De lijst met geverifieerde spelers is momenteel leeg. Daarom nee
|
||||
spelers waren niet geverifieerd.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand de lijst met geverifieerde spelers wist
|
||||
cleared: '%prefix%Je hebt met succes de verificatie van in totaal %removed% unieke speler(s) ongedaan gemaakt.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand de grootte van de lijst met geverifieerde spelers controleert
|
||||
size: '%prefix%Er zijn momenteel %amount% unieke speler(s) geverifieerd.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand de verificatie van een IP-adres ongedaan maakt
|
||||
removed: '%prefix%De verificatie van %ip% is succesvol ingetrokken.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand een IP-adres verifieert
|
||||
added: '%prefix%%ip% succesvol geverifieerd.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand een IP-adres/UUID probeert te verifiëren die al is geverifieerd
|
||||
already: '%prefix%Het IP-adres en de UUID die u heeft opgegeven, zijn al geverifieerd.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand de verificatie van een IP-adres ongedaan maakt, maar het is niet geverifieerd
|
||||
ip-not-found: '%prefix%Het door u opgegeven IP-adres is niet geverifieerd.'
|
||||
# Bericht dat wordt weergegeven wanneer iemand tweemaal hetzelfde IP-adres probeert te de-verifiëren (dubbele handeling)
|
||||
blocked: '%prefix%Wacht tot de huidige bewerking is voltooid.'
|
||||
|
||||
# Vertalingen voor '/sonar statistics'
|
||||
statistics:
|
||||
# Informatieve boodschap die boven alles wordt getoond bij het bekijken van de statistieken
|
||||
header: '%prefix%Er worden %type% statistieken voor deze sessie weergegeven:'
|
||||
# Bericht dat wordt weergegeven wanneer een speler een onbekende statistiek probeert te bekijken
|
||||
unknown-type: '%prefix%<red>Onbekend statistieke! Beschikbare statistieken: <gray>%statistics%'
|
||||
# Formaat van het algemene statistische bericht
|
||||
general:
|
||||
- ' <dark_aqua>▪ <gray>Geverifieerde IP-adressen: <white>%verified%'
|
||||
- ' <dark_aqua>▪ <gray>IP-adressen verifiëren: <white>%verifying%'
|
||||
- ' <dark_aqua>▪ <gray>IP-adressen op de zwarte lijst: <white>%blacklisted%'
|
||||
- ' <dark_aqua>▪ <gray>Wachtrij staande aanmeldingen: <white>%queued%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal aantal niet-unieke joins: <white>%total_joins%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal aantal verificatiepogingen: <white>%total_attempts%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal aantal mislukte verificaties: <white>%total_failed%'
|
||||
- ' <dark_aqua>▪ <gray>Server-uptime: <white>%uptime%'
|
||||
# Formaat van het bericht over CPU-statistieken
|
||||
cpu:
|
||||
- ' <dark_aqua>▪ <gray>Verwerk het CPU-gebruik nu: <white>%process_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>Systeem-CPU-gebruik nu: <white>%system_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>CPU-gebruik per kernproces: <white>%average_process_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>CPU-gebruik per core systeem: <white>%average_system_cpu%%'
|
||||
- ' <dark_aqua>▪ <gray>Algemene systeembelasting: <white>%load_average%%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal aantal virtuele CPUs: <white>%virtual_cores%'
|
||||
# Formaat van het bericht met geheugenstatistieken
|
||||
memory:
|
||||
- ' <dark_aqua>▪ <gray>Totaal vrij geheugen: <white>%free_memory%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal gebruikt geheugen: <white>%used_memory%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal maximaal geheugen: <white>%max_memory%'
|
||||
- ' <dark_aqua>▪ <gray>Totaal toegewezen geheugen: <white>%total_memory%'
|
||||
# Formaat van het bericht met netwerkstatistieken
|
||||
network:
|
||||
- ' <dark_aqua>▪ <gray>Huidige inkomende gebruikte bandbreedte: <white>%incoming%'
|
||||
- ' <dark_aqua>▪ <gray>Huidige uitgaande gebruikte bandbreedte: <white>%outgoing%'
|
||||
- ' <dark_aqua>▪ <gray>Totale inkomende gebruikte bandbreedte: <white>%ttl_incoming%'
|
||||
- ' <dark_aqua>▪ <gray>Totale uitgaande gebruikte bandbreedte: <white>%ttl_outgoing%'
|
||||
|
||||
# Vertalingen voor alle berichten tijdens het verificatieproces
|
||||
verification:
|
||||
# Vertalingen voor alle debug-berichten tijdens de verificatie
|
||||
logs:
|
||||
# Bericht dat in de console wordt geregistreerd wanneer een nieuwe speler zich bij de server voegt
|
||||
connection: '%name%%ip% (%protocol%) heeft verbinding gemaakt.'
|
||||
# Bericht dat in de console wordt geregistreerd wanneer de verificatie van een speler mislukt
|
||||
failed: '%ip% (%protocol%) heeft de bot-controle niet doorstaan vanwege: %reason%'
|
||||
# Bericht dat op de console wordt geregistreerd wanneer een speler op de zwarte lijst staat
|
||||
blacklisted: '%ip% (%protocol%) stond op de zwarte lijst vanwege te veel mislukte pogingen'
|
||||
# Bericht dat op de console wordt geregistreerd wanneer een speler is geverifieerd
|
||||
successful: '%name% is succesvol geverifieerd (%time%s!).'
|
||||
|
||||
# Berichten die aan de speler worden getoond wanneer hij of zij de CAPTCHA moet invoeren
|
||||
captcha:
|
||||
# Bericht dat aan de speler wordt getoond wanneer hij het antwoord op de captcha moet invoeren
|
||||
enter-code: '%prefix%<green>Voer de code in de chat in die wordt weergegeven op
|
||||
de kaart.'
|
||||
# Bericht dat aan de speler wordt getoond wanneer hij of zij het verkeerde antwoord invoert in de chat
|
||||
incorrect: '%prefix%<red>U heeft de verkeerde code ingevoerd. Probeer het opnieuw.'
|
||||
|
||||
# Verbindingsbericht dat wordt getoond als iemand zich aansluit terwijl de captcha nog niet is voorbereid
|
||||
currently-preparing:
|
||||
- '%header%'
|
||||
- <yellow>Uw anti-bot gegevens zijn nog niet voorbereid.
|
||||
- <gray>Wacht een paar seconden voordat u opnieuw probeert te verifiëren.
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand tijdens de verificatie te snel opnieuw deelneemt
|
||||
too-fast-reconnect:
|
||||
- '%header%'
|
||||
- <gold>Je hebt te snel opnieuw verbinding gemaakt. Probeer het later opnieuw.
|
||||
- <gray>Wacht een paar seconden voordat u opnieuw probeert te verifiëren.
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand zich aanmeldt, maar zich al aan het verifiëren is
|
||||
already-verifying:
|
||||
- '%header%'
|
||||
- <red>Uw IP-adres wordt momenteel geverifieerd.
|
||||
- <red>Wacht een paar seconden voordat u opnieuw probeert te verifiëren.
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand zich aanmeldt, maar al in de wachtrij staat voor verificatie
|
||||
already-queued:
|
||||
- '%header%'
|
||||
- <red>Uw IP-adres staat momenteel in de wachtrij voor verificatie.
|
||||
- <red>Wacht een paar minuten voordat u opnieuw probeert te verifiëren.
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand lid wordt, maar tijdelijk op de zwarte lijst staat
|
||||
blacklisted:
|
||||
- '%header%'
|
||||
- <red>Momenteel wordt u de toegang tot de server ontzegd.
|
||||
- <red>Wacht een paar minuten voordat u weer verbinding kunt maken met de server.
|
||||
- <gold>Vals positief? <gray>%support-url%
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand zich aanmeldt met een ongeldige gebruikersnaam
|
||||
invalid-username:
|
||||
- '%header%'
|
||||
- <red>Uw gebruikersnaam bevat ongeldige tekens.
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand zich aanmeldt met een versie op de zwarte lijst
|
||||
blacklisted-protocol:
|
||||
- '%header%'
|
||||
- <red>U gebruikt een versie die niet is toegestaan op onze server.
|
||||
- <gold>Hulp nodig bij het inloggen? <gray>%support-url%
|
||||
- '%footer%'
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand succesvol verifieert
|
||||
success:
|
||||
- '%header%'
|
||||
- <green>U heeft de verificatie succesvol doorlopen.
|
||||
- <white>Wanneer u opnieuw verbinding maakt, kunt u nu op de server spelen.
|
||||
# Verbindingsbericht dat wordt weergegeven wanneer iemand de verificatie mislukt
|
||||
failed:
|
||||
- '%header%'
|
||||
- <red>De bot-verificatie is mislukt.
|
||||
- <gray>Wacht een paar seconden voordat u opnieuw probeert te verifiëren.
|
||||
- <gold>Hulp nodig? <gray>%support-url%
|
||||
- '%footer%'
|
||||
|
||||
# Vertalingen voor Sonar's actiebalk uitgebreide berichten
|
||||
verbose:
|
||||
layout:
|
||||
# Lay-out voor de actiebalk van Sonar, uitgebreid
|
||||
# Tijdelijke aanduidingen:
|
||||
# - '%queued%' Aantal verbindingen in de wachtrij
|
||||
# - '%verifying%' Aantal verifiërende verbindingen
|
||||
# - '%blacklisted%' Aantal op de zwarte lijst geplaatste IP-adressen
|
||||
# - '%total-joins%' Aantal totale pogingen tot deelname
|
||||
# - '%verify-total%' Aantal totale verificatiepogingen
|
||||
# - '%verify-success%' Aantal geverifieerde IP-adressen
|
||||
# - '%verify-failed%' Aantal mislukte verificaties
|
||||
# - '%logins-per-second%' Aantal logins per seconde
|
||||
# - '%connections-per-second%' Aantal verbindingen per seconde
|
||||
# - '%attack-duration%' Duur van de huidige aanval
|
||||
# - '%incoming-traffic%' Inkomend bandbreedtegebruik per seconde
|
||||
# - '%outgoing-traffic%' Uitgaand bandbreedtegebruik per seconde
|
||||
# - '%incoming-traffic-ttl%' Totaal inkomend bandbreedtegebruik
|
||||
# - '%outgoing-traffic-ttl%' Totaal uitgaand bandbreedtegebruik
|
||||
# - '%used-memory%' Hoeveelheid gebruikt geheugen van het proces
|
||||
# - '%total-memory%' Hoeveelheid totale geheugen van het proces
|
||||
# - '%max-memory%' Hoeveelheid maximaal geheugen van het proces
|
||||
# - '%free-memory%' Hoeveelheid vrij geheugen van het proces
|
||||
# - '%animation%' Aanpasbaar geanimeerd symbool
|
||||
# Vertalingen voor de normale uitgebreide uitvoer van Sonar
|
||||
normal: '%prefix%<gray>CPS <white>%connections-per-second% <dark_aqua>╺ <gray>Inloggen/s
|
||||
<white>%logins-per-second% <dark_aqua>╺ <gray>Verifiëren <white>%verifying% <dark_aqua>|
|
||||
<green>⬆ <white>%outgoing-traffic%/s <red>⬇ <white>%incoming-traffic%/s <green><bold>%animation%<reset>'
|
||||
# Layout for Sonar's actionbar verbose during an attack
|
||||
attack: '%prefix%<gray>CPS <white>%connections-per-second% <dark_aqua>╺ <gray>Inloggen/s
|
||||
<white>%logins-per-second% <dark_aqua>╺ <gray>Wachtrij <white>%queued% <dark_aqua>╺
|
||||
<gray>Verifiëren <white>%verifying% <dark_aqua>╺ <gray>Duur <white>%attack-duration%
|
||||
<dark_aqua>| <green>⬆ <white>%outgoing-traffic%/s <red>⬇ <white>%incoming-traffic%/s <green><bold>%animation%<reset>'
|
||||
# Animatie voor de actiebalk
|
||||
# Alternatieven:
|
||||
# - ▙, ▛, ▜, ▟
|
||||
# - ⬈, ⬊, ⬋, ⬉
|
||||
animation:
|
||||
- ◜
|
||||
- ◝
|
||||
- ◞
|
||||
- ◟
|
||||
|
||||
# Vertalingen voor Sonar's aanval meldingen
|
||||
notifications:
|
||||
# Lay-out voor de titel van de aanval meldingen van Sonar
|
||||
title: <yellow><b>Sonar<reset>
|
||||
# Lay-out voor de ondertitel van Sonar's aanval meldingen
|
||||
subtitle: <gray>Er is een bot-aanval gedetecteerd
|
||||
# Lay-out voor de aanval meldingen van Sonar in de chat
|
||||
chat:
|
||||
- ''
|
||||
- <yellow><b>Sonar<reset>
|
||||
- ''
|
||||
- <gray>Er is een bot-aanval gedetecteerd.
|
||||
- ' <dark_aqua>▪ <gray>Inloggen per seconde: <white>%logins-per-second%'
|
||||
- ' <dark_aqua>▪ <gray>Spelers verifiëren: <white>%verifying%'
|
||||
- ' <dark_aqua>▪ <gray>Spelers in de wachtrij: <white>%queued%'
|
||||
- ''
|
||||
- <gray>Bekijk meer informatie via <white><click:run_command:'/sonar verbose'><hover:show_text:'(Klik
|
||||
om uit te voeren)'>/sonar verbose</hover></click><gray> of <white><click:run_command:'/sonar
|
||||
stats'><hover:show_text:'(Klik om uit te voeren)'>/sonar stats</hover></click><gray>.
|
||||
- ''
|
||||
@@ -185,10 +185,6 @@ verification:
|
||||
captcha:
|
||||
# Сообщение, которое показывается игроку, когда он должен ввести ответ на капчу
|
||||
enter-code: '%prefix%<green>Введите код в чате, который отображается на карте.'
|
||||
# Таймер, который показывается игроку, когда он должен ввести капчу
|
||||
# (Установите это значение на '' что-бы отключить эту функцию)
|
||||
action-bar: '%prefix%<green>У вас осталось %time-left% секунд, чтобы ввести код
|
||||
в чате'
|
||||
# Сообщение, которое показывается игроку, когда он вводит неправильную капчу в чат
|
||||
incorrect: '%prefix%<red>Вы ввели неправильный код. Пожалуйста, попробуйте еще раз.'
|
||||
|
||||
|
||||
@@ -176,9 +176,6 @@ verification:
|
||||
captcha:
|
||||
# Captcha'nın cevabını girmeleri gerektiğinde oyuncuya gösterilen mesaj
|
||||
enter-code: '%prefix%<green>Haritada gösterilen kodu lütfen sohbete girin.'
|
||||
# Timer that is shown to the player when they have to enter the answer to the captcha
|
||||
# (Set this to '' to disable the action bar message)
|
||||
action-bar: '%prefix%<green>Kodu girmek için %time-left% saniyeniz kaldı'
|
||||
# Message that is shown to the player when they enter the wrong answer in chat
|
||||
incorrect: '%prefix%<red>Yanlış kodu girdiniz. Lütfen tekrar deneyin.'
|
||||
|
||||
|
||||
@@ -180,8 +180,6 @@ verification:
|
||||
captcha:
|
||||
# 玩家需要输入验证码答案时显示的消息
|
||||
enter-code: '%prefix%<green>请在聊天框中发送地图上的验证码.'
|
||||
# 显示还有多少秒来解决验证码. (设置为空即禁用)
|
||||
action-bar: '%prefix%<green>您还有 %time-left% 秒来解决该验证码.'
|
||||
# 当玩家输入错误的验证码时显示的消息
|
||||
incorrect: '%prefix%<red>您输入了错误的验证码. 请再试一次'
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#
|
||||
# /$$$$$$
|
||||
# /$$__ $$
|
||||
# | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$
|
||||
# | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$
|
||||
# \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/
|
||||
# /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$
|
||||
# | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$
|
||||
# \______/ \______/ |__/ |__/ \_______/|__/
|
||||
#
|
||||
# Besoin d'aide ou d'autres questions ? https://jonesdev.xyz/discord
|
||||
# Code source : https://github.com/jonesdevelopment/sonar
|
||||
# Droit d'auteur Jones Development, un contributeur Sonar, licence sous GPL-3.0
|
||||
#
|
||||
|
||||
# Les notifications d'attaque bot peuvent être envoyé à discord via un webhook
|
||||
webhook:
|
||||
# Lien du webhook discord (Mettez '' pour désactiver les webhooks)
|
||||
url: ''
|
||||
# Nom d'utilisateur du webhook
|
||||
username: Sonar
|
||||
# Lien vers l'avatar du webhook (Mettez '' pour désactiver)
|
||||
avatar-url: ''
|
||||
# Message à envoyer (Mettez '' pour désactiver)
|
||||
# Vous pouvez mentionner des personnes en utilisant <@idUtilisateur>
|
||||
# Si vous voulez mentionner un rôle vous devriez utiliser <@&idRole>
|
||||
content: ''
|
||||
# Embed qui sera envoyé quand il y a une attaque
|
||||
embed:
|
||||
# Petit footer de l'embed
|
||||
footer:
|
||||
# Message du footer
|
||||
text: © Jones Development et Contributeurs Sonar
|
||||
# Lien de l'icône du footer
|
||||
icon-url: ''
|
||||
# Titre du webhook discord
|
||||
title: '✅ Attaque mitigé'
|
||||
# Lien clickable du titre
|
||||
title-url: ''
|
||||
# Description (message) de l'embed
|
||||
description:
|
||||
- 'L''attaque sur votre serveur a été mitigé'
|
||||
- ''
|
||||
- 'Démarré à: <t:%start-timestamp%:T>'
|
||||
- 'Fini à: <t:%end-timestamp%:T>'
|
||||
- 'Durée: %duration%'
|
||||
- ''
|
||||
- 'Pique du processeur: %peak-cpu%%'
|
||||
- 'Pique de la mémoire ram: %peak-memory%'
|
||||
- 'Pique du nombre de bots par secondes: %peak-bps%'
|
||||
- ''
|
||||
- "IP Blacklisté durant l'attaque: %total-blacklisted%"
|
||||
- "Vérification échoué durant l'attaque: %total-failed%"
|
||||
- "Vérification réussi durant l'attaque: %total-success%"
|
||||
# Code couleur RGB pour l'embed
|
||||
# Sélectionner la couleur: https://www.rapidtables.com/web/color/RGB_Color.html
|
||||
color:
|
||||
red: 0
|
||||
green: 255
|
||||
blue: 0
|
||||
@@ -0,0 +1,60 @@
|
||||
#
|
||||
# /$$$$$$
|
||||
# /$$__ $$
|
||||
# | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$
|
||||
# | $$$$$$ /$$__ $$| $$__ $$ |____ $$ /$$__ $$
|
||||
# \____ $$| $$ \ $$| $$ \ $$ /$$$$$$$| $$ \__/
|
||||
# /$$ \ $$| $$ | $$| $$ | $$ /$$__ $$| $$
|
||||
# | $$$$$$/| $$$$$$/| $$ | $$| $$$$$$$| $$
|
||||
# \______/ \______/ |__/ |__/ \_______/|__/
|
||||
#
|
||||
# Hulp nodig of vragen? https://jonesdev.xyz/discord
|
||||
# Broncode: https://github.com/jonesdevelopment/sonar
|
||||
# Copyright Jones Development and Sonar Contributors, licensed under GPL-3.0
|
||||
#
|
||||
|
||||
# Bot aanval meldingen kunnen ook met behulp van webhooks naar uw Discord-server worden verzonden
|
||||
webhook:
|
||||
# URL van de Discord-webhook (zet dit op '' om webhooks uit te schakelen)
|
||||
url: ''
|
||||
# Gebruikersnaam van de Discord-webhook-afzender
|
||||
username: Sonar
|
||||
# URL naar de avatar van de Discord-webhook-afzender (zet dit op '' om uit te schakelen)
|
||||
avatar-url: ''
|
||||
# Inhoud van het Discord-webhook (zet dit op '' om uit te schakelen)
|
||||
# U kunt dit gebruiken om bv. ping medewerkers met <@userId>
|
||||
# Als u rollen wilt pingen, moet u <@&roleId> gebruiken
|
||||
content: ''
|
||||
# Embed Discord-webhook dat wordt verzonden wanneer een aanval is gestopt
|
||||
embed:
|
||||
# Klein voettekst bericht van de Discord-webhook-insluiting
|
||||
footer:
|
||||
# Inhoud van de voettekst bericht van de Discord-webhook-insluiting
|
||||
text: © Jones Development and Sonar Contributors
|
||||
# URL van de voettekst pictogram van de Discord-webhook-insluiting
|
||||
icon-url: ''
|
||||
# Titel van de Discord-webhook-insluiting
|
||||
title: ':white_check_mark: Aanval verzacht'
|
||||
# Klikbare URL van de titel van de Discord-webhook-insluiting
|
||||
title-url: ''
|
||||
# Beschrijving (inhoud) van de Discord-webhook-insluiting
|
||||
description:
|
||||
- De aanval op uw server is afgezwakt.
|
||||
- ''
|
||||
- 'Aanval beginnen: <t:%start-timestamp%:T>'
|
||||
- 'Einde aanval: <t:%end-timestamp%:T>'
|
||||
- 'Duur van de aanval: %duration%'
|
||||
- ''
|
||||
- 'Maximaal proces CPU-gebruik tijdens de aanval: %peak-cpu%%'
|
||||
- 'Maximaal proces-geheugengebruik tijdens de aanval: %peak-memory%'
|
||||
- 'Maximaal bots per seconde tijdens de aanval: %peak-bps%'
|
||||
- ''
|
||||
- 'IP-adressen op de zwarte lijst gezet tijdens de aanval: %total-blacklisted%'
|
||||
- 'Mislukte verificaties tijdens de aanval: %total-failed%'
|
||||
- 'Succesvolle verificaties tijdens de aanval: %total-success%'
|
||||
# RGB-kleuren van de Discord-webhook-insluiting
|
||||
# Kleur kiezer: https://www.rapidtables.com/web/color/RGB_Color.html
|
||||
color:
|
||||
red: 0
|
||||
green: 255
|
||||
blue: 0
|
||||
@@ -40,9 +40,9 @@ public final class SonarVelocity extends SonarBootstrap<SonarVelocityPlugin> {
|
||||
public static SonarVelocity INSTANCE;
|
||||
|
||||
public SonarVelocity(final @NotNull SonarVelocityPlugin plugin) {
|
||||
super(plugin, new VelocityLibraryManager<>(
|
||||
plugin, plugin.getLogger(), plugin.getDataDirectory(), plugin.getServer().getPluginManager()),
|
||||
plugin.getDataDirectory().toFile(), SonarPlatform.VELOCITY);
|
||||
super(plugin, SonarPlatform.VELOCITY, plugin.getDataDirectory().toFile(),
|
||||
new VelocityLibraryManager<>(plugin, plugin.getLogger(),
|
||||
plugin.getDataDirectory(), plugin.getServer().getPluginManager()));
|
||||
INSTANCE = this;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,9 @@ public final class SonarVelocity extends SonarBootstrap<SonarVelocityPlugin> {
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
// Make sure to properly shutdown bStats metrics
|
||||
metrics.shutdown();
|
||||
if (metrics != null) {
|
||||
// Make sure to properly shutdown bStats metrics
|
||||
metrics.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -22,19 +22,21 @@ import io.netty.channel.ChannelInitializer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import xyz.jonesdev.sonar.api.ReflectiveOperationException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static com.velocitypowered.proxy.network.Connections.MINECRAFT_DECODER;
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_HANDLER;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackChannelInitializer extends ChannelInitializer<Channel> {
|
||||
private static final Method INIT_CHANNEL_METHOD;
|
||||
private static final MethodHandle INIT_CHANNEL_METHOD;
|
||||
|
||||
static {
|
||||
try {
|
||||
INIT_CHANNEL_METHOD = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
INIT_CHANNEL_METHOD.setAccessible(true);
|
||||
INIT_CHANNEL_METHOD = MethodHandles.privateLookupIn(ChannelInitializer.class, MethodHandles.lookup())
|
||||
.findVirtual(ChannelInitializer.class, "initChannel", MethodType.methodType(void.class, Channel.class));
|
||||
} catch (Throwable throwable) {
|
||||
throw new ReflectiveOperationException(throwable);
|
||||
}
|
||||
@@ -46,7 +48,7 @@ public final class FallbackChannelInitializer extends ChannelInitializer<Channel
|
||||
protected void initChannel(final Channel channel) throws Exception {
|
||||
// Invoke the original method
|
||||
try {
|
||||
INIT_CHANNEL_METHOD.invoke(originalChannelInitializer, channel);
|
||||
INIT_CHANNEL_METHOD.invokeExact(originalChannelInitializer, channel);
|
||||
} catch (Throwable throwable) {
|
||||
throw new ReflectiveOperationException(throwable);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,18 @@
|
||||
{
|
||||
"id": "viaversion",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "packetevents",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "vpacketevents",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "fastlogin",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"main": "$main"
|
||||
|
||||
Reference in new issue
Block a user