mirror of
https://github.com/jonesdevelopment/sonar.git
synced 2026-11-05 09:20:15 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af12ef535c | ||
|
|
7de08ffa98 | ||
|
|
c56d41cd77 | ||
|
|
4b30729138 | ||
|
|
1254514ad2 | ||
|
|
b4673d8e9f | ||
|
|
5eaaf88ec8 | ||
|
|
367ce07cb0 | ||
|
|
901b49b063 | ||
|
|
a3cdc08f90 | ||
|
|
150a3575b2 | ||
|
|
6082bf944d | ||
|
|
e6d20e2b94 | ||
|
|
6f3a8432a7 | ||
|
|
350ae02ff0 | ||
|
|
32c37c0337 | ||
|
|
b8e552dff9 | ||
|
|
39902c2c9b | ||
|
|
3324ee6238 | ||
|
|
732a291417 | ||
|
|
778ac20e73 | ||
|
|
8cc49884ec | ||
|
|
798ba4bfd1 | ||
|
|
5139a63ff7 | ||
|
|
06d81f1ec0 | ||
|
|
d08de99e03 | ||
|
|
411cadb5c3 | ||
|
|
ab99061b93 | ||
|
|
7d7f1d97d9 | ||
|
|
9f4cc49cf7 | ||
|
|
8531dcc58a | ||
|
|
ec498000ba | ||
|
|
9ac46ce5a4 | ||
|
|
7848e47990 | ||
|
|
e377644e89 | ||
|
|
9f377780cb | ||
|
|
f14c5b2b90 | ||
|
|
45683040ab | ||
|
|
d0f63bea48 | ||
|
|
030a532df8 | ||
|
|
0f957b444b | ||
|
|
cb03833a8a | ||
|
|
22f2ab56bc | ||
|
|
cda6b395ac | ||
|
|
46c5853f7c | ||
|
|
cf4713b2d8 | ||
|
|
f82f0ddd87 | ||
|
|
7f3d244030 | ||
|
|
3db8230e9f | ||
|
|
8295119016 | ||
|
|
a0b14214ae | ||
|
|
3d96a32f81 | ||
|
|
de67ab12c2 | ||
|
|
adef9d9ccb | ||
|
|
71b40af656 | ||
|
|
3a79711a8b | ||
|
|
3094f12f84 | ||
|
|
a74c3da8d4 | ||
|
|
427768fc43 | ||
|
|
b0d7dfb735 | ||
|
|
ff9216c4cc | ||
|
|
43a1aa2ae8 | ||
|
|
f36a613124 | ||
|
|
3e193bddd7 | ||
|
|
66d0651d1e | ||
|
|
b21c4e8a9a | ||
|
|
b77e0c4806 | ||
|
|
cb76dfe06e | ||
|
|
d0a758473f | ||
|
|
e4dfab87da | ||
|
|
2fe3ab1d8d | ||
|
|
4483e52852 | ||
|
|
22b41151d6 | ||
|
|
e849060db1 | ||
|
|
59b338e775 |
No files matched your search
@@ -0,0 +1 @@
|
||||
patreon: jonesdev
|
||||
@@ -48,6 +48,11 @@ Sonar also protects against spambot attacks since it queues the incoming connect
|
||||
Sonar is unlikely to ever falsely prevent a player from joining the server since Minecraft uses the TCP protocol, which means that packets are always sent in the correct order. Therefore, lag or ping should not affect the bot check.
|
||||
If you or one of your players experiences a false positive, make sure to report it by opening a [GitHub issue](https://github.com/jonesdevelopment/sonar/issues/new/choose) or a ticket on the [Discord server](https://jonesdev.xyz/discord/).
|
||||
|
||||
## Sponsors
|
||||
Massive thanks to the sponsors of Sonar who help keep this project running:
|
||||
|
||||
<a href="https://github.com/Hydoxl"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/107579333?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
|
||||
|
||||
## Building
|
||||
If you want to build your own version of Sonar, please take a look at the [Sonar building documentation](https://docs.jonesdev.xyz/development/building).
|
||||
<br>
|
||||
|
||||
@@ -21,42 +21,36 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@v3
|
||||
with:
|
||||
arguments: build-sonar
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@v3
|
||||
with:
|
||||
arguments: build-sonar
|
||||
|
||||
- name: Upload Bukkit Artifact
|
||||
uses: actions/upload-artifact@v3.1.3
|
||||
with:
|
||||
# Artifact name
|
||||
name: Sonar
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: bukkit/build/libs/Sonar-Bukkit.jar
|
||||
if-no-files-found: error
|
||||
- name: Upload Bukkit Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Sonar-Bukkit
|
||||
path: bukkit/build/libs/Sonar-Bukkit.jar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload BungeeCord Artifact
|
||||
uses: actions/upload-artifact@v3.1.3
|
||||
with:
|
||||
# Artifact name
|
||||
name: Sonar
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: bungeecord/build/libs/Sonar-Bungee.jar
|
||||
if-no-files-found: error
|
||||
- name: Upload BungeeCord Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Sonar-Bungee
|
||||
path: bungeecord/build/libs/Sonar-Bungee.jar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Velocity Artifact
|
||||
uses: actions/upload-artifact@v3.1.3
|
||||
with:
|
||||
# Artifact name
|
||||
name: Sonar
|
||||
# A file, directory or wildcard pattern that describes what to upload
|
||||
path: velocity/build/libs/Sonar-Velocity.jar
|
||||
if-no-files-found: error
|
||||
- name: Upload Velocity Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Sonar-Velocity
|
||||
path: velocity/build/libs/Sonar-Velocity.jar
|
||||
if-no-files-found: error
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) ${YEAR} Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,3 +14,4 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,3 @@ tasks {
|
||||
archiveFileName = "sonar-api-${rootProject.version}.jar"
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -49,22 +49,68 @@ public interface Sonar {
|
||||
@ApiStatus.Internal
|
||||
@NotNull Audience sender(final @NotNull Object object);
|
||||
|
||||
/**
|
||||
* Gets the platform Sonar is running on (e.g., Bukkit, BungeeCord, Velocity).
|
||||
*
|
||||
* @return The {@link SonarPlatform} enum representing the current platform.
|
||||
*/
|
||||
@NotNull SonarPlatform getPlatform();
|
||||
|
||||
/**
|
||||
* Gets the logger instance for Sonar.
|
||||
*
|
||||
* @return The {@link LoggerWrapper} instance.
|
||||
*/
|
||||
@NotNull LoggerWrapper getLogger();
|
||||
|
||||
/**
|
||||
* Gets the Sonar configuration.
|
||||
*
|
||||
* @return The {@link SonarConfiguration} instance.
|
||||
*/
|
||||
@NotNull SonarConfiguration getConfig();
|
||||
|
||||
/**
|
||||
* Gets the subcommand registry for Sonar commands.
|
||||
*
|
||||
* @return The {@link SubcommandRegistry} instance.
|
||||
*/
|
||||
@NotNull SubcommandRegistry getSubcommandRegistry();
|
||||
|
||||
/**
|
||||
* Gets the controller for verified players.
|
||||
* Used for managing players who have passed the verification.
|
||||
*
|
||||
* @return The {@link VerifiedPlayerController} instance.
|
||||
*/
|
||||
VerifiedPlayerController getVerifiedPlayerController();
|
||||
|
||||
/**
|
||||
* Gets the handler for action bar notifications.
|
||||
*
|
||||
* @return The {@link ActionBarNotificationHandler} instance.
|
||||
*/
|
||||
@NotNull ActionBarNotificationHandler getActionBarNotificationHandler();
|
||||
|
||||
/**
|
||||
* Gets the handler for chat notifications.
|
||||
*
|
||||
* @return The {@link ChatNotificationHandler} instance.
|
||||
*/
|
||||
@NotNull ChatNotificationHandler getChatNotificationHandler();
|
||||
|
||||
/**
|
||||
* Gets the system timer used for tracking plugin launch time.
|
||||
*
|
||||
* @return The {@link SystemTimer} instance.
|
||||
*/
|
||||
@NotNull SystemTimer getLaunchTimer();
|
||||
|
||||
/**
|
||||
* Gets the statistics tracker for Sonar.
|
||||
*
|
||||
* @return The {@link SonarStatistics} instance.
|
||||
*/
|
||||
@NotNull SonarStatistics getStatistics();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -73,30 +119,67 @@ public interface Sonar {
|
||||
@SuppressWarnings("unused")
|
||||
void setChatNotificationHandler(final @NotNull ChatNotificationHandler notificationHandler);
|
||||
|
||||
/**
|
||||
* Reloads the Sonar configuration.
|
||||
*/
|
||||
void reload();
|
||||
|
||||
@NotNull
|
||||
default SonarVersion getVersion() {
|
||||
/**
|
||||
* Gets the current version of Sonar.
|
||||
*
|
||||
* @return The {@link SonarVersion} instance.
|
||||
*/
|
||||
@NotNull default SonarVersion getVersion() {
|
||||
return SonarVersion.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default SonarEventManager getEventManager() {
|
||||
/**
|
||||
* Gets the event manager for Sonar.
|
||||
*
|
||||
* @return The {@link SonarEventManager} instance.
|
||||
*/
|
||||
@NotNull default SonarEventManager getEventManager() {
|
||||
return SonarEventManager.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default AttackTracker getAttackTracker() {
|
||||
/**
|
||||
* Gets the attack tracker for Sonar.
|
||||
*
|
||||
* @return The {@link AttackTracker} instance.
|
||||
*/
|
||||
@NotNull default AttackTracker getAttackTracker() {
|
||||
return AttackTracker.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default Fallback getFallback() {
|
||||
/**
|
||||
* Gets the anti-bot handler (called "Fallback") for Sonar.
|
||||
*
|
||||
* @return The {@link Fallback} instance.
|
||||
*/
|
||||
@NotNull default Fallback getFallback() {
|
||||
return Fallback.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Sonar get() {
|
||||
/**
|
||||
* Gets the instance of the Sonar API.
|
||||
*
|
||||
* @return The {@link Sonar} instance.
|
||||
* @throws IllegalStateException If Sonar has not been initialized.
|
||||
*/
|
||||
@NotNull static Sonar get() {
|
||||
return SonarSupplier.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of the Sonar API.
|
||||
* Only use this method if you understand the implications,
|
||||
* and have a specific reason to bypass the standard {@link #get()} method.
|
||||
* In most cases, {@link #get()} is the preferred way to access the Sonar API.
|
||||
*
|
||||
* @return The Sonar instance.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NotNull static Sonar get0() {
|
||||
return SonarSupplier.sonar;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,4 +30,11 @@ public class SonarSupplier {
|
||||
}
|
||||
sonar = _sonar;
|
||||
}
|
||||
|
||||
public Sonar get() {
|
||||
if (sonar == null) {
|
||||
throw new IllegalStateException("Sonar is not initialized yet");
|
||||
}
|
||||
return sonar;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -36,8 +36,8 @@ public interface SonarCommand {
|
||||
default void handle(final @NotNull InvocationSource source, final String @NotNull [] args) {
|
||||
// Check if the player actually has the permission to run the command
|
||||
if (source.isPlayer() && !source.getPermissionFunction().test("sonar.command")) {
|
||||
if (Sonar.get().getConfig().getNoPermission() != null) {
|
||||
source.sendMessage(Sonar.get().getConfig().getNoPermission());
|
||||
if (Sonar.get0().getConfig().getNoPermission() != null) {
|
||||
source.sendMessage(Sonar.get0().getConfig().getNoPermission());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public interface SonarCommand {
|
||||
|
||||
if (args.length > 0) {
|
||||
// Search subcommand if command arguments are present
|
||||
subcommand = Sonar.get().getSubcommandRegistry().getSubcommands().stream()
|
||||
subcommand = Sonar.get0().getSubcommandRegistry().getSubcommands().stream()
|
||||
.filter(sub -> sub.getInfo().name().equalsIgnoreCase(args[0])
|
||||
|| Arrays.stream(sub.getInfo().aliases()).anyMatch(alias -> alias.equalsIgnoreCase(args[0])))
|
||||
.findFirst();
|
||||
@@ -57,8 +57,8 @@ public interface SonarCommand {
|
||||
if (!command.getInfo().onlyConsole()
|
||||
&& !source.getPermissionFunction().test(command.getPermission())) {
|
||||
source.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.subcommand-no-permission"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix()),
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.subcommand-no-permission"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
|
||||
Placeholder.unparsed("permission", command.getPermission())));
|
||||
return;
|
||||
}
|
||||
@@ -66,28 +66,28 @@ public interface SonarCommand {
|
||||
command.invoke(source, args);
|
||||
}, () -> {
|
||||
final UpdateChecker.CheckResult checkResult = UpdateChecker.getLastCheckResult();
|
||||
Component version = Component.text(Sonar.get().getVersion().getFormatted());
|
||||
Component version = Component.text(Sonar.get0().getVersion().getFormatted());
|
||||
if (checkResult.getConfigKey() != null) {
|
||||
version = version.append(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.main." + checkResult.getConfigKey())));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.main." + checkResult.getConfigKey())));
|
||||
}
|
||||
|
||||
// Print standard help message
|
||||
source.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
String.join("<newline>",
|
||||
Sonar.get().getConfig().getMessagesConfig().getStringList("commands.main.header")),
|
||||
Sonar.get0().getConfig().getMessagesConfig().getStringList("commands.main.header")),
|
||||
Placeholder.component("version", version),
|
||||
Placeholder.unparsed("platform", Sonar.get().getPlatform().getDisplayName()),
|
||||
Placeholder.unparsed("platform", Sonar.get0().getPlatform().getDisplayName()),
|
||||
Placeholder.unparsed("copyright-year", String.valueOf(Calendar.getInstance().get(Calendar.YEAR)))));
|
||||
|
||||
final Component yes = MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.main.tick"));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.main.tick"));
|
||||
final Component no = MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.main.cross"));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.main.cross"));
|
||||
|
||||
Sonar.get().getSubcommandRegistry().getSubcommands().forEach(command -> {
|
||||
Sonar.get0().getSubcommandRegistry().getSubcommands().forEach(command -> {
|
||||
source.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.main.subcommands"),
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.main.subcommands"),
|
||||
TagResolver.resolver("suggest-subcommand",
|
||||
(queue, context) -> Tag.styling(ClickEvent.suggestCommand("/sonar " + command.getInfo().name()))),
|
||||
Placeholder.unparsed("subcommand", command.getInfo().name()),
|
||||
@@ -103,7 +103,7 @@ public interface SonarCommand {
|
||||
static void prepareCachedTabSuggestions() {
|
||||
if (TAB_SUGGESTIONS.isEmpty()) {
|
||||
final List<String> subcommandsAndAliases = new ArrayList<>();
|
||||
for (final Subcommand subcommand : Sonar.get().getSubcommandRegistry().getSubcommands()) {
|
||||
for (final Subcommand subcommand : Sonar.get0().getSubcommandRegistry().getSubcommands()) {
|
||||
subcommandsAndAliases.add(subcommand.getInfo().name());
|
||||
|
||||
final List<String> arguments = Arrays.asList(subcommand.getInfo().arguments());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -48,8 +48,8 @@ public abstract class Subcommand {
|
||||
protected static @Nullable String validateIP(final InvocationSource source, final String raw) {
|
||||
if (!IPv4_REGEX.matcher(raw).matches() && !IPv6_REGEX.matcher(raw).matches()) {
|
||||
source.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.invalid-ip-address"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix())));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.invalid-ip-address"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())));
|
||||
return null;
|
||||
}
|
||||
return raw;
|
||||
@@ -61,8 +61,8 @@ public abstract class Subcommand {
|
||||
|
||||
protected final void incorrectUsage(final @NotNull InvocationSource invocationSource, final String usage) {
|
||||
invocationSource.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.incorrect-usage"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix()),
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.incorrect-usage"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
|
||||
Placeholder.unparsed("subcommand-usage", usage)));
|
||||
}
|
||||
|
||||
@@ -70,16 +70,16 @@ public abstract class Subcommand {
|
||||
// Check if the subcommand can only be executed by players
|
||||
if (info.onlyPlayers() && !invocationSource.isPlayer()) {
|
||||
invocationSource.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.player-only"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix())));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.player-only"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the subcommand can only be executed though console
|
||||
if (info.onlyConsole() && invocationSource.isPlayer()) {
|
||||
invocationSource.sendMessage(MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("commands.console-only"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix())));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("commands.console-only"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public abstract class Subcommand {
|
||||
|
||||
public final @NotNull String getDescription() {
|
||||
final String path = String.format("commands.%s.description", info.name());
|
||||
return Objects.requireNonNull(Sonar.get().getConfig().getMessagesConfig().getString(path));
|
||||
return Objects.requireNonNull(Sonar.get0().getConfig().getMessagesConfig().getString(path));
|
||||
}
|
||||
|
||||
protected abstract void execute(final @NotNull InvocationSource source, final String @NotNull [] args);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -140,6 +140,7 @@ public enum Language {
|
||||
FA("Persian"),
|
||||
PL("Polish"),
|
||||
PT("Portuguese"),
|
||||
PT_BR("Brazilian Portuguese", "pt-br"),
|
||||
PS("Pushto"),
|
||||
QU("Quechua"),
|
||||
RM("Raeto-Romance"),
|
||||
@@ -203,7 +204,18 @@ public enum Language {
|
||||
this.code = name().toLowerCase();
|
||||
}
|
||||
|
||||
Language(final String name, final String code) {
|
||||
this.name = name;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public static Language fromCode(final @NotNull String code) {
|
||||
return Language.valueOf(code.toUpperCase());
|
||||
for (final Language language : values()) {
|
||||
if (language.code.equalsIgnoreCase(code)) {
|
||||
return language;
|
||||
}
|
||||
}
|
||||
// Fallback to English
|
||||
return EN;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -89,7 +89,7 @@ public final class SimpleYamlConfig {
|
||||
|
||||
public int getInt(final String path) {
|
||||
if (!yaml.contains(path)) {
|
||||
Sonar.get().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
Sonar.get0().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
return 0;
|
||||
}
|
||||
return yaml.getInt(path);
|
||||
@@ -97,7 +97,7 @@ public final class SimpleYamlConfig {
|
||||
|
||||
public boolean getBoolean(final String path) {
|
||||
if (!yaml.contains(path)) {
|
||||
Sonar.get().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
Sonar.get0().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
return false;
|
||||
}
|
||||
return yaml.getBoolean(path);
|
||||
@@ -105,7 +105,7 @@ public final class SimpleYamlConfig {
|
||||
|
||||
public @NotNull String getString(final String path) {
|
||||
if (!yaml.contains(path)) {
|
||||
Sonar.get().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
Sonar.get0().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
return "";
|
||||
}
|
||||
final Object object = yaml.get(path);
|
||||
@@ -117,7 +117,7 @@ public final class SimpleYamlConfig {
|
||||
|
||||
public List<String> getStringList(final String path) {
|
||||
if (!yaml.contains(path)) {
|
||||
Sonar.get().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
Sonar.get0().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
return yaml.getStringList(path);
|
||||
@@ -125,7 +125,7 @@ public final class SimpleYamlConfig {
|
||||
|
||||
public List<Integer> getIntList(final String path) {
|
||||
if (!yaml.contains(path)) {
|
||||
Sonar.get().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
Sonar.get0().getLogger().warn("Could not find {} in {}.", path, file.getName());
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
return yaml.getIntegerList(path);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -66,14 +66,14 @@ public final class SonarConfiguration {
|
||||
final URL defaultLanguageFile = Sonar.class.getResource("/assets/language.properties");
|
||||
// Make sure the file actually exists before trying to copy it
|
||||
if (defaultLanguageFile == null) {
|
||||
Sonar.get().getLogger().error("Cannot check for custom language (is the file missing?)");
|
||||
Sonar.get0().getLogger().error("Cannot check for custom language (is the file missing?)");
|
||||
return DEFAULT_FALLBACK_LANGUAGE;
|
||||
}
|
||||
// Copy the file to the plugin data directory
|
||||
try (final InputStream inputStream = defaultLanguageFile.openStream()) {
|
||||
Files.copy(inputStream, languageFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException exception) {
|
||||
Sonar.get().getLogger().error("Error copying file: {}", exception);
|
||||
Sonar.get0().getLogger().error("Error copying file: {}", exception);
|
||||
return DEFAULT_FALLBACK_LANGUAGE;
|
||||
}
|
||||
}
|
||||
@@ -87,13 +87,13 @@ public final class SonarConfiguration {
|
||||
// Try parsing the property as a language
|
||||
return Language.fromCode(property);
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().error("Could not find requested language: {}", throwable);
|
||||
Sonar.get().getLogger().error("You can view a full list of valid language codes here:");
|
||||
Sonar.get().getLogger().error("https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes");
|
||||
Sonar.get().getLogger().error("If a translation does not exist yet, Sonar will use English (en).");
|
||||
Sonar.get0().getLogger().error("Could not find requested language: {}", throwable);
|
||||
Sonar.get0().getLogger().error("You can view a full list of valid language codes here:");
|
||||
Sonar.get0().getLogger().error("https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes");
|
||||
Sonar.get0().getLogger().error("If a translation does not exist yet, Sonar will use English (en).");
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
Sonar.get().getLogger().error("Error reading language file: {}", exception);
|
||||
Sonar.get0().getLogger().error("Error reading language file: {}", exception);
|
||||
}
|
||||
return DEFAULT_FALLBACK_LANGUAGE;
|
||||
}
|
||||
@@ -112,13 +112,13 @@ public final class SonarConfiguration {
|
||||
final String property = System.getProperty("user.language", "en");
|
||||
language = Language.fromCode(property);
|
||||
// Make sure the user knows that we're using the system language for translations
|
||||
Sonar.get().getLogger().info("Using system language ({}) for translations.", language);
|
||||
Sonar.get0().getLogger().info("Using system language ({}) for translations.", language);
|
||||
} catch (Exception exception) {
|
||||
Sonar.get().getLogger().warn("Could not use system language for translations.");
|
||||
Sonar.get().getLogger().warn("Using default language ({}) for translations.", language);
|
||||
Sonar.get0().getLogger().warn("Could not use system language for translations.");
|
||||
Sonar.get0().getLogger().warn("Using default language ({}) for translations.", language);
|
||||
}
|
||||
} else {
|
||||
Sonar.get().getLogger().info("Using custom language ({}) for translations.", language);
|
||||
Sonar.get0().getLogger().info("Using custom language ({}) for translations.", language);
|
||||
}
|
||||
|
||||
// Load all configurations
|
||||
@@ -158,12 +158,12 @@ public final class SonarConfiguration {
|
||||
verification.timing = Verification.Timing.valueOf(generalConfig.getString("verification.timing"));
|
||||
// Warn the user if the verification timing is set to NEVER
|
||||
if (verification.timing == Verification.Timing.NEVER) {
|
||||
Sonar.get().getLogger().warn(" ");
|
||||
Sonar.get().getLogger().warn("You have set the verification timing to 'NEVER'.");
|
||||
Sonar.get().getLogger().warn("Sonar will NOT perform the bot verification at all, therefore making it useless.");
|
||||
Sonar.get().getLogger().warn("It is highly suggested to set this option to either 'DURING_ATTACK' or 'ALWAYS'.");
|
||||
Sonar.get().getLogger().warn("Please only edit this option if you really know what you are doing.");
|
||||
Sonar.get().getLogger().warn(" ");
|
||||
Sonar.get0().getLogger().warn(" ");
|
||||
Sonar.get0().getLogger().warn("You have set the verification timing to 'NEVER'.");
|
||||
Sonar.get0().getLogger().warn("Sonar will NOT perform the bot verification at all, therefore making it useless.");
|
||||
Sonar.get0().getLogger().warn("It is highly suggested to set this option to either 'DURING_ATTACK' or 'ALWAYS'.");
|
||||
Sonar.get0().getLogger().warn("Please only edit this option if you really know what you are doing.");
|
||||
Sonar.get0().getLogger().warn(" ");
|
||||
}
|
||||
|
||||
verification.gravity.enabled = generalConfig.getBoolean("verification.checks.gravity.enabled");
|
||||
@@ -187,7 +187,7 @@ public final class SonarConfiguration {
|
||||
if (backgroundFile.exists()) {
|
||||
verification.map.backgroundImage = backgroundFile;
|
||||
} else {
|
||||
Sonar.get().getLogger().error("Could not find background image {}", backgroundFile.getAbsolutePath());
|
||||
Sonar.get0().getLogger().error("Could not find background image {}", backgroundFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,16 +220,12 @@ public final class SonarConfiguration {
|
||||
webhook.content = webhookConfig.getString("webhook.content");
|
||||
webhook.footer.text = webhookConfig.getString("webhook.embed.footer.text");
|
||||
webhook.footer.iconUrl = webhookConfig.getString("webhook.embed.footer.icon-url");
|
||||
|
||||
final String realEmbedPath = "webhook.embed";
|
||||
final String embedPath = realEmbedPath + ".";
|
||||
|
||||
webhook.embed.title = webhookConfig.getString(embedPath + "title");
|
||||
webhook.embed.titleUrl = webhookConfig.getString(embedPath + "title-url");
|
||||
webhook.embed.description = String.join("\n", webhookConfig.getStringList(embedPath + "description"));
|
||||
webhook.embed.r = webhookConfig.getInt(embedPath + "color.red");
|
||||
webhook.embed.g = webhookConfig.getInt(embedPath + "color.green");
|
||||
webhook.embed.b = webhookConfig.getInt(embedPath + "color.blue");
|
||||
webhook.embed.title = webhookConfig.getString("webhook.embed.title");
|
||||
webhook.embed.titleUrl = webhookConfig.getString("webhook.embed.title-url");
|
||||
webhook.embed.description = String.join("\n", webhookConfig.getStringList("webhook.embed.description"));
|
||||
webhook.embed.r = webhookConfig.getInt("webhook.embed.color.red");
|
||||
webhook.embed.g = webhookConfig.getInt("webhook.embed.color.green");
|
||||
webhook.embed.b = webhookConfig.getInt("webhook.embed.color.blue");
|
||||
|
||||
if (!webhook.url.isEmpty()) {
|
||||
if (webhook.username.isEmpty()) {
|
||||
@@ -266,6 +262,7 @@ public final class SonarConfiguration {
|
||||
|
||||
tooManyOnlinePerIp = deserializeDisconnectMessage("too-many-online-per-ip");
|
||||
verification.currentlyPreparing = deserializeDisconnectMessage("verification.currently-preparing");
|
||||
verification.unsupportedVersion = deserializeDisconnectMessage("verification.unsupported-version");
|
||||
verification.tooFastReconnect = deserializeDisconnectMessage("verification.too-fast-reconnect");
|
||||
verification.alreadyVerifying = deserializeDisconnectMessage("verification.already-verifying");
|
||||
verification.alreadyQueued = deserializeDisconnectMessage("verification.already-queued");
|
||||
@@ -291,7 +288,7 @@ public final class SonarConfiguration {
|
||||
final String resourceName = url + "/" + language.getCode() + ".yml";
|
||||
URL result = Sonar.class.getResource("/assets/" + resourceName);
|
||||
if (result == null) {
|
||||
Sonar.get().getLogger().warn("Could not find " + resourceName + "! Using en.yml!");
|
||||
Sonar.get0().getLogger().warn("Could not find " + resourceName + "! Using en.yml!");
|
||||
result = Objects.requireNonNull(Sonar.class.getResource("/assets/" + url + "/en.yml"));
|
||||
}
|
||||
return result;
|
||||
@@ -300,7 +297,7 @@ public final class SonarConfiguration {
|
||||
private static int clamp(final int v, final int max, final int min) {
|
||||
final int output = Math.max(Math.min(v, min), max);
|
||||
if (output != v) {
|
||||
Sonar.get().getLogger().warn("Clamped configuration value {} to {}", v, output);
|
||||
Sonar.get0().getLogger().warn("Clamped configuration value {} to {}", v, output);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@@ -440,6 +437,7 @@ public final class SonarConfiguration {
|
||||
private Component blacklisted;
|
||||
private Component protocolBlacklisted;
|
||||
private Component currentlyPreparing;
|
||||
private Component unsupportedVersion;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
+14
-13
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -56,17 +56,17 @@ public final class VerifiedPlayerController {
|
||||
private final ExecutorService updateService = Executors.newSingleThreadExecutor();
|
||||
|
||||
public VerifiedPlayerController(final @NotNull LibraryManager libraryManager) {
|
||||
final SonarConfiguration.Database database = Sonar.get().getConfig().getDatabase();
|
||||
final SonarConfiguration.Database database = Sonar.get0().getConfig().getDatabase();
|
||||
cachedDatabaseType = database.getType();
|
||||
|
||||
if (cachedDatabaseType == SonarConfiguration.Database.Type.NONE) {
|
||||
Sonar.get().getLogger().warn("Configure a database to save verified players.");
|
||||
Sonar.get0().getLogger().warn("Configure a database to save verified players.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure to only load the driver once per database type
|
||||
if (!cachedDatabaseType.isLoaded()) {
|
||||
Sonar.get().getLogger().info("Loading {} driver version {}",
|
||||
Sonar.get0().getLogger().info("Loading {} driver version {}",
|
||||
cachedDatabaseType.getDatabaseType().getDatabaseName(),
|
||||
cachedDatabaseType.getDatabaseDriver().getVersion());
|
||||
libraryManager.loadLibrary(cachedDatabaseType.getDatabaseDriver());
|
||||
@@ -79,20 +79,20 @@ public final class VerifiedPlayerController {
|
||||
// H2 has a different JDBC URL layout
|
||||
// https://www.codejava.net/java-se/jdbc/connect-to-h2-database-examples
|
||||
if (cachedDatabaseType == SonarConfiguration.Database.Type.H2) {
|
||||
final File file = new File(Sonar.get().getConfig().getPluginFolder(),
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("database.filename"));
|
||||
final File file = new File(Sonar.get0().getConfig().getPluginFolder(),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.filename"));
|
||||
jdbcURL = String.format(cachedDatabaseType.getConnectionString(), file.getAbsolutePath());
|
||||
} else {
|
||||
// Normal JDBC URL layout for MySQL/MariaDB/...
|
||||
jdbcURL = String.format(cachedDatabaseType.getConnectionString(),
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("database.host"),
|
||||
Sonar.get().getConfig().getGeneralConfig().getInt("database.port"),
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("database.name"));
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.host"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getInt("database.port"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.name"));
|
||||
}
|
||||
|
||||
connectionSource = new JdbcConnectionSource(jdbcURL,
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("database.username"),
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("database.password"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.username"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("database.password"),
|
||||
cachedDatabaseType.getDatabaseType());
|
||||
|
||||
try {
|
||||
@@ -133,6 +133,8 @@ public final class VerifiedPlayerController {
|
||||
public void close() {
|
||||
// The connection source will always be null if the database type is NONE.
|
||||
if (connectionSource != null) {
|
||||
// Shut down the update service before letting it re-use the connection.
|
||||
updateService.shutdown();
|
||||
try {
|
||||
connectionSource.close();
|
||||
} catch (Exception exception) {
|
||||
@@ -140,7 +142,6 @@ public final class VerifiedPlayerController {
|
||||
}
|
||||
// Make sure not to reuse a closed connection
|
||||
connectionSource = null;
|
||||
updateService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +159,7 @@ public final class VerifiedPlayerController {
|
||||
for (final VerifiedPlayer player : oldEntries) {
|
||||
dao.delete(player);
|
||||
}
|
||||
Sonar.get().getLogger().info("Removed {} database entries older than {} days.",
|
||||
Sonar.get0().getLogger().info("Removed {} database entries older than {} days.",
|
||||
oldEntries.size(), maximumAge);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -47,7 +47,7 @@ public final class SonarEventManager {
|
||||
try {
|
||||
eventListener.handle(event);
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().error("Could not pass {} to listener: {}",
|
||||
Sonar.get0().getLogger().error("Could not pass {} to listener: {}",
|
||||
event.getClass().getSimpleName(), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -49,16 +49,16 @@ public final class Fallback {
|
||||
private Ratelimiter<InetAddress> ratelimiter;
|
||||
|
||||
public boolean shouldVerifyNewPlayers() {
|
||||
return shouldPerform(Sonar.get().getConfig().getVerification().getTiming());
|
||||
return shouldPerform(Sonar.get0().getConfig().getVerification().getTiming());
|
||||
}
|
||||
|
||||
public boolean shouldPerformCaptcha() {
|
||||
return shouldPerform(Sonar.get().getConfig().getVerification().getMap().getTiming());
|
||||
return shouldPerform(Sonar.get0().getConfig().getVerification().getMap().getTiming());
|
||||
}
|
||||
|
||||
private static boolean shouldPerform(final SonarConfiguration.Verification.Timing timing) {
|
||||
return timing == SonarConfiguration.Verification.Timing.ALWAYS
|
||||
|| (timing == SonarConfiguration.Verification.Timing.DURING_ATTACK
|
||||
&& Sonar.get().getAttackTracker().getCurrentAttack() != null);
|
||||
&& Sonar.get0().getAttackTracker().getCurrentAttack() != null);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -38,7 +38,7 @@ public final class FallbackLoginQueue {
|
||||
private final ConcurrentMap<InetAddress, Runnable> players = new ConcurrentHashMap<>(512);
|
||||
|
||||
public void poll() {
|
||||
final int maxQueuePolls = Math.min(players.size(), Sonar.get().getConfig().getQueue().getMaxQueuePolls());
|
||||
final int maxQueuePolls = Math.min(players.size(), Sonar.get0().getConfig().getQueue().getMaxQueuePolls());
|
||||
// No need to initiate an executor service task if nobody is currently queued
|
||||
if (maxQueuePolls <= 0) return;
|
||||
// We need to be cautious here since we don't want any concurrency issues
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,23 +27,17 @@ import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public interface FallbackUser {
|
||||
@NotNull
|
||||
Channel channel();
|
||||
@NotNull Channel channel();
|
||||
|
||||
@NotNull
|
||||
InetAddress getInetAddress();
|
||||
@NotNull InetAddress getInetAddress();
|
||||
|
||||
@NotNull
|
||||
ProtocolVersion getProtocolVersion();
|
||||
@NotNull ProtocolVersion getProtocolVersion();
|
||||
|
||||
@NotNull
|
||||
SystemTimer getLoginTimer();
|
||||
@NotNull SystemTimer getLoginTimer();
|
||||
|
||||
@NotNull
|
||||
String getFingerprint();
|
||||
@NotNull String getFingerprint();
|
||||
|
||||
@NotNull
|
||||
String getUsername();
|
||||
@NotNull String getUsername();
|
||||
|
||||
boolean isForceCaptcha();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -26,52 +26,54 @@ import java.util.Map;
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum ProtocolVersion {
|
||||
UNKNOWN(-1),
|
||||
MINECRAFT_1_7_2(4),
|
||||
MINECRAFT_1_7_6(5),
|
||||
MINECRAFT_1_8(47),
|
||||
MINECRAFT_1_9(107),
|
||||
MINECRAFT_1_9_1(108),
|
||||
MINECRAFT_1_9_2(109),
|
||||
MINECRAFT_1_9_4(110),
|
||||
MINECRAFT_1_10(210),
|
||||
MINECRAFT_1_11(315),
|
||||
MINECRAFT_1_11_1(316),
|
||||
MINECRAFT_1_12(335),
|
||||
MINECRAFT_1_12_1(338),
|
||||
MINECRAFT_1_12_2(340),
|
||||
MINECRAFT_1_13(393),
|
||||
MINECRAFT_1_13_1(401),
|
||||
MINECRAFT_1_13_2(404),
|
||||
MINECRAFT_1_14(477),
|
||||
MINECRAFT_1_14_1(480),
|
||||
MINECRAFT_1_14_2(485),
|
||||
MINECRAFT_1_14_3(490),
|
||||
MINECRAFT_1_14_4(498),
|
||||
MINECRAFT_1_15(573),
|
||||
MINECRAFT_1_15_1(575),
|
||||
MINECRAFT_1_15_2(578),
|
||||
MINECRAFT_1_16(735),
|
||||
MINECRAFT_1_16_1(736),
|
||||
MINECRAFT_1_16_2(751),
|
||||
MINECRAFT_1_16_3(753),
|
||||
MINECRAFT_1_16_4(754),
|
||||
MINECRAFT_1_17(755),
|
||||
MINECRAFT_1_17_1(756),
|
||||
MINECRAFT_1_18(757),
|
||||
MINECRAFT_1_18_2(758),
|
||||
MINECRAFT_1_19(759),
|
||||
MINECRAFT_1_19_1(760),
|
||||
MINECRAFT_1_19_3(761),
|
||||
MINECRAFT_1_19_4(762),
|
||||
MINECRAFT_1_20(763),
|
||||
MINECRAFT_1_20_2(764),
|
||||
MINECRAFT_1_20_3(765),
|
||||
MINECRAFT_1_20_5(766),
|
||||
MINECRAFT_1_21(767),
|
||||
MINECRAFT_1_21_2(768);
|
||||
UNKNOWN(-1, "Unknown"),
|
||||
MINECRAFT_1_7_2(4, "1.7.2"),
|
||||
MINECRAFT_1_7_6(5, "1.7.6"),
|
||||
MINECRAFT_1_8(47, "1.8"),
|
||||
MINECRAFT_1_9(107, "1.9"),
|
||||
MINECRAFT_1_9_1(108, "1.9.1"),
|
||||
MINECRAFT_1_9_2(109, "1.9.2"),
|
||||
MINECRAFT_1_9_4(110, "1.9.3"),
|
||||
MINECRAFT_1_10(210, "1.10"),
|
||||
MINECRAFT_1_11(315, "1.11"),
|
||||
MINECRAFT_1_11_1(316, "1.11.1"),
|
||||
MINECRAFT_1_12(335, "1.12"),
|
||||
MINECRAFT_1_12_1(338, "1.12.1"),
|
||||
MINECRAFT_1_12_2(340, "1.12.2"),
|
||||
MINECRAFT_1_13(393, "1.13"),
|
||||
MINECRAFT_1_13_1(401, "1.13.1"),
|
||||
MINECRAFT_1_13_2(404, "1.13.2"),
|
||||
MINECRAFT_1_14(477, "1.14"),
|
||||
MINECRAFT_1_14_1(480, "1.14.1"),
|
||||
MINECRAFT_1_14_2(485, "1.14.2"),
|
||||
MINECRAFT_1_14_3(490, "1.14.3"),
|
||||
MINECRAFT_1_14_4(498, "1.14.4"),
|
||||
MINECRAFT_1_15(573, "1.15"),
|
||||
MINECRAFT_1_15_1(575, "1.15.1"),
|
||||
MINECRAFT_1_15_2(578, "1.15.2"),
|
||||
MINECRAFT_1_16(735, "1.16"),
|
||||
MINECRAFT_1_16_1(736, "1.16.1"),
|
||||
MINECRAFT_1_16_2(751, "1.16.2"),
|
||||
MINECRAFT_1_16_3(753, "1.16.3"),
|
||||
MINECRAFT_1_16_4(754, "1.16.4"),
|
||||
MINECRAFT_1_17(755, "1.17"),
|
||||
MINECRAFT_1_17_1(756, "1.17.1"),
|
||||
MINECRAFT_1_18(757, "1.18"),
|
||||
MINECRAFT_1_18_2(758, "1.18.2"),
|
||||
MINECRAFT_1_19(759, "1.19"),
|
||||
MINECRAFT_1_19_1(760, "1.19.1"),
|
||||
MINECRAFT_1_19_3(761, "1.19.3"),
|
||||
MINECRAFT_1_19_4(762, "1.19.4"),
|
||||
MINECRAFT_1_20(763, "1.20"),
|
||||
MINECRAFT_1_20_2(764, "1.20.2"),
|
||||
MINECRAFT_1_20_3(765, "1.20.3"),
|
||||
MINECRAFT_1_20_5(766, "1.20.5"),
|
||||
MINECRAFT_1_21(767, "1.21"),
|
||||
MINECRAFT_1_21_2(768, "1.21.2"),
|
||||
MINECRAFT_1_21_4(769, "1.21.4");
|
||||
|
||||
private final int protocol;
|
||||
private final String name;
|
||||
|
||||
public static final ProtocolVersion LATEST_VERSION;
|
||||
public static final Map<Integer, ProtocolVersion> ID_TO_PROTOCOL_CONSTANT;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+20
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,29 +44,29 @@ public final class ActionBarNotificationHandler extends NotificationHandler {
|
||||
}
|
||||
|
||||
// Prepare the action bar verbose
|
||||
final AttackTracker.AttackStatistics attackStatistics = Sonar.get().getAttackTracker().getCurrentAttack();
|
||||
final AttackTracker.AttackStatistics attackStatistics = Sonar.get0().getAttackTracker().getCurrentAttack();
|
||||
final SystemTimer attackTimer = attackStatistics == null ? null : attackStatistics.getDuration();
|
||||
final String attackDuration = attackTimer == null ? "00:00" : DATE_FORMATTER.format(attackTimer.delay());
|
||||
|
||||
final Component actionBarComponent = MiniMessage.miniMessage().deserialize(attackTimer == null
|
||||
? Sonar.get().getConfig().getMessagesConfig().getString("verbose.layout.normal")
|
||||
: Sonar.get().getConfig().getMessagesConfig().getString("verbose.layout.attack"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix()),
|
||||
? Sonar.get0().getConfig().getMessagesConfig().getString("verbose.layout.normal")
|
||||
: Sonar.get0().getConfig().getMessagesConfig().getString("verbose.layout.attack"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
|
||||
Placeholder.unparsed("attack-duration", attackDuration),
|
||||
Placeholder.unparsed("animation", nextAnimation()),
|
||||
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get().getFallback().getQueue().getPlayers().size())),
|
||||
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get().getFallback().getConnected().size())),
|
||||
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get().getFallback().getBlacklist().estimatedSize())),
|
||||
Placeholder.unparsed("total-joins", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalPlayersJoined())),
|
||||
Placeholder.unparsed("logins-per-second", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getLoginsPerSecond())),
|
||||
Placeholder.unparsed("connections-per-second", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getConnectionsPerSecond())),
|
||||
Placeholder.unparsed("verify-total", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalAttemptedVerifications())),
|
||||
Placeholder.unparsed("verify-success", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalSuccessfulVerifications())),
|
||||
Placeholder.unparsed("verify-failed", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalFailedVerifications())),
|
||||
Placeholder.unparsed("incoming-traffic", Sonar.get().getStatistics().getPerSecondIncomingBandwidthFormatted()),
|
||||
Placeholder.unparsed("outgoing-traffic", Sonar.get().getStatistics().getPerSecondOutgoingBandwidthFormatted()),
|
||||
Placeholder.unparsed("incoming-traffic-ttl", formatMemory(Sonar.get().getStatistics().getTotalIncomingBandwidth())),
|
||||
Placeholder.unparsed("outgoing-traffic-ttl", formatMemory(Sonar.get().getStatistics().getTotalOutgoingBandwidth())),
|
||||
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getQueue().getPlayers().size())),
|
||||
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getConnected().size())),
|
||||
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getBlacklist().estimatedSize())),
|
||||
Placeholder.unparsed("total-joins", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalPlayersJoined())),
|
||||
Placeholder.unparsed("logins-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getLoginsPerSecond())),
|
||||
Placeholder.unparsed("connections-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getConnectionsPerSecond())),
|
||||
Placeholder.unparsed("verify-total", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalAttemptedVerifications())),
|
||||
Placeholder.unparsed("verify-success", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalSuccessfulVerifications())),
|
||||
Placeholder.unparsed("verify-failed", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalFailedVerifications())),
|
||||
Placeholder.unparsed("incoming-traffic", Sonar.get0().getStatistics().getPerSecondIncomingBandwidthFormatted()),
|
||||
Placeholder.unparsed("outgoing-traffic", Sonar.get0().getStatistics().getPerSecondOutgoingBandwidthFormatted()),
|
||||
Placeholder.unparsed("incoming-traffic-ttl", formatMemory(Sonar.get0().getStatistics().getTotalIncomingBandwidth())),
|
||||
Placeholder.unparsed("outgoing-traffic-ttl", formatMemory(Sonar.get0().getStatistics().getTotalOutgoingBandwidth())),
|
||||
Placeholder.unparsed("used-memory", formatMemory(getUsedMemory())),
|
||||
Placeholder.unparsed("free-memory", formatMemory(getFreeMemory())),
|
||||
Placeholder.unparsed("total-memory", formatMemory(getTotalMemory())),
|
||||
@@ -74,7 +74,7 @@ public final class ActionBarNotificationHandler extends NotificationHandler {
|
||||
|
||||
// Send the action bar to all online players
|
||||
for (final UUID subscriber : subscribers) {
|
||||
final Audience audience = Sonar.get().audience(subscriber);
|
||||
final Audience audience = Sonar.get0().audience(subscriber);
|
||||
if (audience == null) continue;
|
||||
|
||||
// Send the action bar to all online subscribers
|
||||
@@ -83,7 +83,7 @@ public final class ActionBarNotificationHandler extends NotificationHandler {
|
||||
}
|
||||
|
||||
public String nextAnimation() {
|
||||
final var animations = Sonar.get().getConfig().getVerboseAnimation();
|
||||
final var animations = Sonar.get0().getConfig().getVerboseAnimation();
|
||||
final int nextIndex = ++animationIndex % animations.size();
|
||||
return animations.toArray(new String[0])[nextIndex];
|
||||
}
|
||||
|
||||
+20
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,30 +43,30 @@ public final class ChatNotificationHandler extends NotificationHandler {
|
||||
|
||||
// Prepare the chat notification
|
||||
final Component notificationTitle = MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("notifications.title"));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("notifications.title"));
|
||||
final Component notificationSubtitle = MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("notifications.subtitle"));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("notifications.subtitle"));
|
||||
final Title title = Title.title(notificationTitle, notificationSubtitle);
|
||||
|
||||
final List<String> chatNotification = Sonar.get().getConfig().getMessagesConfig().getStringList("notifications.chat");
|
||||
final List<String> chatNotification = Sonar.get0().getConfig().getMessagesConfig().getStringList("notifications.chat");
|
||||
final Component[] chatNotificationComponents = new Component[chatNotification.size()];
|
||||
|
||||
for (int i = 0; i < chatNotificationComponents.length; i++) {
|
||||
chatNotificationComponents[i] = MiniMessage.miniMessage().deserialize(chatNotification.get(i),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix()),
|
||||
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get().getFallback().getQueue().getPlayers().size())),
|
||||
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get().getFallback().getConnected().size())),
|
||||
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get().getFallback().getBlacklist().estimatedSize())),
|
||||
Placeholder.unparsed("total-joins", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalPlayersJoined())),
|
||||
Placeholder.unparsed("logins-per-second", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getLoginsPerSecond())),
|
||||
Placeholder.unparsed("connections-per-second", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getConnectionsPerSecond())),
|
||||
Placeholder.unparsed("verify-total", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalAttemptedVerifications())),
|
||||
Placeholder.unparsed("verify-success", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalSuccessfulVerifications())),
|
||||
Placeholder.unparsed("verify-failed", DECIMAL_FORMAT.format(Sonar.get().getStatistics().getTotalFailedVerifications())),
|
||||
Placeholder.unparsed("incoming-traffic", Sonar.get().getStatistics().getPerSecondIncomingBandwidthFormatted()),
|
||||
Placeholder.unparsed("outgoing-traffic", Sonar.get().getStatistics().getPerSecondOutgoingBandwidthFormatted()),
|
||||
Placeholder.unparsed("incoming-traffic-ttl", formatMemory(Sonar.get().getStatistics().getTotalIncomingBandwidth())),
|
||||
Placeholder.unparsed("outgoing-traffic-ttl", formatMemory(Sonar.get().getStatistics().getTotalOutgoingBandwidth())),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix()),
|
||||
Placeholder.unparsed("queued", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getQueue().getPlayers().size())),
|
||||
Placeholder.unparsed("verifying", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getConnected().size())),
|
||||
Placeholder.unparsed("blacklisted", DECIMAL_FORMAT.format(Sonar.get0().getFallback().getBlacklist().estimatedSize())),
|
||||
Placeholder.unparsed("total-joins", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalPlayersJoined())),
|
||||
Placeholder.unparsed("logins-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getLoginsPerSecond())),
|
||||
Placeholder.unparsed("connections-per-second", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getConnectionsPerSecond())),
|
||||
Placeholder.unparsed("verify-total", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalAttemptedVerifications())),
|
||||
Placeholder.unparsed("verify-success", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalSuccessfulVerifications())),
|
||||
Placeholder.unparsed("verify-failed", DECIMAL_FORMAT.format(Sonar.get0().getStatistics().getTotalFailedVerifications())),
|
||||
Placeholder.unparsed("incoming-traffic", Sonar.get0().getStatistics().getPerSecondIncomingBandwidthFormatted()),
|
||||
Placeholder.unparsed("outgoing-traffic", Sonar.get0().getStatistics().getPerSecondOutgoingBandwidthFormatted()),
|
||||
Placeholder.unparsed("incoming-traffic-ttl", formatMemory(Sonar.get0().getStatistics().getTotalIncomingBandwidth())),
|
||||
Placeholder.unparsed("outgoing-traffic-ttl", formatMemory(Sonar.get0().getStatistics().getTotalOutgoingBandwidth())),
|
||||
Placeholder.unparsed("used-memory", formatMemory(getUsedMemory())),
|
||||
Placeholder.unparsed("free-memory", formatMemory(getFreeMemory())),
|
||||
Placeholder.unparsed("total-memory", formatMemory(getTotalMemory())),
|
||||
@@ -74,8 +74,8 @@ public final class ChatNotificationHandler extends NotificationHandler {
|
||||
}
|
||||
|
||||
// Send the title and chat messages to all online players
|
||||
for (final UUID subscriber : Sonar.get().getChatNotificationHandler().getSubscribers()) {
|
||||
final Audience audience = Sonar.get().audience(subscriber);
|
||||
for (final UUID subscriber : Sonar.get0().getChatNotificationHandler().getSubscribers()) {
|
||||
final Audience audience = Sonar.get0().audience(subscriber);
|
||||
if (audience == null) continue;
|
||||
|
||||
// Send the message to all online subscribers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -52,10 +52,10 @@ public final class AttackTracker {
|
||||
}
|
||||
|
||||
public void checkIfUnderAttack() {
|
||||
final long joinsPerSecond = Sonar.get().getStatistics().getLoginsPerSecond();
|
||||
final int verifyingPlayers = Sonar.get().getFallback().getConnected().size();
|
||||
final int queuedPlayers = Sonar.get().getFallback().getQueue().getPlayers().size();
|
||||
final int minPlayers = Sonar.get().getConfig().getMinPlayersForAttack();
|
||||
final long joinsPerSecond = Sonar.get0().getStatistics().getLoginsPerSecond();
|
||||
final int verifyingPlayers = Sonar.get0().getFallback().getConnected().size();
|
||||
final int queuedPlayers = Sonar.get0().getFallback().getQueue().getPlayers().size();
|
||||
final int minPlayers = Sonar.get0().getConfig().getMinPlayersForAttack();
|
||||
|
||||
if (joinsPerSecond > minPlayers // Check the number of bots/joins per second.
|
||||
|| verifyingPlayers > minPlayers // Check the number of verifying players.
|
||||
@@ -66,10 +66,10 @@ public final class AttackTracker {
|
||||
// An attack has been detected
|
||||
if (currentAttack == null) {
|
||||
currentAttack = new AttackStatistics();
|
||||
currentAttack.successfulVerifications = Sonar.get().getVerifiedPlayerController().getCache().size();
|
||||
currentAttack.failedVerifications = Sonar.get().getStatistics().getTotalFailedVerifications();
|
||||
Sonar.get().getEventManager().publish(new AttackDetectedEvent());
|
||||
Sonar.get().getChatNotificationHandler().handleNotification();
|
||||
currentAttack.successfulVerifications = Sonar.get0().getVerifiedPlayerController().getCache().size();
|
||||
currentAttack.failedVerifications = Sonar.get0().getStatistics().getTotalFailedVerifications();
|
||||
Sonar.get0().getEventManager().publish(new AttackDetectedEvent());
|
||||
Sonar.get0().getChatNotificationHandler().handleNotification();
|
||||
} else {
|
||||
// Reset attack timer if we're still under attack
|
||||
currentAttack.timer.reset();
|
||||
@@ -80,7 +80,7 @@ public final class AttackTracker {
|
||||
// Update joins per second peak if necessary
|
||||
currentAttack.peakJoinsPerSecond = joinsPerSecond;
|
||||
}
|
||||
final long connectionsPerSecond = Sonar.get().getStatistics().getConnectionsPerSecond();
|
||||
final long connectionsPerSecond = Sonar.get0().getStatistics().getConnectionsPerSecond();
|
||||
if (connectionsPerSecond > currentAttack.peakConnectionsPerSecond) {
|
||||
// Update connections per second peak if necessary
|
||||
currentAttack.peakConnectionsPerSecond = connectionsPerSecond;
|
||||
@@ -96,14 +96,14 @@ public final class AttackTracker {
|
||||
currentAttack.peakProcessMemoryUsage = processMemoryUsage;
|
||||
}
|
||||
} else if (currentAttack != null) {
|
||||
if (currentAttack.duration.delay() > Sonar.get().getConfig().getMinAttackDuration()
|
||||
&& currentAttack.timer.delay() > Sonar.get().getConfig().getAttackCooldownDelay()) {
|
||||
if (currentAttack.duration.delay() > Sonar.get0().getConfig().getMinAttackDuration()
|
||||
&& currentAttack.timer.delay() > Sonar.get0().getConfig().getAttackCooldownDelay()) {
|
||||
// The current attack has stopped
|
||||
Sonar.get().getEventManager().publish(new AttackMitigatedEvent(currentAttack));
|
||||
Sonar.get0().getEventManager().publish(new AttackMitigatedEvent(currentAttack));
|
||||
|
||||
if (++attackThreshold > Sonar.get().getConfig().getMinAttackThreshold()) {
|
||||
if (++attackThreshold > Sonar.get0().getConfig().getMinAttackThreshold()) {
|
||||
// Post webhook to Discord
|
||||
Optional.ofNullable(Sonar.get().getConfig().getWebhook().getDiscordWebhook())
|
||||
Optional.ofNullable(Sonar.get0().getConfig().getWebhook().getDiscordWebhook())
|
||||
.ifPresent(webhook -> {
|
||||
// Save attack statistics
|
||||
final long deltaInMillis = currentAttack.duration.delay();
|
||||
@@ -116,15 +116,15 @@ public final class AttackTracker {
|
||||
final String formattedDuration = String.format("%d minutes, %.0f seconds", minutes, seconds);
|
||||
final String startTimestamp = String.valueOf(currentAttack.duration.getStart() / 1000L);
|
||||
final String endTimestamp = String.valueOf(System.currentTimeMillis() / 1000L);
|
||||
final long blacklisted = Sonar.get().getFallback().getBlacklist().estimatedSize();
|
||||
final long blacklisted = Sonar.get0().getFallback().getBlacklist().estimatedSize();
|
||||
// Calculate during-attack-statistics using their deltas
|
||||
final long totalVerified = Sonar.get().getVerifiedPlayerController().getCache().size();
|
||||
final long totalVerified = Sonar.get0().getVerifiedPlayerController().getCache().size();
|
||||
final long verified = Math.max(totalVerified - currentAttack.successfulVerifications, 0);
|
||||
final long totalFailed = Sonar.get().getStatistics().getTotalFailedVerifications();
|
||||
final long totalFailed = Sonar.get0().getStatistics().getTotalFailedVerifications();
|
||||
final long failed = Math.max(totalFailed - currentAttack.failedVerifications, 0);
|
||||
|
||||
webhook.post(() -> {
|
||||
final SonarConfiguration.Webhook.Embed config = Sonar.get().getConfig().getWebhook().getEmbed();
|
||||
final SonarConfiguration.Webhook.Embed config = Sonar.get0().getConfig().getWebhook().getEmbed();
|
||||
final String description = config.getDescription()
|
||||
.replace("<start-timestamp>", startTimestamp)
|
||||
.replace("<end-timestamp>", endTimestamp)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -48,23 +48,23 @@ public class UpdateChecker {
|
||||
final JsonObject json = parseJson(urlConnection);
|
||||
final String latestStableRelease = json.get("tag_name").getAsString();
|
||||
final int convertedLatestVersion = convertVersion(latestStableRelease);
|
||||
final int convertedCurrentVersion = convertVersion(Sonar.get().getVersion().getVersion());
|
||||
final int convertedCurrentVersion = convertVersion(Sonar.get0().getVersion().getVersion());
|
||||
|
||||
if (convertedCurrentVersion < convertedLatestVersion) {
|
||||
Sonar.get().getLogger().warn("A new version of Sonar is available: {}", latestStableRelease);
|
||||
Sonar.get().getLogger().warn("Please make sure to update to the latest version to ensure stability and security:");
|
||||
Sonar.get().getLogger().warn("https://github.com/jonesdevelopment/sonar/releases/latest");
|
||||
Sonar.get0().getLogger().warn("A new version of Sonar is available: {}", latestStableRelease);
|
||||
Sonar.get0().getLogger().warn("Please make sure to update to the latest version to ensure stability and security:");
|
||||
Sonar.get0().getLogger().warn("https://github.com/jonesdevelopment/sonar/releases/latest");
|
||||
lastCheckResult = CheckResult.OUTDATED_VERSION;
|
||||
} else if (convertedCurrentVersion > convertedLatestVersion || !Sonar.get().getVersion().getGitBranch().equals("main")) {
|
||||
Sonar.get().getLogger().warn("You are currently using an unreleased version of Sonar!");
|
||||
Sonar.get().getLogger().warn("The contributors of Sonar are not responsible for any damage done by using an unstable version");
|
||||
} else if (convertedCurrentVersion > convertedLatestVersion || !Sonar.get0().getVersion().getGitBranch().equals("main")) {
|
||||
Sonar.get0().getLogger().warn("You are currently using an unreleased version of Sonar!");
|
||||
Sonar.get0().getLogger().warn("The contributors of Sonar are not responsible for any damage done by using an unstable version");
|
||||
lastCheckResult = CheckResult.UNSTABLE_VERSION;
|
||||
} else if (lastCheckResult != CheckResult.LATEST_VERSION) {
|
||||
Sonar.get().getLogger().info("You are currently using the latest stable release of Sonar!");
|
||||
Sonar.get0().getLogger().info("You are currently using the latest stable release of Sonar!");
|
||||
lastCheckResult = CheckResult.LATEST_VERSION;
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().warn("Unable to retrieve version information: {}", throwable);
|
||||
Sonar.get0().getLogger().warn("Unable to retrieve version information: {}", throwable);
|
||||
lastCheckResult = CheckResult.API_ERROR;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -59,18 +59,18 @@ public final class DiscordWebhook {
|
||||
// Discord replies with HTTP_NO_CONTENT (204) if the request is successful
|
||||
final int code = urlConnection.getResponseCode();
|
||||
if (code != HTTP_NO_CONTENT) {
|
||||
Sonar.get().getLogger().warn("Unexpected Discord webhook response code {}", code);
|
||||
Sonar.get0().getLogger().warn("Unexpected Discord webhook response code {}", code);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Sonar.get().getLogger().error("Could not send webhook: {}", exception);
|
||||
Sonar.get0().getLogger().error("Could not send webhook: {}", exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String prepareSerializedContent(final SonarConfiguration.Webhook.@NotNull Embed embed) {
|
||||
final String content = Sonar.get().getConfig().getWebhook().getContent();
|
||||
final String username = Sonar.get().getConfig().getWebhook().getUsername();
|
||||
final String avatarUrl = Sonar.get().getConfig().getWebhook().getAvatarUrl();
|
||||
final String content = Sonar.get0().getConfig().getWebhook().getContent();
|
||||
final String username = Sonar.get0().getConfig().getWebhook().getUsername();
|
||||
final String avatarUrl = Sonar.get0().getConfig().getWebhook().getAvatarUrl();
|
||||
|
||||
int rgb = embed.getR();
|
||||
rgb = (rgb << 8) + embed.getG();
|
||||
@@ -78,8 +78,8 @@ public final class DiscordWebhook {
|
||||
|
||||
final Webhook.EmbedMessage embedMessage = new Webhook.EmbedMessage(
|
||||
embed.getTitle(), embed.getDescription(), embed.getTitleUrl(), rgb, new Webhook.Field[0],
|
||||
new Webhook.Footer(Sonar.get().getConfig().getWebhook().getFooter().getText(),
|
||||
Sonar.get().getConfig().getWebhook().getFooter().getIconUrl()));
|
||||
new Webhook.Footer(Sonar.get0().getConfig().getWebhook().getFooter().getText(),
|
||||
Sonar.get0().getConfig().getWebhook().getFooter().getIconUrl()));
|
||||
final List<Webhook.EmbedMessage> embeds = Collections.singletonList(embedMessage);
|
||||
|
||||
final Webhook webhook = new Webhook(content, username, avatarUrl, false, embeds);
|
||||
|
||||
+17
-2
@@ -3,7 +3,8 @@ import net.kyori.indra.git.IndraGitExtension
|
||||
plugins {
|
||||
java
|
||||
alias(libs.plugins.shadow)
|
||||
alias(libs.plugins.indra.git) apply true
|
||||
alias(libs.plugins.indra.git)
|
||||
alias(libs.plugins.spotless)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@@ -15,6 +16,7 @@ allprojects {
|
||||
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
apply(plugin = "com.diffplug.spotless")
|
||||
|
||||
dependencies {
|
||||
compileOnly(rootProject.libs.lombok)
|
||||
@@ -31,6 +33,16 @@ allprojects {
|
||||
compileOnly(rootProject.libs.libby.core)
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
endWithNewline()
|
||||
formatAnnotations()
|
||||
removeUnusedImports()
|
||||
trimTrailingWhitespace()
|
||||
indentWithSpaces(2)
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
// Set the file name of the shadowed jar
|
||||
@@ -80,6 +92,9 @@ allprojects {
|
||||
attributes["Git-Commit"] = gitCommit
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +102,7 @@ tasks {
|
||||
// This is a small wrapper tasks to simplify the building process
|
||||
register("build-sonar") {
|
||||
val subprojects = listOf("api", "captcha", "common", "bukkit", "bungeecord", "velocity")
|
||||
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:shadowJar") }
|
||||
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:spotlessApply", "$it:shadowJar") }
|
||||
dependsOn(buildTasks)
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,3 @@ tasks {
|
||||
relocate("net.kyori", "xyz.jonesdev.sonar.libs.kyori")
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -40,7 +40,7 @@ public final class BukkitSonarCommand implements CommandExecutor, TabExecutor, S
|
||||
// Create our own invocation source wrapper to handle messages properly
|
||||
final InvocationSource invocationSource = new InvocationSource(
|
||||
sender instanceof Player ? ((Player) sender).getUniqueId() : null,
|
||||
Sonar.get().sender(sender),
|
||||
Sonar.get0().sender(sender),
|
||||
sender::hasPermission);
|
||||
// Pass the invocation source and command arguments to our command handler
|
||||
handle(invocationSource, args);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -70,7 +70,11 @@ public enum BukkitServerVersion {
|
||||
MINECRAFT_1_20_4,
|
||||
MINECRAFT_1_20_5,
|
||||
MINECRAFT_1_20_6,
|
||||
MINECRAFT_1_21;
|
||||
MINECRAFT_1_21,
|
||||
MINECRAFT_1_21_1,
|
||||
MINECRAFT_1_21_2,
|
||||
MINECRAFT_1_21_3,
|
||||
MINECRAFT_1_21_4;
|
||||
|
||||
static final BukkitServerVersion[] REVERSED_VALUES;
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -267,7 +267,7 @@ public class FallbackBukkitInjector {
|
||||
return;
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Sonar.get().getLogger().error("An error occurred while injecting {}", exception);
|
||||
Sonar.get0().getLogger().error("An error occurred while injecting {}", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -92,7 +92,7 @@ public final class BukkitJoinListener implements Listener {
|
||||
channel.close();
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().warn("Couldn't find {}: {}", event.getPlayer().getName(), throwable);
|
||||
Sonar.get0().getLogger().warn("Couldn't find {}: {}", event.getPlayer().getName(), throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,3 @@ tasks {
|
||||
archiveFileName = "Sonar-Bungee.jar" // Hardcode a shortened version of the name
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -86,6 +86,10 @@ public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
// Add warning because of questionable design choices that haunt me in my dreams.
|
||||
logger.warn("The use of BungeeCord is supported but not condoned.");
|
||||
logger.warn("Consider upgrading to Velocity (https://velocitypowered.com)");
|
||||
|
||||
// Initialize bStats.org metrics
|
||||
metrics = new Metrics(getPlugin(), getPlatform().getMetricsId());
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -38,7 +38,7 @@ public final class BungeeSonarCommand extends Command implements TabExecutor, So
|
||||
// Create our own invocation source wrapper to handle messages properly
|
||||
final InvocationSource invocationSource = new InvocationSource(
|
||||
sender instanceof ProxiedPlayer ? ((ProxiedPlayer) sender).getUniqueId() : null,
|
||||
Sonar.get().sender(sender),
|
||||
Sonar.get0().sender(sender),
|
||||
sender::hasPermission);
|
||||
// Pass the invocation source and command arguments to our command handler
|
||||
handle(invocationSource, args);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+56
-19
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,11 @@ package xyz.jonesdev.sonar.bungee.fallback;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.val;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.protocol.channel.BungeeChannelInitializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import sun.misc.Unsafe;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackInjectedChannelInitializer;
|
||||
@@ -34,26 +38,59 @@ import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_PACKET_
|
||||
public class FallbackBungeeInjector {
|
||||
public void inject() {
|
||||
try {
|
||||
final Field childField = PipelineUtils.class.getField("SERVER_CHILD");
|
||||
final Field childField;
|
||||
|
||||
try {
|
||||
// This field only exists on BungeeCord build 1908 and below.
|
||||
// See https://github.com/SpigotMC/BungeeCord/pull/3776 for more info.
|
||||
//noinspection all
|
||||
childField = PipelineUtils.class.getField("SERVER_CHILD");
|
||||
} catch (NoSuchFieldException exception) {
|
||||
injectOnModernBungeeCord();
|
||||
return;
|
||||
}
|
||||
|
||||
childField.setAccessible(true);
|
||||
|
||||
// Make sure to store the original channel initializer
|
||||
final ChannelInitializer<Channel> originalInitializer = PipelineUtils.SERVER_CHILD;
|
||||
final ChannelInitializer<Channel> injectedInitializer = new FallbackInjectedChannelInitializer(
|
||||
originalInitializer, pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
|
||||
new FallbackBungeeInboundHandler()));
|
||||
|
||||
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
final Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
|
||||
final Object base = unsafe.staticFieldBase(childField);
|
||||
final long offset = unsafe.staticFieldOffset(childField);
|
||||
|
||||
// Replace the original channel initializer with our new injected initializer
|
||||
unsafe.putObject(base, offset, injectedInitializer);
|
||||
injectOnOldBungeeCord(childField);
|
||||
} catch (Exception exception) {
|
||||
Sonar.get().getLogger().error("An error occurred while injecting {}", exception);
|
||||
Sonar.get0().getLogger().error("An error occurred while injecting {}", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static void injectOnOldBungeeCord(final @NotNull Field childField) throws Exception {
|
||||
// Make sure to store the original channel initializer
|
||||
//noinspection unchecked
|
||||
val originalInitializer = (ChannelInitializer<Channel>) childField.get(null);
|
||||
final ChannelInitializer<Channel> injectedInitializer = new FallbackInjectedChannelInitializer(
|
||||
originalInitializer, pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
|
||||
new FallbackBungeeInboundHandler()));
|
||||
|
||||
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
final Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
|
||||
final Object base = unsafe.staticFieldBase(childField);
|
||||
final long offset = unsafe.staticFieldOffset(childField);
|
||||
|
||||
// Replace the original channel initializer with our new injected initializer
|
||||
unsafe.putObject(base, offset, injectedInitializer);
|
||||
}
|
||||
|
||||
// See https://github.com/SpigotMC/BungeeCord/pull/3787
|
||||
private static void injectOnModernBungeeCord() {
|
||||
// The order is important...
|
||||
final BungeeChannelInitializer original = ProxyServer.getInstance().unsafe().getFrontendChannelInitializer();
|
||||
final BungeeChannelInitializer newInitializer = BungeeChannelInitializer.create(
|
||||
channel -> {
|
||||
// https://github.com/SpigotMC/BungeeCord/pull/3787#issuecomment-2661059876
|
||||
if (!original.getChannelAcceptor().accept(channel)) {
|
||||
return false;
|
||||
}
|
||||
FallbackInjectedChannelInitializer.inject(channel,
|
||||
pipeline -> pipeline.addAfter(PACKET_DECODER, FALLBACK_PACKET_HANDLER,
|
||||
new FallbackBungeeInboundHandler()));
|
||||
return true;
|
||||
});
|
||||
ProxyServer.getInstance().unsafe().setFrontendChannelInitializer(newInitializer);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,3 @@ dependencies {
|
||||
testCompileOnly(project(":api"))
|
||||
testCompileOnly(rootProject.libs.imagefilters)
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -3,6 +3,3 @@ dependencies {
|
||||
implementation(project(":captcha"))
|
||||
compileOnly(rootProject.libs.adventure.nbt)
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -47,7 +47,7 @@ class LibraryLoader {
|
||||
Library.builder()
|
||||
.groupId("com{}github{}ben-manes{}caffeine")
|
||||
.artifactId("caffeine")
|
||||
.version("3.1.8")
|
||||
.version("3.2.0")
|
||||
.relocate("com{}github{}benmanes{}caffeine", "xyz{}jonesdev{}sonar{}libs{}caffeine")
|
||||
.build(),
|
||||
// ORMLite
|
||||
@@ -72,19 +72,19 @@ class LibraryLoader {
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-minimessage")
|
||||
.version("4.17.0")
|
||||
.version("4.13.1") // adventure-platforms hasn't updated in years... Please update! :'(
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-text-serializer-gson")
|
||||
.version("4.17.0")
|
||||
.version("4.18.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build(),
|
||||
Library.builder()
|
||||
.groupId("net{}kyori")
|
||||
.artifactId("adventure-nbt")
|
||||
.version("4.17.0")
|
||||
.version("4.18.0")
|
||||
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
|
||||
.build()
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -55,11 +55,11 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
// Account for this by checking if the inetAddress has been set yet
|
||||
if (inetAddress != null) {
|
||||
// Remove the IP address from the queue
|
||||
Sonar.get().getFallback().getQueue().getPlayers().compute(inetAddress, (ignored, action) -> {
|
||||
Sonar.get0().getFallback().getQueue().getPlayers().compute(inetAddress, (ignored, action) -> {
|
||||
// The player is not queued, so we need to remove them from other maps as well
|
||||
if (action == null) {
|
||||
// Remove the IP address from the connected players, if needed
|
||||
Sonar.get().getFallback().getConnected().compute(inetAddress, (__, v) -> {
|
||||
Sonar.get0().getFallback().getConnected().compute(inetAddress, (__, v) -> {
|
||||
/*
|
||||
* Remove this account from the online players or decrement the number of accounts
|
||||
* with the same IP, but only if the player is logging into the backend server.
|
||||
@@ -67,7 +67,7 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
* we've never actually incremented it in the first place ¯\_(ツ)_/¯
|
||||
*/
|
||||
if (v == null) {
|
||||
Sonar.get().getFallback().getOnline().compute(inetAddress,
|
||||
Sonar.get0().getFallback().getOnline().compute(inetAddress,
|
||||
(ignored1, count) -> count == null || count <= 1 ? null : count - 1);
|
||||
}
|
||||
return null;
|
||||
@@ -83,8 +83,7 @@ public final class FallbackInboundHandler extends ChannelInboundHandlerAdapter {
|
||||
* will run before the connection knows that there has been an error.
|
||||
*/
|
||||
@Override
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx,
|
||||
final Throwable cause) throws Exception {
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
+30
-30
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -28,6 +28,7 @@ import xyz.jonesdev.sonar.api.fingerprint.FingerprintingUtil;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackTimeoutHandler;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.util.GeyserUtil;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
@@ -73,39 +74,45 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
final @NotNull Runnable initialLoginAction,
|
||||
final @NotNull String username,
|
||||
final @NotNull InetSocketAddress socketAddress) throws Exception {
|
||||
// Check if the player has already sent a login packet
|
||||
if (this.username != null) {
|
||||
// Count every single attempted login
|
||||
GlobalSonarStatistics.countLogin();
|
||||
// Ensure that the player sent a handshake packet
|
||||
if (protocolVersion == null) {
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
// Connections from unknown protocol versions will be discarded
|
||||
// as this is the safest way of handling unwanted connections.
|
||||
// Sonar does not support snapshots or Minecraft versions older than 1.7.2
|
||||
if (protocolVersion.isUnknown()) {
|
||||
customDisconnect(ctx.channel(), unsupportedVersion, ProtocolVersion.MINECRAFT_1_7_2);
|
||||
return;
|
||||
}
|
||||
// Ensure that the player has not sent a login packet yet
|
||||
if (this.username != null) {
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
GlobalSonarStatistics.countLogin();
|
||||
this.username = username;
|
||||
|
||||
final InetAddress inetAddress = socketAddress.getAddress();
|
||||
ctx.pipeline().get(FallbackInboundHandler.class).setInetAddress(inetAddress);
|
||||
|
||||
// Check if Fallback is already verifying a player with the same IP address
|
||||
if (Sonar.get().getFallback().getConnected().containsKey(inetAddress)) {
|
||||
if (Sonar.get0().getFallback().getConnected().containsKey(inetAddress)) {
|
||||
customDisconnect(ctx.channel(), alreadyVerifying, protocolVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the protocol ID of the player is not allowed to enter the server
|
||||
if (Sonar.get().getConfig().getVerification().getBlacklistedProtocols().contains(protocolVersion.getProtocol())) {
|
||||
if (Sonar.get0().getConfig().getVerification().getBlacklistedProtocols().contains(protocolVersion.getProtocol())) {
|
||||
customDisconnect(ctx.channel(), protocolBlacklisted, protocolVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
final String hostAddress = inetAddress.getHostAddress();
|
||||
// Check if the player failed the verification too many times
|
||||
final int limit = Sonar.get().getConfig().getVerification().getBlacklistThreshold();
|
||||
final int limit = Sonar.get0().getConfig().getVerification().getBlacklistThreshold();
|
||||
if (limit > 0) {
|
||||
final int score = Sonar.get().getFallback().getBlacklist().asMap().getOrDefault(hostAddress, 0);
|
||||
final int score = Sonar.get0().getFallback().getBlacklist().asMap().getOrDefault(hostAddress, 0);
|
||||
if (score >= limit) {
|
||||
customDisconnect(ctx.channel(), blacklisted, protocolVersion);
|
||||
return;
|
||||
@@ -113,27 +120,27 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
}
|
||||
|
||||
// Don't continue the verification process if the verification is disabled
|
||||
if (!Sonar.get().getFallback().shouldVerifyNewPlayers()) {
|
||||
if (!Sonar.get0().getFallback().shouldVerifyNewPlayers()) {
|
||||
initialLogin(ctx.channel(), inetAddress, initialLoginAction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Completely skip Geyser connections if configured
|
||||
final boolean geyser = GeyserUtil.isGeyserConnection(ctx.channel(), socketAddress);
|
||||
if (geyser && !Sonar.get().getConfig().getVerification().isCheckGeyser()) {
|
||||
if (geyser && !Sonar.get0().getConfig().getVerification().isCheckGeyser()) {
|
||||
initialLogin(ctx.channel(), inetAddress, initialLoginAction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we actually have to verify the player
|
||||
final String fingerprint = FingerprintingUtil.getFingerprint(username, hostAddress);
|
||||
if (Sonar.get().getVerifiedPlayerController().getCache().contains(fingerprint)) {
|
||||
if (Sonar.get0().getVerifiedPlayerController().getCache().contains(fingerprint)) {
|
||||
initialLogin(ctx.channel(), inetAddress, initialLoginAction);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the IP address is currently being rate-limited
|
||||
if (!Sonar.get().getFallback().getRatelimiter().attempt(inetAddress)) {
|
||||
if (!Sonar.get0().getFallback().getRatelimiter().attempt(inetAddress)) {
|
||||
customDisconnect(ctx.channel(), reconnectedTooFast, protocolVersion);
|
||||
return;
|
||||
}
|
||||
@@ -142,7 +149,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
rewriteProtocol(ctx, channelRemovalListener);
|
||||
|
||||
// Queue the connection for further processing
|
||||
Sonar.get().getFallback().getQueue().getPlayers().compute(inetAddress, (__, runnable) -> {
|
||||
Sonar.get0().getFallback().getQueue().getPlayers().compute(inetAddress, (__, runnable) -> {
|
||||
// Check if the player is already queued since we don't want bots to flood the queue
|
||||
if (runnable != null) {
|
||||
customDisconnect(ctx.channel(), alreadyQueued, protocolVersion);
|
||||
@@ -150,17 +157,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
return null;
|
||||
}
|
||||
|
||||
return () -> {
|
||||
// Check if the username matches the valid name regex to prevent
|
||||
// UTF-16 names or other types of exploits
|
||||
if (!Sonar.get().getConfig().getVerification().getValidNameRegex().matcher(username).matches()) {
|
||||
customDisconnect(ctx.channel(), invalidUsername, protocolVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an instance for the user and let the verification handler take over the channel
|
||||
new FallbackUserWrapper(ctx.channel(), inetAddress, protocolVersion, username, fingerprint, geyser);
|
||||
};
|
||||
// Create an instance for the user and let the verification handler take over the channel
|
||||
return () -> new FallbackUserWrapper(ctx, inetAddress, protocolVersion, username, fingerprint, geyser);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -170,8 +168,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
protected final void initialLogin(final @NotNull Channel channel,
|
||||
final @NotNull InetAddress inetAddress,
|
||||
final @NotNull Runnable loginPacket) throws Exception {
|
||||
Sonar.get().getFallback().getOnline().compute(inetAddress, (__, count) -> {
|
||||
final int maxOnlinePerIp = Sonar.get().getConfig().getMaxOnlinePerIp();
|
||||
Sonar.get0().getFallback().getOnline().compute(inetAddress, (__, count) -> {
|
||||
final int maxOnlinePerIp = Sonar.get0().getConfig().getMaxOnlinePerIp();
|
||||
// Skip the maximum online per IP check if it's disabled in the configuration
|
||||
if (count != null && maxOnlinePerIp > 0) {
|
||||
// Check if the number of online players using the same IP address as
|
||||
@@ -208,8 +206,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
}
|
||||
// Add our read/write timeout handler
|
||||
ctx.pipeline().addFirst(FALLBACK_TIMEOUT, new FallbackTimeoutHandler(
|
||||
Sonar.get().getConfig().getVerification().getReadTimeout(),
|
||||
Sonar.get().getConfig().getVerification().getWriteTimeout(),
|
||||
Sonar.get0().getConfig().getVerification().getReadTimeout(),
|
||||
Sonar.get0().getConfig().getVerification().getWriteTimeout(),
|
||||
TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@@ -231,18 +229,20 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
private static void _customDisconnect(final @NotNull Channel channel,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
// TODO: recode this
|
||||
// Remove the connection handler pipeline to completely take over the channel
|
||||
final String handler = Sonar.get().getPlatform().getConnectionHandler();
|
||||
final String handler = Sonar.get0().getPlatform().getConnectionHandler();
|
||||
if (channel.pipeline().context(handler) != null) {
|
||||
channel.pipeline().remove(handler);
|
||||
}
|
||||
final String encoder = Sonar.get().getPlatform().getEncoder().apply(channel.pipeline());
|
||||
final String encoder = Sonar.get0().getPlatform().getEncoder().apply(channel.pipeline());
|
||||
final ChannelHandler currentEncoder = channel.pipeline().get(encoder);
|
||||
// Close the channel if no encoder exists
|
||||
if (currentEncoder != null) {
|
||||
// We don't need to update the encoder if it has already been replaced by Sonar
|
||||
if (!(currentEncoder instanceof FallbackPacketEncoder)) {
|
||||
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
channel.pipeline().replace(encoder, FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
}
|
||||
ProtocolUtil.closeWith(channel, protocolVersion, packet);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -18,6 +18,7 @@
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
@@ -59,13 +60,13 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
@Setter
|
||||
private boolean forceCaptcha;
|
||||
|
||||
public FallbackUserWrapper(final @NotNull Channel channel,
|
||||
public FallbackUserWrapper(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull InetAddress inetAddress,
|
||||
final @NotNull ProtocolVersion protocolVersion,
|
||||
final @NotNull String username,
|
||||
final @NotNull String fingerprint,
|
||||
final boolean geyser) {
|
||||
this.channel = channel;
|
||||
this.channel = ctx.channel();
|
||||
this.inetAddress = inetAddress;
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.username = username;
|
||||
@@ -75,18 +76,18 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
|
||||
GlobalSonarStatistics.totalAttemptedVerifications++;
|
||||
|
||||
if (Sonar.get().getConfig().getVerification().isLogConnections()
|
||||
&& (Sonar.get().getAttackTracker().getCurrentAttack() == null
|
||||
|| Sonar.get().getConfig().getVerification().isLogDuringAttack())) {
|
||||
Sonar.get().getLogger().info(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.connection")
|
||||
if (Sonar.get0().getConfig().getVerification().isLogConnections()
|
||||
&& (Sonar.get0().getAttackTracker().getCurrentAttack() == null
|
||||
|| Sonar.get0().getConfig().getVerification().isLogDuringAttack())) {
|
||||
Sonar.get0().getLogger().info(
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("verification.logs.connection")
|
||||
.replace("<username>", username)
|
||||
.replace("<ip>", Sonar.get().getConfig().formatAddress(inetAddress))
|
||||
.replace("<protocol>", String.valueOf(protocolVersion.getProtocol())));
|
||||
.replace("<ip>", Sonar.get0().getConfig().formatAddress(inetAddress))
|
||||
.replace("<protocol>", protocolVersion.getName()));
|
||||
}
|
||||
|
||||
// Call the VerifyJoinEvent for external API usage
|
||||
Sonar.get().getEventManager().publish(new UserVerifyJoinEvent(this));
|
||||
Sonar.get0().getEventManager().publish(new UserVerifyJoinEvent(this));
|
||||
|
||||
// Run this in the channel's event loop to avoid issues
|
||||
channel.eventLoop().execute(() -> {
|
||||
@@ -96,16 +97,14 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
}
|
||||
|
||||
// Mark the player as connected by caching them in a map of verifying players
|
||||
Sonar.get().getFallback().getConnected().compute(inetAddress, (__, v) -> true);
|
||||
Sonar.get0().getFallback().getConnected().compute(inetAddress, (__, v) -> true);
|
||||
|
||||
// Replace normal encoder to allow custom packets
|
||||
// TODO: recode injection
|
||||
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
|
||||
channel.pipeline().addFirst(FALLBACK_FRAME_ENCODER, FallbackVarIntLengthEncoder.INSTANCE);
|
||||
channel.pipeline().addLast(FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
|
||||
// Replace normal decoder to allow custom packets
|
||||
// TODO: recode injection
|
||||
final FallbackPacketDecoder newDecoder = new FallbackPacketDecoder(protocolVersion);
|
||||
channel.pipeline().addFirst(FALLBACK_FRAME_DECODER, new FallbackVarInt21FrameDecoder());
|
||||
channel.pipeline().addLast(FALLBACK_PACKET_DECODER, newDecoder);
|
||||
@@ -126,7 +125,6 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
newDecoder.setListener(new FallbackPreJoinHandler(this));
|
||||
|
||||
// Make sure to catch all exceptions during the verification
|
||||
// TODO: recode injection
|
||||
channel.pipeline().addLast(FALLBACK_TAIL_EXCEPTIONS, FallbackTailExceptionsHandler.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -60,13 +60,17 @@ public final class FallbackInjectedChannelInitializer extends ChannelInitializer
|
||||
throw new ReflectiveOperationException(throwable);
|
||||
}
|
||||
|
||||
inject(channel, sonarPipelineInjector);
|
||||
}
|
||||
|
||||
public static void inject(final @NotNull Channel channel, final Consumer<ChannelPipeline> sonarPipelineInjector) {
|
||||
// Inject Sonar's channel handler into the pipeline;
|
||||
// Also make sure the player is not a fake player to avoid compatibility issues
|
||||
if (channel.isActive() && !FakeChannelUtil.isFakeChannel(channel)) {
|
||||
final FallbackInboundHandler inboundHandler = new FallbackInboundHandler(sonarPipelineInjector);
|
||||
// We need to be careful on Bukkit, as the encoder can be different
|
||||
if (Sonar.get().getPlatform() == SonarPlatform.BUKKIT) {
|
||||
final String encoder = Sonar.get().getPlatform().getEncoder().apply(channel.pipeline());
|
||||
if (Sonar.get0().getPlatform() == SonarPlatform.BUKKIT) {
|
||||
final String encoder = Sonar.get0().getPlatform().getEncoder().apply(channel.pipeline());
|
||||
channel.pipeline().addBefore(encoder, FALLBACK_INBOUND_HANDLER, inboundHandler);
|
||||
} else {
|
||||
channel.pipeline().addFirst(FALLBACK_INBOUND_HANDLER, inboundHandler);
|
||||
|
||||
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,8 +30,7 @@ public final class FallbackTailExceptionsHandler extends ChannelDuplexHandler {
|
||||
// does not have any other pipelines that could handle this error.
|
||||
// Additionally, this will also run after our custom decoder.
|
||||
@Override
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx,
|
||||
final Throwable cause) throws Exception {
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
// Close the channel if we encounter any errors.
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -43,6 +43,7 @@ public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
// Skip any runs of 0x00 we might find
|
||||
final int packetStart = byteBuf.forEachByte(ByteProcessor.FIND_NON_NUL);
|
||||
if (packetStart == -1) {
|
||||
byteBuf.clear();
|
||||
return;
|
||||
}
|
||||
byteBuf.readerIndex(packetStart);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+8
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -44,12 +44,12 @@ public class CaptchaPreparer {
|
||||
}
|
||||
|
||||
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");
|
||||
Sonar.get0().getLogger().info("Asynchronously preparing CAPTCHA answers...");
|
||||
Sonar.get0().getLogger().info("Players will be able to join even if the preparation isn't finished");
|
||||
|
||||
// Prepare cache
|
||||
final int precomputeAmount = Sonar.get().getConfig().getVerification().getMap().getPrecomputeAmount();
|
||||
final char[] alphabet = Sonar.get().getConfig().getVerification().getMap().getAlphabet().toCharArray();
|
||||
final int precomputeAmount = Sonar.get0().getConfig().getVerification().getMap().getPrecomputeAmount();
|
||||
final char[] alphabet = Sonar.get0().getConfig().getVerification().getMap().getAlphabet().toCharArray();
|
||||
|
||||
preparedAmount = 0;
|
||||
cached = new MapCaptchaInfo[precomputeAmount];
|
||||
@@ -62,13 +62,13 @@ public class CaptchaPreparer {
|
||||
for (int j = 0; j < answer.length; j++) {
|
||||
answer[j] = alphabet[RANDOM.nextInt(alphabet.length)];
|
||||
}
|
||||
final BufferedImage image = Sonar.get().getFallback().getCaptchaGenerator().createImage(answer);
|
||||
final BufferedImage image = Sonar.get0().getFallback().getCaptchaGenerator().createImage(answer);
|
||||
// Convert and cache converted Minecraft map bytes
|
||||
cached[preparedAmount++] = new MapCaptchaInfo(new String(answer), MapColorPalette.imageToBuffer(image));
|
||||
}
|
||||
|
||||
Sonar.get().getLogger().info("Finished preparing {} CAPTCHA answers ({}s)!", preparedAmount, timer);
|
||||
Sonar.get().getEventManager().publish(new CaptchaGenerationEndEvent(timer, preparedAmount));
|
||||
Sonar.get0().getLogger().info("Finished preparing {} CAPTCHA answers ({}s)!", preparedAmount, timer);
|
||||
Sonar.get0().getEventManager().publish(new CaptchaGenerationEndEvent(timer, preparedAmount));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+12
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -383,26 +383,6 @@ public enum FallbackPacketRegistry {
|
||||
map(0x03, MINECRAFT_1_19, true),
|
||||
map(0x04, MINECRAFT_1_19_4, true),
|
||||
map(0x03, MINECRAFT_1_20_2, true));
|
||||
clientbound.register(TeleportEntityPacket.class, TeleportEntityPacket::new,
|
||||
map(0x18, MINECRAFT_1_7_2, true),
|
||||
map(0x4A, MINECRAFT_1_9, true),
|
||||
map(0x49, MINECRAFT_1_9_4, true),
|
||||
map(0x4B, MINECRAFT_1_12, true),
|
||||
map(0x4C, MINECRAFT_1_12_1, true),
|
||||
map(0x50, MINECRAFT_1_13, true),
|
||||
map(0x56, MINECRAFT_1_14, true),
|
||||
map(0x57, MINECRAFT_1_15, true),
|
||||
map(0x56, MINECRAFT_1_16, true),
|
||||
map(0x61, MINECRAFT_1_17, true),
|
||||
map(0x62, MINECRAFT_1_18, true),
|
||||
map(0x63, MINECRAFT_1_19, true),
|
||||
map(0x66, MINECRAFT_1_19_1, true),
|
||||
map(0x64, MINECRAFT_1_19_3, true),
|
||||
map(0x68, MINECRAFT_1_19_4, true),
|
||||
map(0x6B, MINECRAFT_1_20_2, true),
|
||||
map(0x6D, MINECRAFT_1_20_3, true),
|
||||
map(0x70, MINECRAFT_1_20_5, true),
|
||||
map(0x77, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(UpdateTimePacket.class, UpdateTimePacket::new,
|
||||
map(0x03, MINECRAFT_1_7_2, true),
|
||||
map(0x44, MINECRAFT_1_9, true),
|
||||
@@ -422,6 +402,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x64, MINECRAFT_1_20_5, true),
|
||||
map(0x6B, MINECRAFT_1_21_2, true));
|
||||
|
||||
serverbound.register(ClientTickEndPacket.class, ClientTickEndPacket::new,
|
||||
map(0x0B, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
|
||||
map(0x09, MINECRAFT_1_7_2, false),
|
||||
map(0x17, MINECRAFT_1_9, false),
|
||||
@@ -435,7 +417,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x2B, MINECRAFT_1_20_2, false),
|
||||
map(0x2C, MINECRAFT_1_20_3, false),
|
||||
map(0x2F, MINECRAFT_1_20_5, false),
|
||||
map(0x31, MINECRAFT_1_21_2, false));
|
||||
map(0x31, MINECRAFT_1_21_2, false),
|
||||
map(0x33, MINECRAFT_1_21_4, false));
|
||||
serverbound.register(PaddleBoatPacket.class, PaddleBoatPacket::new,
|
||||
map(0x11, MINECRAFT_1_9, false),
|
||||
map(0x12, MINECRAFT_1_12, false),
|
||||
@@ -467,7 +450,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x22, MINECRAFT_1_20_2, false),
|
||||
map(0x23, MINECRAFT_1_20_3, false),
|
||||
map(0x26, MINECRAFT_1_20_5, false),
|
||||
map(0x28, MINECRAFT_1_21_2, false));
|
||||
map(0x28, MINECRAFT_1_21_2, false),
|
||||
map(0x29, MINECRAFT_1_21_4, false));
|
||||
serverbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
|
||||
map(0x10, MINECRAFT_1_9, false),
|
||||
map(0x11, MINECRAFT_1_12, false),
|
||||
@@ -524,7 +508,7 @@ public enum FallbackPacketRegistry {
|
||||
map(0x08, MINECRAFT_1_19_4, false),
|
||||
map(0x09, MINECRAFT_1_20_2, false),
|
||||
map(0x0A, MINECRAFT_1_20_5, false),
|
||||
map(0xC, MINECRAFT_1_21_2, false));
|
||||
map(0x0C, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(PluginMessagePacket.class, PluginMessagePacket::new,
|
||||
map(0x17, MINECRAFT_1_7_2, false),
|
||||
map(0x09, MINECRAFT_1_9, false),
|
||||
@@ -625,7 +609,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x23, MINECRAFT_1_20_2, false),
|
||||
map(0x24, MINECRAFT_1_20_3, false),
|
||||
map(0x27, MINECRAFT_1_20_5, false),
|
||||
map(0x29, MINECRAFT_1_21_2, false));
|
||||
map(0x29, MINECRAFT_1_21_2, false),
|
||||
map(0x2B, MINECRAFT_1_21_4, false));
|
||||
serverbound.register(AnimationPacket.class, AnimationPacket::new,
|
||||
map(0x0A, MINECRAFT_1_7_2, false),
|
||||
map(0x1A, MINECRAFT_1_9, false),
|
||||
@@ -639,7 +624,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x32, MINECRAFT_1_20_2, false),
|
||||
map(0x33, MINECRAFT_1_20_3, false),
|
||||
map(0x36, MINECRAFT_1_20_5, false),
|
||||
map(0x38, MINECRAFT_1_21_2, false));
|
||||
map(0x38, MINECRAFT_1_21_2, false),
|
||||
map(0x3A, MINECRAFT_1_21_4, false));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -50,7 +50,7 @@ public final class FallbackPacketSnapshot implements FallbackPacket {
|
||||
try {
|
||||
originalPacket.encode(byteBuf, protocolVersion);
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().error("Could not encode packet {} for version {}: {}",
|
||||
Sonar.get0().getLogger().error("Could not encode packet {} for version {}: {}",
|
||||
originalPacket, protocolVersion, throwable);
|
||||
break;
|
||||
}
|
||||
|
||||
+43
-42
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -80,9 +80,10 @@ public class FallbackPreparer {
|
||||
public final FallbackPacket PRE_JOIN_KEEP_ALIVE = new FallbackPacketSnapshot(new KeepAlivePacket(PRE_JOIN_KEEP_ALIVE_ID));
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_20 = new FallbackPacket[] {
|
||||
new FallbackPacketSnapshot(new RegistryDataPacket(DimensionRegistry.CODEC_1_20, null, null))};
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20);
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20_5);
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_21 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21);
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_21_2 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_2);
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_21_4 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_21_4);
|
||||
public final FallbackPacket START_WRITING_CHUNKS = new GameEventPacket(13, 0);
|
||||
public final static FallbackPacket INVALID_HELD_ITEM_SLOT = new SetHeldItemPacket(-1);
|
||||
public final FallbackPacket RANDOM_KEEP_ALIVE = new FallbackPacketSnapshot(new KeepAlivePacket(RANDOM.nextInt()));
|
||||
@@ -111,22 +112,22 @@ public class FallbackPreparer {
|
||||
public FallbackPacket alreadyVerifying;
|
||||
public FallbackPacket reconnectedTooFast;
|
||||
public FallbackPacket protocolBlacklisted;
|
||||
public FallbackPacket invalidUsername;
|
||||
public FallbackPacket unsupportedVersion;
|
||||
public FallbackPacket tooManyOnlinePerIP;
|
||||
public FallbackPacket[] xpCountdown;
|
||||
public FallbackPacket updateTime;
|
||||
|
||||
public static int maxMovementTick, dynamicSpawnYPosition, maxTotalPacketsSent;
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public void prepare() {
|
||||
// Preload the packet registry to avoid CPU/RAM issues on 1st connection
|
||||
Sonar.get().getLogger().info("Preloading all registered packets...");
|
||||
Sonar.get0().getLogger().info("Preloading all registered packets...");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
FallbackPacketRegistry.values();
|
||||
|
||||
// Prepare LoginSuccess packet with capped username to 16 characters
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
String username = Sonar.get().getConfig().getGeneralConfig().getString("verification.cached-username");
|
||||
String username = Sonar.get0().getConfig().getGeneralConfig().getString("verification.cached-username");
|
||||
if (username.length() > 16) {
|
||||
username = username.substring(0, 16);
|
||||
}
|
||||
@@ -134,16 +135,16 @@ public class FallbackPreparer {
|
||||
|
||||
// Prepare JoinGame packet
|
||||
joinGame = new FallbackPacketSnapshot(new JoinGamePacket(PLAYER_ENTITY_ID,
|
||||
Sonar.get().getConfig().getVerification().getGamemode().getId(),
|
||||
Sonar.get0().getConfig().getVerification().getGamemode().getId(),
|
||||
-1, 0, 0,
|
||||
RANDOM.nextInt(3), 1, 0, 0,
|
||||
new String[]{"lol"}, "lol", "flat",
|
||||
new String[]{"minecraft:overworld"}, "minecraft:overworld", "flat",
|
||||
DimensionType.OVERWORLD, RANDOM.nextLong() & 1337,
|
||||
false, true, false,
|
||||
false, false, false, true));
|
||||
|
||||
// Prepare the gravity check
|
||||
maxMovementTick = Sonar.get().getConfig().getVerification().getGravity().getMaxMovementTicks();
|
||||
maxMovementTick = Sonar.get0().getConfig().getVerification().getGravity().getMaxMovementTicks();
|
||||
|
||||
double motionY = 0, fallDistance = 0;
|
||||
|
||||
@@ -183,25 +184,25 @@ public class FallbackPreparer {
|
||||
}
|
||||
|
||||
// Prepare disconnect packets during login
|
||||
blacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getBlacklisted(), true));
|
||||
alreadyVerifying = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getAlreadyVerifying(), true));
|
||||
alreadyQueued = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
invalidUsername = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getInvalidUsername(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getTooManyOnlinePerIp(), true));
|
||||
blacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getBlacklisted(), true));
|
||||
alreadyVerifying = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getAlreadyVerifying(), true));
|
||||
alreadyQueued = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
unsupportedVersion = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getVerification().getUnsupportedVersion(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get0().getConfig().getTooManyOnlinePerIp(), true));
|
||||
|
||||
// Prepare transfer packet
|
||||
if (Sonar.get().getConfig().getGeneralConfig().getBoolean("verification.transfer.enabled")) {
|
||||
if (Sonar.get0().getConfig().getGeneralConfig().getBoolean("verification.transfer.enabled")) {
|
||||
transferToOrigin = new FallbackPacketSnapshot(new TransferPacket(
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("verification.transfer.destination-host"),
|
||||
Sonar.get().getConfig().getGeneralConfig().getInt("verification.transfer.destination-port")));
|
||||
Sonar.get0().getConfig().getGeneralConfig().getString("verification.transfer.destination-host"),
|
||||
Sonar.get0().getConfig().getGeneralConfig().getInt("verification.transfer.destination-port")));
|
||||
} else {
|
||||
transferToOrigin = null;
|
||||
}
|
||||
|
||||
// Prepare update time packet
|
||||
final int timeOfDay = Sonar.get().getConfig().getVerification().getTimeOfDay();
|
||||
final int timeOfDay = Sonar.get0().getConfig().getVerification().getTimeOfDay();
|
||||
if (timeOfDay != 1000) {
|
||||
updateTime = new UpdateTimePacket(0L, timeOfDay, false);
|
||||
} else {
|
||||
@@ -209,29 +210,29 @@ public class FallbackPreparer {
|
||||
}
|
||||
|
||||
// If the welcome message is empty, we don't need to send a message to the player
|
||||
final String welcome = Sonar.get().getConfig().getMessagesConfig().getString("verification.welcome");
|
||||
final String welcome = Sonar.get0().getConfig().getMessagesConfig().getString("verification.welcome");
|
||||
if (welcome.isEmpty()) {
|
||||
welcomeMessage = null;
|
||||
} else {
|
||||
welcomeMessage = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
MiniMessage.miniMessage().deserialize(welcome,
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix())))));
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
|
||||
}
|
||||
|
||||
if (Sonar.get().getConfig().getVerification().getMap().getTiming() != SonarConfiguration.Verification.Timing.NEVER
|
||||
|| Sonar.get().getConfig().getVerification().getGravity().isCaptchaOnFail()) {
|
||||
if (Sonar.get0().getConfig().getVerification().getMap().getTiming() != SonarConfiguration.Verification.Timing.NEVER
|
||||
|| Sonar.get0().getConfig().getVerification().getGravity().isCaptchaOnFail()) {
|
||||
// Prepare CAPTCHA messages
|
||||
enterCodeMessage = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.captcha.enter"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix())))));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("verification.captcha.enter"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
|
||||
incorrectCaptcha = new FallbackPacketSnapshot(new SystemChatPacket(new ComponentHolder(
|
||||
MiniMessage.miniMessage().deserialize(
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.captcha.incorrect"),
|
||||
Placeholder.component("prefix", Sonar.get().getConfig().getPrefix())))));
|
||||
Sonar.get0().getConfig().getMessagesConfig().getString("verification.captcha.incorrect"),
|
||||
Placeholder.component("prefix", Sonar.get0().getConfig().getPrefix())))));
|
||||
|
||||
// Prepare countdown
|
||||
xpCountdown = new FallbackPacket[Sonar.get().getConfig().getVerification().getMap().getMaxDuration() / 1000];
|
||||
xpCountdown = new FallbackPacket[Sonar.get0().getConfig().getVerification().getMap().getMaxDuration() / 1000];
|
||||
|
||||
for (int i = 0; i < xpCountdown.length; i++) {
|
||||
final float bar = (float) i / xpCountdown.length;
|
||||
@@ -240,15 +241,15 @@ public class FallbackPreparer {
|
||||
|
||||
// Update the CAPTCHA generator if necessary
|
||||
final CaptchaGenerationStartEvent generationStartEvent = new CaptchaGenerationStartEvent(
|
||||
Sonar.get().getFallback().getCaptchaGenerator());
|
||||
Sonar.get().getEventManager().publish(generationStartEvent);
|
||||
Sonar.get0().getFallback().getCaptchaGenerator());
|
||||
Sonar.get0().getEventManager().publish(generationStartEvent);
|
||||
|
||||
if (generationStartEvent.getCaptchaGenerator() == null
|
||||
|| generationStartEvent.getCaptchaGenerator() instanceof StandardCaptchaGenerator) {
|
||||
Sonar.get().getFallback().setCaptchaGenerator(new StandardCaptchaGenerator(
|
||||
Sonar.get().getConfig().getVerification().getMap().getBackgroundImage()));
|
||||
Sonar.get0().getFallback().setCaptchaGenerator(new StandardCaptchaGenerator(
|
||||
Sonar.get0().getConfig().getVerification().getMap().getBackgroundImage()));
|
||||
} else {
|
||||
Sonar.get().getLogger().info("Custom CAPTCHA generator detected, skipping reinitialization.");
|
||||
Sonar.get0().getLogger().info("Custom CAPTCHA generator detected, skipping reinitialization.");
|
||||
}
|
||||
|
||||
// Prepare CAPTCHA answers
|
||||
@@ -258,24 +259,24 @@ public class FallbackPreparer {
|
||||
enterCodeMessage = null;
|
||||
incorrectCaptcha = null;
|
||||
xpCountdown = null;
|
||||
Sonar.get().getFallback().setCaptchaGenerator(null);
|
||||
Sonar.get0().getFallback().setCaptchaGenerator(null);
|
||||
}
|
||||
|
||||
maxTotalPacketsSent = maxMovementTick + 2
|
||||
+ (xpCountdown == null ? 0 : xpCountdown.length) * 20 + 5
|
||||
+ Sonar.get().getConfig().getVerification().getVehicle().getMinimumPackets() * 4
|
||||
+ Sonar.get().getConfig().getVerification().getMap().getMaxTries()
|
||||
+ Sonar.get0().getConfig().getVerification().getVehicle().getMinimumPackets() * 4
|
||||
+ Sonar.get0().getConfig().getVerification().getMap().getMaxTries()
|
||||
+ 150 /* some arbitrary leeway */;
|
||||
}
|
||||
|
||||
public static FallbackPacket[] getRegistryPackets(final @NotNull ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_4)) {
|
||||
return REGISTRY_SYNC_1_21_4;
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21_2)) {
|
||||
return REGISTRY_SYNC_1_21_2;
|
||||
}
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21)) {
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21)) {
|
||||
return REGISTRY_SYNC_1_21;
|
||||
}
|
||||
if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
return REGISTRY_SYNC_1_20_5;
|
||||
}
|
||||
return REGISTRY_SYNC_1_20;
|
||||
|
||||
+29
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -69,7 +69,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 7389;
|
||||
}
|
||||
return 7619;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 7619;
|
||||
}
|
||||
return 8163;
|
||||
}, protocolVersion -> (double) 0.75f),
|
||||
TRAPDOOR(protocolVersion -> {
|
||||
// We have to use wooden trapdoors for 1.7 since 1.7 doesn't have iron trapdoors
|
||||
@@ -112,7 +115,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 10414;
|
||||
}
|
||||
return 10749;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 10749;
|
||||
}
|
||||
return 11293;
|
||||
}, protocolVersion -> 0.1875),
|
||||
END_PORTAL_FRAME(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -148,7 +154,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 7414;
|
||||
}
|
||||
return 7644;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 7644;
|
||||
}
|
||||
return 8185;
|
||||
}, protocolVersion -> 0.8125),
|
||||
DAYLIGHT_SENSOR(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -187,7 +196,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 9207;
|
||||
}
|
||||
return 9462;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 9462;
|
||||
}
|
||||
return 10006;
|
||||
}, protocolVersion -> 0.375),
|
||||
COBBLESTONE_WALL(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -223,7 +235,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 7922;
|
||||
}
|
||||
return 8152;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 8152;
|
||||
}
|
||||
return 8696;
|
||||
}, protocolVersion -> 1.5),
|
||||
STONE_SLABS(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -262,7 +277,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 11231;
|
||||
}
|
||||
return 11566;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 11566;
|
||||
}
|
||||
return 12110;
|
||||
}, protocolVersion -> 0.5),
|
||||
WHITE_CARPET(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
@@ -301,7 +319,10 @@ public enum BlockType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 10728;
|
||||
}
|
||||
return 11063;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 11063;
|
||||
}
|
||||
return 11607;
|
||||
}, protocolVersion -> protocolVersion.compareTo(MINECRAFT_1_8) < 0 ? 0 : 0.0625);
|
||||
|
||||
private final Function<ProtocolVersion, Integer> id;
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
+7
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -35,8 +35,10 @@ public final class DimensionRegistry {
|
||||
public final CompoundBinaryTag CODEC_1_19_1;
|
||||
public final CompoundBinaryTag CODEC_1_19_4;
|
||||
public final CompoundBinaryTag CODEC_1_20;
|
||||
public final CompoundBinaryTag CODEC_1_20_5;
|
||||
public final CompoundBinaryTag CODEC_1_21;
|
||||
public final CompoundBinaryTag CODEC_1_21_2;
|
||||
public final CompoundBinaryTag CODEC_1_21_4;
|
||||
|
||||
static {
|
||||
CODEC_1_16 = getCodec("codec_1_16.nbt");
|
||||
@@ -46,15 +48,17 @@ public final class DimensionRegistry {
|
||||
CODEC_1_19_1 = getCodec("codec_1_19_1.nbt");
|
||||
CODEC_1_19_4 = getCodec("codec_1_19_4.nbt");
|
||||
CODEC_1_20 = getCodec("codec_1_20.nbt");
|
||||
CODEC_1_20_5 = getCodec("codec_1_20_5.nbt");
|
||||
CODEC_1_21 = getCodec("codec_1_21.nbt");
|
||||
CODEC_1_21_2 = getCodec("codec_1_21_2.nbt");
|
||||
CODEC_1_21_4 = getCodec("codec_1_21_4.nbt");
|
||||
}
|
||||
|
||||
private @NotNull CompoundBinaryTag getCodec(final @NotNull String fileName) {
|
||||
try (final InputStream inputStream = Sonar.class.getResourceAsStream("/assets/codecs/" + fileName)) {
|
||||
return BinaryTagIO.reader().read(Objects.requireNonNull(inputStream), BinaryTagIO.Compression.GZIP);
|
||||
return BinaryTagIO.unlimitedReader().read(Objects.requireNonNull(inputStream), BinaryTagIO.Compression.GZIP);
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().error("Could not load mappings for {}: {}", fileName, throwable);
|
||||
Sonar.get0().getLogger().error("Could not load mappings for {}: {}", fileName, throwable);
|
||||
throw new IllegalStateException(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,7 +24,9 @@ import lombok.RequiredArgsConstructor;
|
||||
@RequiredArgsConstructor
|
||||
public enum DimensionType {
|
||||
OVERWORLD("minecraft:overworld", 0, 0),
|
||||
@Deprecated
|
||||
THE_NETHER("minecraft:the_nether", -1, 1),
|
||||
@Deprecated
|
||||
THE_END("minecraft:the_end", 1, 2);
|
||||
|
||||
private final String key;
|
||||
|
||||
+10
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
* Copyright (C) 2025 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -54,7 +54,11 @@ public enum EntityType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 10;
|
||||
}
|
||||
return 85; // 1.21.2 split the boat type in id registries.
|
||||
// 1.21.2 split the boat type in id registries.
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 85;
|
||||
}
|
||||
return 84;
|
||||
}),
|
||||
MINECART(protocolVersion -> {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
@@ -87,7 +91,10 @@ public enum EntityType {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 69;
|
||||
}
|
||||
return 82;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 82;
|
||||
}
|
||||
return 81;
|
||||
});
|
||||
|
||||
private final Function<ProtocolVersion, Integer> id;
|
||||
|
||||
Loaded 100 of 213 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user