mirror of
https://github.com/jonesdevelopment/sonar.git
synced 2026-11-05 09:20:15 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
e33ee1333a | ||
|
|
50e6b017f8 | ||
|
|
f25cc18cb9 | ||
|
|
a7b1bfd958 | ||
|
|
d97f124201 | ||
|
|
5e9d8b4b29 | ||
|
|
c3eabd1265 | ||
|
|
9d2752dc32 | ||
|
|
5fe9c18268 | ||
|
|
f93dae9532 | ||
|
|
ab36823ca2 | ||
|
|
5c94f06510 | ||
|
|
d069b9aadb | ||
|
|
3337009fe4 | ||
|
|
b010e18552 | ||
|
|
82b4b3bac7 | ||
|
|
b143ea548a | ||
|
|
689e3ea36b | ||
|
|
c9c1a2abb7 | ||
|
|
a8aa284a5e | ||
|
|
448f8d9af3 | ||
|
|
3d8f61fce3 | ||
|
|
cf27a9fe84 | ||
|
|
bec6251b2a | ||
|
|
6497b89f10 | ||
|
|
525d67808e | ||
|
|
8864c0749a | ||
|
|
1ec4704f8e | ||
|
|
8a4937e3af | ||
|
|
f90446d4e3 | ||
|
|
66141815cb | ||
|
|
3fe7ccd65c | ||
|
|
f6203416d1 | ||
|
|
3c73ecf60f | ||
|
|
c116d7b556 | ||
|
|
057cda6c7a | ||
|
|
3a97a1f949 | ||
|
|
69b20769de | ||
|
|
9b87fde7c6 | ||
|
|
b939767ab9 | ||
|
|
d5a8cd5346 | ||
|
|
aa4e4662bb | ||
|
|
29187d4248 |
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
|
||||
@@ -75,28 +75,23 @@ public interface Sonar {
|
||||
|
||||
void reload();
|
||||
|
||||
@NotNull
|
||||
default SonarVersion getVersion() {
|
||||
@NotNull default SonarVersion getVersion() {
|
||||
return SonarVersion.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default SonarEventManager getEventManager() {
|
||||
@NotNull default SonarEventManager getEventManager() {
|
||||
return SonarEventManager.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default AttackTracker getAttackTracker() {
|
||||
@NotNull default AttackTracker getAttackTracker() {
|
||||
return AttackTracker.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
default Fallback getFallback() {
|
||||
@NotNull default Fallback getFallback() {
|
||||
return Fallback.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Sonar get() {
|
||||
@NotNull static Sonar get() {
|
||||
return SonarSupplier.sonar;
|
||||
}
|
||||
}
|
||||
@@ -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,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Sonar Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.api.command;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@ToString(of = "rawArguments")
|
||||
public final class CommandInvocation {
|
||||
private final InvocationSource source;
|
||||
private final String[] rawArguments;
|
||||
}
|
||||
@@ -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,17 +30,15 @@ import xyz.jonesdev.sonar.api.update.UpdateChecker;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
public interface SonarCommand {
|
||||
List<String> TAB_SUGGESTIONS = new ArrayList<>();
|
||||
|
||||
Map<String, List<String>> ARG_TAB_SUGGESTIONS = new HashMap<>();
|
||||
Map<Integer, List<String>> TAB_SUGGESTIONS = new LinkedHashMap<>();
|
||||
|
||||
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")) {
|
||||
source.sendMessage(Sonar.get().getConfig().getNoPermission());
|
||||
if (Sonar.get().getConfig().getNoPermission() != null) {
|
||||
source.sendMessage(Sonar.get().getConfig().getNoPermission());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,29 +101,28 @@ public interface SonarCommand {
|
||||
}
|
||||
|
||||
static void prepareCachedTabSuggestions() {
|
||||
// Don't re-cache tab suggestions
|
||||
if (!TAB_SUGGESTIONS.isEmpty()) return;
|
||||
// Cache tab suggestions
|
||||
for (final Subcommand subcommand : Sonar.get().getSubcommandRegistry().getSubcommands()) {
|
||||
TAB_SUGGESTIONS.add(subcommand.getInfo().name());
|
||||
if (subcommand.getInfo().aliases().length > 0) {
|
||||
TAB_SUGGESTIONS.addAll(Arrays.asList(subcommand.getInfo().aliases()));
|
||||
}
|
||||
final List<String> arguments = Arrays.asList(subcommand.getInfo().arguments());
|
||||
ARG_TAB_SUGGESTIONS.put(subcommand.getInfo().name(), arguments);
|
||||
for (final String alias : subcommand.getInfo().aliases()) {
|
||||
ARG_TAB_SUGGESTIONS.put(alias, arguments);
|
||||
if (TAB_SUGGESTIONS.isEmpty()) {
|
||||
final List<String> subcommandsAndAliases = new ArrayList<>();
|
||||
for (final Subcommand subcommand : Sonar.get().getSubcommandRegistry().getSubcommands()) {
|
||||
subcommandsAndAliases.add(subcommand.getInfo().name());
|
||||
|
||||
final List<String> arguments = Arrays.asList(subcommand.getInfo().arguments());
|
||||
TAB_SUGGESTIONS.put(subcommand.getInfo().name().hashCode(), arguments);
|
||||
|
||||
for (final String alias : subcommand.getInfo().aliases()) {
|
||||
subcommandsAndAliases.add(alias);
|
||||
TAB_SUGGESTIONS.put(alias.hashCode(), arguments);
|
||||
}
|
||||
}
|
||||
TAB_SUGGESTIONS.put(-1, subcommandsAndAliases);
|
||||
}
|
||||
}
|
||||
|
||||
default List<String> getCachedTabSuggestions(final String @NotNull [] arguments) {
|
||||
if (arguments.length <= 1) {
|
||||
return TAB_SUGGESTIONS;
|
||||
} else if (arguments.length == 2) {
|
||||
final String subcommandName = arguments[0].toLowerCase();
|
||||
return ARG_TAB_SUGGESTIONS.getOrDefault(subcommandName, emptyList());
|
||||
if (arguments.length <= 2) {
|
||||
final int subcommandHash = arguments.length <= 1 ? -1 : arguments[0].toLowerCase().hashCode();
|
||||
return TAB_SUGGESTIONS.getOrDefault(subcommandHash, Collections.emptyList());
|
||||
}
|
||||
return emptyList();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -23,7 +23,6 @@ import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.command.CommandInvocation;
|
||||
import xyz.jonesdev.sonar.api.command.InvocationSource;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -91,7 +90,7 @@ public abstract class Subcommand {
|
||||
}
|
||||
|
||||
// Execute the sub command from the invocation source with the given arguments
|
||||
execute(new CommandInvocation(invocationSource, arguments));
|
||||
execute(invocationSource, arguments);
|
||||
}
|
||||
|
||||
public final @NotNull String getDescription() {
|
||||
@@ -99,5 +98,5 @@ public abstract class Subcommand {
|
||||
return Objects.requireNonNull(Sonar.get().getConfig().getMessagesConfig().getString(path));
|
||||
}
|
||||
|
||||
protected abstract void execute(final @NotNull CommandInvocation invocation);
|
||||
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
|
||||
|
||||
@@ -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
|
||||
@@ -195,6 +195,7 @@ public final class SonarConfiguration {
|
||||
verification.brand.validRegex = Pattern.compile(generalConfig.getString("verification.checks.client-brand.valid-regex"));
|
||||
verification.brand.maxLength = generalConfig.getInt("verification.checks.client-brand.max-length");
|
||||
|
||||
verification.timeOfDay = clamp(generalConfig.getInt("verification.time-of-day"), 0, 24000);
|
||||
verification.gamemode = Verification.Gamemode.valueOf(generalConfig.getString("verification.gamemode"));
|
||||
verification.validNameRegex = Pattern.compile(generalConfig.getString("verification.checks.valid-name-regex"));
|
||||
verification.validLocaleRegex = Pattern.compile(generalConfig.getString("verification.checks.valid-locale-regex"));
|
||||
@@ -219,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()) {
|
||||
@@ -242,8 +239,14 @@ public final class SonarConfiguration {
|
||||
|
||||
// Messages
|
||||
prefix = MiniMessage.miniMessage().deserialize(messagesConfig.getString("prefix"));
|
||||
noPermission = MiniMessage.miniMessage().deserialize(messagesConfig.getString("commands.no-permission"),
|
||||
Placeholder.component("prefix", prefix));
|
||||
|
||||
final String noPermissionMessage = messagesConfig.getString("commands.no-permission");
|
||||
if (noPermissionMessage.isEmpty()) {
|
||||
noPermission = null;
|
||||
} else {
|
||||
noPermission = MiniMessage.miniMessage().deserialize(noPermissionMessage,
|
||||
Placeholder.component("prefix", prefix));
|
||||
}
|
||||
|
||||
SonarCommand.prepareCachedTabSuggestions();
|
||||
|
||||
@@ -259,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");
|
||||
@@ -408,6 +412,7 @@ public final class SonarConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private int timeOfDay;
|
||||
private boolean checkGeyser;
|
||||
private boolean logConnections;
|
||||
private boolean logDuringAttack;
|
||||
@@ -432,6 +437,7 @@ public final class SonarConfiguration {
|
||||
private Component blacklisted;
|
||||
private Component protocolBlacklisted;
|
||||
private Component currentlyPreparing;
|
||||
private Component unsupportedVersion;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
+51
-58
@@ -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
|
||||
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.Range;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.api.database.model.VerifiedPlayer;
|
||||
import xyz.jonesdev.sonar.api.fingerprint.FingerprintingUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
@@ -45,8 +46,6 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public final class VerifiedPlayerController {
|
||||
private static final ExecutorService DB_UPDATE_SERVICE = Executors.newSingleThreadExecutor();
|
||||
|
||||
@Getter
|
||||
private final Set<String> cache = Collections.synchronizedSet(new HashSet<>());
|
||||
private @Nullable ConnectionSource connectionSource;
|
||||
@@ -54,6 +53,7 @@ public final class VerifiedPlayerController {
|
||||
private QueryBuilder<VerifiedPlayer, Integer> queryBuilder;
|
||||
@Getter
|
||||
private final @NotNull SonarConfiguration.Database.Type cachedDatabaseType;
|
||||
private final ExecutorService updateService = Executors.newSingleThreadExecutor();
|
||||
|
||||
public VerifiedPlayerController(final @NotNull LibraryManager libraryManager) {
|
||||
final SonarConfiguration.Database database = Sonar.get().getConfig().getDatabase();
|
||||
@@ -95,7 +95,6 @@ public final class VerifiedPlayerController {
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("database.password"),
|
||||
cachedDatabaseType.getDatabaseType());
|
||||
|
||||
// Create database table
|
||||
try {
|
||||
TableUtils.createTableIfNotExists(connectionSource, VerifiedPlayer.class);
|
||||
} catch (SQLException ignored) {
|
||||
@@ -111,14 +110,16 @@ public final class VerifiedPlayerController {
|
||||
|
||||
// Make sure to run the clean task and the caching task in the same thread
|
||||
// https://github.com/jonesdevelopment/sonar/issues/150
|
||||
DB_UPDATE_SERVICE.execute(() -> {
|
||||
try {
|
||||
// Make sure to clear all outdated entries first
|
||||
clearOld(database.getMaximumAge());
|
||||
// Add all entries from the database to the cache
|
||||
dao.queryForAll().forEach(verifiedPlayer -> cache.add(verifiedPlayer.getFingerprint()));
|
||||
} catch (SQLException exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
updateService.execute(() -> {
|
||||
if (connectionSource != null) {
|
||||
try {
|
||||
// Make sure to clear all outdated entries first
|
||||
clearOld(database.getMaximumAge());
|
||||
// Add all entries from the database to the cache
|
||||
dao.queryForAll().forEach(verifiedPlayer -> cache.add(verifiedPlayer.getFingerprint()));
|
||||
} catch (SQLException exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (SQLException exception) {
|
||||
@@ -132,21 +133,23 @@ 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) {
|
||||
exception.printStackTrace(System.err);
|
||||
}
|
||||
// Make sure not to reuse a closed connection
|
||||
connectionSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all old entries using the given timestamp.
|
||||
* Clear all old entries using the given timestamp
|
||||
*/
|
||||
private void clearOld(final @Range(from = 1, to = 365) int maximumAge) throws SQLException {
|
||||
final long timestamp = Instant.now()
|
||||
.minus(maximumAge, ChronoUnit.DAYS)
|
||||
.getEpochSecond() * 1000L; // convert to ms
|
||||
final long timestamp = Instant.now().minus(maximumAge, ChronoUnit.DAYS).getEpochSecond() * 1000L;
|
||||
|
||||
final List<VerifiedPlayer> oldEntries = queryBuilder.where()
|
||||
.lt("timestamp", new Timestamp(timestamp))
|
||||
@@ -175,34 +178,36 @@ public final class VerifiedPlayerController {
|
||||
return;
|
||||
}
|
||||
|
||||
DB_UPDATE_SERVICE.execute(() -> {
|
||||
// We cannot throw a NullPointerException within the executor service
|
||||
// because we want to handle the error instead of simply throwing an exception
|
||||
if (connectionSource == null) {
|
||||
return;
|
||||
}
|
||||
updateService.execute(() -> {
|
||||
if (connectionSource != null) {
|
||||
try {
|
||||
final List<VerifiedPlayer> verifiedPlayer = queryBuilder.where()
|
||||
.eq("fingerprint", fingerprint)
|
||||
.query();
|
||||
|
||||
try {
|
||||
final List<VerifiedPlayer> verifiedPlayer = queryBuilder.where()
|
||||
.eq("fingerprint", fingerprint)
|
||||
.query();
|
||||
|
||||
if (verifiedPlayer != null) {
|
||||
for (final VerifiedPlayer player : verifiedPlayer) {
|
||||
dao.delete(player);
|
||||
if (verifiedPlayer != null) {
|
||||
for (final VerifiedPlayer player : verifiedPlayer) {
|
||||
dao.delete(player);
|
||||
}
|
||||
}
|
||||
} catch (SQLException exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
}
|
||||
} catch (SQLException exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* First, cache the player locally and then,
|
||||
* secondly, asynchronously add the player to the database.
|
||||
*
|
||||
* @param player VerifiedPlayer model
|
||||
* Creates a new VerifiedPlayer model from the given username, host address, and timestamp
|
||||
*/
|
||||
public void add(final @NotNull String username, final @NotNull String hostAddress, final long timestamp) {
|
||||
final String fingerprint = FingerprintingUtil.getFingerprint(username, hostAddress);
|
||||
// Add a new VerifiedPlayer object from the given parameters to the database
|
||||
add(new VerifiedPlayer(fingerprint, timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the player locally and then adds the player to the database
|
||||
*/
|
||||
public void add(final @NotNull VerifiedPlayer player) {
|
||||
cache.add(player.getFingerprint());
|
||||
@@ -212,39 +217,27 @@ public final class VerifiedPlayerController {
|
||||
return;
|
||||
}
|
||||
|
||||
DB_UPDATE_SERVICE.execute(() -> {
|
||||
// We cannot throw a NullPointerException within the executor service
|
||||
// because we want to handle the error instead of simply throwing an exception
|
||||
if (connectionSource == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
dao.createIfNotExists(player);
|
||||
} catch (SQLException exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
updateService.execute(() -> {
|
||||
if (connectionSource != null) {
|
||||
try {
|
||||
dao.createIfNotExists(player);
|
||||
} catch (SQLException exception) {
|
||||
exception.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of verified IP addresses
|
||||
*
|
||||
* @return Estimated size of the local cache
|
||||
*/
|
||||
public int estimatedSize() {
|
||||
return cache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the local cache, and, if the database type is set,
|
||||
* remove the table from the database.
|
||||
*/
|
||||
public synchronized void clearAll() {
|
||||
public void clearAll() {
|
||||
cache.clear();
|
||||
|
||||
// Delete the entire table from the database, if necessary
|
||||
if (cachedDatabaseType != SonarConfiguration.Database.Type.NONE) {
|
||||
if (connectionSource != null
|
||||
&& cachedDatabaseType != SonarConfiguration.Database.Type.NONE) {
|
||||
try {
|
||||
dao.deleteBuilder().delete();
|
||||
} catch (SQLException 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
|
||||
|
||||
+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
|
||||
|
||||
@@ -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
|
||||
@@ -20,7 +20,6 @@ package xyz.jonesdev.sonar.api.event.impl;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
|
||||
@@ -28,6 +27,5 @@ import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserBlacklistedEvent implements SonarEvent {
|
||||
@ApiStatus.Experimental
|
||||
private final FallbackUser user;
|
||||
}
|
||||
@@ -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,6 +27,5 @@ import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserVerifyJoinEvent implements SonarEvent {
|
||||
private final String username;
|
||||
private final FallbackUser user;
|
||||
}
|
||||
@@ -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
|
||||
@@ -22,12 +22,10 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import xyz.jonesdev.sonar.api.event.SonarEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.FallbackUser;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class UserVerifySuccessEvent implements SonarEvent {
|
||||
private final FallbackUser user;
|
||||
private final SystemTimer loginTimer;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,51 +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);
|
||||
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;
|
||||
@@ -90,6 +93,22 @@ public enum ProtocolVersion {
|
||||
return ID_TO_PROTOCOL_CONSTANT.getOrDefault(protocol, UNKNOWN);
|
||||
}
|
||||
|
||||
public boolean greaterThan(final ProtocolVersion that) {
|
||||
return compareTo(that) > 0;
|
||||
}
|
||||
|
||||
public boolean greaterThanOrEquals(final ProtocolVersion that) {
|
||||
return compareTo(that) >= 0;
|
||||
}
|
||||
|
||||
public boolean lessThan(final ProtocolVersion that) {
|
||||
return compareTo(that) < 0;
|
||||
}
|
||||
|
||||
public boolean lessThanOrEquals(final ProtocolVersion that) {
|
||||
return compareTo(that) <= 0;
|
||||
}
|
||||
|
||||
public boolean inBetween(final ProtocolVersion first, final ProtocolVersion last) {
|
||||
return compareTo(first) >= 0 && compareTo(last) <= 0;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,7 +66,7 @@ public final class AttackTracker {
|
||||
// An attack has been detected
|
||||
if (currentAttack == null) {
|
||||
currentAttack = new AttackStatistics();
|
||||
currentAttack.successfulVerifications = Sonar.get().getVerifiedPlayerController().estimatedSize();
|
||||
currentAttack.successfulVerifications = Sonar.get().getVerifiedPlayerController().getCache().size();
|
||||
currentAttack.failedVerifications = Sonar.get().getStatistics().getTotalFailedVerifications();
|
||||
Sonar.get().getEventManager().publish(new AttackDetectedEvent());
|
||||
Sonar.get().getChatNotificationHandler().handleNotification();
|
||||
@@ -118,7 +118,7 @@ public final class AttackTracker {
|
||||
final String endTimestamp = String.valueOf(System.currentTimeMillis() / 1000L);
|
||||
final long blacklisted = Sonar.get().getFallback().getBlacklist().estimatedSize();
|
||||
// Calculate during-attack-statistics using their deltas
|
||||
final long totalVerified = Sonar.get().getVerifiedPlayerController().estimatedSize();
|
||||
final long totalVerified = Sonar.get().getVerifiedPlayerController().getCache().size();
|
||||
final long verified = Math.max(totalVerified - currentAttack.successfulVerifications, 0);
|
||||
final long totalFailed = Sonar.get().getStatistics().getTotalFailedVerifications();
|
||||
final long failed = Math.max(totalFailed - currentAttack.failedVerifications, 0);
|
||||
|
||||
@@ -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
|
||||
|
||||
+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
|
||||
@@ -27,10 +27,9 @@ import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.command.InvocationSource;
|
||||
import xyz.jonesdev.sonar.api.command.SonarCommand;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
public final class BukkitSonarCommand implements CommandExecutor, TabExecutor, SonarCommand {
|
||||
|
||||
@Override
|
||||
@@ -54,9 +53,6 @@ public final class BukkitSonarCommand implements CommandExecutor, TabExecutor, S
|
||||
final String commandAlias,
|
||||
final String @NotNull [] args) {
|
||||
// Do not allow tab completion if the player does not have the required permission
|
||||
if (!sender.hasPermission("sonar.command")) {
|
||||
return emptyList();
|
||||
}
|
||||
return getCachedTabSuggestions(args);
|
||||
return sender.hasPermission("sonar.command") ? getCachedTabSuggestions(args) : Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+8
-7
@@ -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.common.fallback.protocol.FallbackPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake.HandshakePacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginStartPacket;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -35,8 +36,6 @@ import java.util.Objects;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.FALLBACK_INBOUND_HANDLER;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.packets.handshake.HandshakePacket.*;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.DEBUG;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readVarInt;
|
||||
|
||||
final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
private static final ProtocolVersion DEFAULT_PROTOCOL_VERSION = ProtocolVersion.MINECRAFT_1_7_2;
|
||||
@@ -79,7 +78,7 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
return;
|
||||
}
|
||||
|
||||
final int packetId = readVarInt(byteBuf);
|
||||
final int packetId = ProtocolUtil.readVarInt(byteBuf);
|
||||
final FallbackPacket packet = registry.createPacket(packetId);
|
||||
|
||||
// Skip the packet if it's not registered within Sonar's packet registry
|
||||
@@ -93,13 +92,14 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
packet.decode(byteBuf, protocolVersion == null ? DEFAULT_PROTOCOL_VERSION : protocolVersion);
|
||||
} catch (Throwable throwable) {
|
||||
byteBuf.release();
|
||||
throw DEBUG ? new DecoderException(throwable) : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException(throwable) : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
// Check if the packet still has bytes left after we decoded it
|
||||
if (byteBuf.isReadable()) {
|
||||
byteBuf.release();
|
||||
throw DEBUG ? new DecoderException("Could not read packet to end") : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Could not read packet to end ("
|
||||
+ byteBuf.readableBytes() + " bytes left)") : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -122,7 +122,8 @@ final class FallbackBukkitInboundHandler extends FallbackInboundHandlerAdapter {
|
||||
updateRegistry(FallbackPacketRegistry.LOGIN, Objects.requireNonNull(protocolVersion));
|
||||
break;
|
||||
default:
|
||||
throw DEBUG ? new DecoderException("Bad intent " + handshake.getIntent()) : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Bad handshake intent " + handshake.getIntent())
|
||||
: QuietDecoderException.INSTANCE;
|
||||
}
|
||||
} else if (packet instanceof LoginStartPacket) {
|
||||
final LoginStartPacket loginStart = (LoginStartPacket) 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
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
@@ -26,7 +26,7 @@ import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.command.InvocationSource;
|
||||
import xyz.jonesdev.sonar.api.command.SonarCommand;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import java.util.Collections;
|
||||
|
||||
public final class BungeeSonarCommand extends Command implements TabExecutor, SonarCommand {
|
||||
public BungeeSonarCommand() {
|
||||
@@ -47,9 +47,6 @@ public final class BungeeSonarCommand extends Command implements TabExecutor, So
|
||||
@Override
|
||||
public Iterable<String> onTabComplete(final @NotNull CommandSender sender, final String @NotNull [] args) {
|
||||
// Do not allow tab completion if the player does not have the required permission
|
||||
if (!sender.hasPermission("sonar.command")) {
|
||||
return emptyList();
|
||||
}
|
||||
return getCachedTabSuggestions(args);
|
||||
return sender.hasPermission("sonar.command") ? getCachedTabSuggestions(args) : Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+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
|
||||
|
||||
@@ -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
|
||||
@@ -38,10 +38,6 @@ import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import static java.awt.image.BufferedImage.TYPE_3BYTE_BGR;
|
||||
import static xyz.jonesdev.sonar.captcha.StandardTTFFontProvider.FONTS;
|
||||
import static xyz.jonesdev.sonar.captcha.StandardTTFFontProvider.STANDARD_FONT_SIZE;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
@@ -92,7 +88,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
|
||||
private @NotNull BufferedImage createBackgroundImage() {
|
||||
// Create a new image buffer with a 3-byte color spectrum
|
||||
final BufferedImage image = new BufferedImage(width, height, TYPE_3BYTE_BGR);
|
||||
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
|
||||
if (background == null) {
|
||||
// Fill the entire image with a noise texture
|
||||
return FBM.filter(image, image);
|
||||
@@ -128,7 +124,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
|
||||
for (int i = 0; i < answer.length; i++) {
|
||||
// Create a glyph vector for the character with a random font
|
||||
final Font font = FONTS[RANDOM.nextInt(FONTS.length)];
|
||||
final Font font = StandardTTFFontProvider.FONTS[RANDOM.nextInt(StandardTTFFontProvider.FONTS.length)];
|
||||
glyphs[i] = font.createGlyphVector(ctx, String.valueOf(answer[i]));
|
||||
}
|
||||
|
||||
@@ -139,7 +135,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
|
||||
.mapToDouble(glyph -> glyph.getLogicalBounds().getWidth() * scalingXY - 1)
|
||||
.sum();
|
||||
double beginX = Math.max(Math.min(width / 2D - totalWidth / 2D, totalWidth), 0);
|
||||
double beginY = (height + STANDARD_FONT_SIZE / 2D) / 2D + scalingXY;
|
||||
double beginY = (height + StandardTTFFontProvider.STANDARD_FONT_SIZE / 2D) / 2D + scalingXY;
|
||||
|
||||
// Draw each glyph one by one
|
||||
for (final GlyphVector glyph : glyphs) {
|
||||
|
||||
@@ -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
|
||||
@@ -46,7 +46,6 @@ import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@@ -142,7 +141,7 @@ public abstract class SonarBootstrap<T> implements Sonar {
|
||||
|
||||
// Update ratelimiter cache
|
||||
getFallback().setRatelimiter(getConfig().getVerification().getReconnectDelay() > 0L
|
||||
? new CaffeineCacheRatelimiter(getConfig().getVerification().getReconnectDelay(), TimeUnit.MILLISECONDS)
|
||||
? new CaffeineCacheRatelimiter(Duration.ofMillis(getConfig().getVerification().getReconnectDelay()))
|
||||
: NoopCacheRatelimiter.INSTANCE);
|
||||
|
||||
// Update blacklist cache
|
||||
|
||||
+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
|
||||
@@ -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 @NotNull Throwable cause) throws Exception {
|
||||
public void exceptionCaught(final @NotNull ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
+20
-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
|
||||
@@ -25,10 +25,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
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;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import java.net.InetAddress;
|
||||
@@ -38,7 +41,6 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.*;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.*;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.closeWith;
|
||||
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@@ -72,17 +74,23 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
final @NotNull Runnable initialLoginAction,
|
||||
final @NotNull String username,
|
||||
final @NotNull InetSocketAddress socketAddress) throws Exception {
|
||||
// Check if the player has already sent a login packet
|
||||
if (this.username != null) {
|
||||
// Count every single attempted login
|
||||
GlobalSonarStatistics.countLogin();
|
||||
// Ensure that the player sent a handshake packet
|
||||
if (protocolVersion == null) {
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
// Connections from unknown protocol versions will be discarded
|
||||
// as this is the safest way of handling unwanted connections.
|
||||
// Sonar does not support snapshots or Minecraft versions older than 1.7.2
|
||||
if (protocolVersion.isUnknown()) {
|
||||
customDisconnect(ctx.channel(), unsupportedVersion, ProtocolVersion.MINECRAFT_1_7_2);
|
||||
return;
|
||||
}
|
||||
// Ensure that the player has not sent a login packet yet
|
||||
if (this.username != null) {
|
||||
throw QuietDecoderException.INSTANCE;
|
||||
}
|
||||
GlobalSonarStatistics.countLogin();
|
||||
this.username = username;
|
||||
|
||||
final InetAddress inetAddress = socketAddress.getAddress();
|
||||
@@ -149,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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -214,7 +213,7 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
|
||||
private static void customDisconnect(final @NotNull Channel channel,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final ProtocolVersion protocolVersion) {
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
if (channel.isActive()) {
|
||||
if (channel.eventLoop().inEventLoop()) {
|
||||
_customDisconnect(channel, packet, protocolVersion);
|
||||
@@ -229,7 +228,8 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
*/
|
||||
private static void _customDisconnect(final @NotNull Channel channel,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final ProtocolVersion protocolVersion) {
|
||||
final @NotNull ProtocolVersion protocolVersion) {
|
||||
// TODO: recode this
|
||||
// Remove the connection handler pipeline to completely take over the channel
|
||||
final String handler = Sonar.get().getPlatform().getConnectionHandler();
|
||||
if (channel.pipeline().context(handler) != null) {
|
||||
@@ -242,9 +242,10 @@ public abstract class FallbackInboundHandlerAdapter extends ChannelInboundHandle
|
||||
// We don't need to update the encoder if it has already been replaced by Sonar
|
||||
if (!(currentEncoder instanceof FallbackPacketEncoder)) {
|
||||
final FallbackPacketEncoder newEncoder = new FallbackPacketEncoder(protocolVersion);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
channel.pipeline().replace(encoder, FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
}
|
||||
closeWith(channel, protocolVersion, packet);
|
||||
ProtocolUtil.closeWith(channel, protocolVersion, packet);
|
||||
} else {
|
||||
channel.close();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -34,18 +35,16 @@ import xyz.jonesdev.sonar.common.fallback.netty.FallbackVarInt21FrameDecoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.netty.FallbackVarIntLengthEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketDecoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketEncoder;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.play.DisconnectPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.verification.FallbackPreJoinHandler;
|
||||
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.FallbackPipelines.*;
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_20_2;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.CONFIG;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.GAME;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.loginSuccess;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.closeWith;
|
||||
|
||||
@Getter
|
||||
@ToString(of = {"protocolVersion", "inetAddress", "geyser"})
|
||||
@@ -61,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;
|
||||
@@ -84,11 +83,11 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
Sonar.get().getConfig().getMessagesConfig().getString("verification.logs.connection")
|
||||
.replace("<username>", username)
|
||||
.replace("<ip>", Sonar.get().getConfig().formatAddress(inetAddress))
|
||||
.replace("<protocol>", String.valueOf(protocolVersion.getProtocol())));
|
||||
.replace("<protocol>", protocolVersion.getName()));
|
||||
}
|
||||
|
||||
// Call the VerifyJoinEvent for external API usage
|
||||
Sonar.get().getEventManager().publish(new UserVerifyJoinEvent(username, this));
|
||||
Sonar.get().getEventManager().publish(new UserVerifyJoinEvent(this));
|
||||
|
||||
// Run this in the channel's event loop to avoid issues
|
||||
channel.eventLoop().execute(() -> {
|
||||
@@ -105,16 +104,23 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
channel.pipeline().addFirst(FALLBACK_FRAME_ENCODER, FallbackVarIntLengthEncoder.INSTANCE);
|
||||
channel.pipeline().addLast(FALLBACK_PACKET_ENCODER, newEncoder);
|
||||
|
||||
// Send LoginSuccess packet to make the client think they are joining the server
|
||||
write(loginSuccess);
|
||||
|
||||
// The LoginSuccess packet has been sent, now we can change the registry state
|
||||
newEncoder.updateRegistry(protocolVersion.compareTo(MINECRAFT_1_20_2) >= 0 ? CONFIG : GAME);
|
||||
|
||||
// Replace normal decoder to allow custom packets
|
||||
final FallbackPacketDecoder newDecoder = new FallbackPacketDecoder(protocolVersion);
|
||||
channel.pipeline().addFirst(FALLBACK_FRAME_DECODER, new FallbackVarInt21FrameDecoder());
|
||||
channel.pipeline().addLast(FALLBACK_PACKET_DECODER, newDecoder);
|
||||
|
||||
// We're sending the LoginSuccess packet now
|
||||
newDecoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.LOGIN);
|
||||
// Send LoginSuccess packet to make the client think they are joining the server
|
||||
write(FallbackPreparer.loginSuccess);
|
||||
|
||||
// pre-1.20.2 clients do not have the configuration stage
|
||||
if (protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
|
||||
newDecoder.updateRegistry(FallbackPacketRegistry.GAME);
|
||||
newEncoder.updateRegistry(FallbackPacketRegistry.GAME);
|
||||
}
|
||||
|
||||
// Listen for all incoming packets by setting the packet listener
|
||||
newDecoder.setListener(new FallbackPreJoinHandler(this));
|
||||
|
||||
@@ -126,7 +132,7 @@ public final class FallbackUserWrapper implements FallbackUser {
|
||||
@Override
|
||||
public void disconnect(final @NotNull Component reason) {
|
||||
final FallbackPacketEncoder encoder = channel.pipeline().get(FallbackPacketEncoder.class);
|
||||
final boolean duringLogin = encoder != null && encoder.getPacketRegistry() != GAME;
|
||||
closeWith(channel, protocolVersion, DisconnectPacket.create(reason, duringLogin));
|
||||
final boolean duringLogin = encoder != null && encoder.getPacketRegistry() == FallbackPacketRegistry.LOGIN;
|
||||
ProtocolUtil.closeWith(channel, protocolVersion, new DisconnectPacket(reason, duringLogin));
|
||||
}
|
||||
}
|
||||
+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
-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 @NotNull 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();
|
||||
}
|
||||
|
||||
+4
-4
@@ -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
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback;
|
||||
package xyz.jonesdev.sonar.common.fallback.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
@@ -26,12 +26,12 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class FallbackTimeoutHandler extends IdleStateHandler {
|
||||
public FallbackTimeoutHandler(final int readTimeout, final int writeTimeout, final TimeUnit timeUnit) {
|
||||
super(readTimeout, writeTimeout, 0L, timeUnit);
|
||||
super(false, readTimeout, writeTimeout, 0L, timeUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelIdle(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull IdleStateEvent idleStateEvent) throws Exception {
|
||||
final IdleStateEvent idleStateEvent) throws Exception {
|
||||
// The netty (default) ReadTimeoutHandler would normally just throw an Exception
|
||||
// The default ReadTimeoutHandler does only check for the boolean 'closed' and
|
||||
// still throws the Exception even if the channel is closed
|
||||
+7
-7
@@ -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
|
||||
@@ -21,14 +21,13 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.util.ByteProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.util.ByteProcessor.FIND_NON_NUL;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.DEBUG;
|
||||
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java
|
||||
public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
|
||||
@@ -42,8 +41,9 @@ public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
}
|
||||
|
||||
// Skip any runs of 0x00 we might find
|
||||
final int packetStart = byteBuf.forEachByte(FIND_NON_NUL);
|
||||
final int packetStart = byteBuf.forEachByte(ByteProcessor.FIND_NON_NUL);
|
||||
if (packetStart == -1) {
|
||||
byteBuf.clear();
|
||||
return;
|
||||
}
|
||||
byteBuf.readerIndex(packetStart);
|
||||
@@ -56,7 +56,7 @@ public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
return;
|
||||
}
|
||||
if (length <= 0) {
|
||||
throw DEBUG ? new DecoderException("Bad VarInt length: " + length) : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Bad VarInt length: " + length) : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
if (byteBuf.readableBytes() < length) {
|
||||
@@ -75,7 +75,7 @@ public final class FallbackVarInt21FrameDecoder extends ByteToMessageDecoder {
|
||||
final int wholeOrMore = byteBuf.getIntLE(byteBuf.readerIndex());
|
||||
final int atStop = ~wholeOrMore & 0x808080;
|
||||
if (atStop == 0) {
|
||||
throw DEBUG ? new DecoderException("VarInt too big") : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("VarInt too big") : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
final int bitsToKeep = Integer.numberOfTrailingZeros(atStop) + 1;
|
||||
|
||||
+6
-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
|
||||
@@ -22,12 +22,10 @@ import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.varIntBytes;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
// https://github.com/PaperMC/Velocity/blob/dev/3.0.0/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintLengthEncoder.java
|
||||
@ChannelHandler.Sharable
|
||||
public final class FallbackVarIntLengthEncoder extends MessageToMessageEncoder<ByteBuf> {
|
||||
@@ -37,12 +35,12 @@ public final class FallbackVarIntLengthEncoder extends MessageToMessageEncoder<B
|
||||
protected void encode(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull ByteBuf byteBuf,
|
||||
final @NotNull List<Object> out) throws Exception {
|
||||
final int length = byteBuf.readableBytes();
|
||||
final int varIntLength = varIntBytes(length);
|
||||
final int readableBytes = byteBuf.readableBytes();
|
||||
final int length = ProtocolUtil.varIntBytes(readableBytes);
|
||||
|
||||
final ByteBuf lenBuf = ctx.alloc().buffer(varIntLength);
|
||||
final ByteBuf lenBuf = ctx.alloc().buffer(length);
|
||||
|
||||
writeVarInt(lenBuf, length);
|
||||
ProtocolUtil.writeVarInt(lenBuf, readableBytes);
|
||||
out.add(lenBuf);
|
||||
out.add(byteBuf.retain());
|
||||
}
|
||||
|
||||
+4
-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
|
||||
@@ -15,12 +15,14 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.captcha;
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.event.impl.CaptchaGenerationEndEvent;
|
||||
import xyz.jonesdev.sonar.api.timer.SystemTimer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.MapCaptchaInfo;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.map.MapColorPalette;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
+3
-5
@@ -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
|
||||
@@ -39,20 +39,18 @@ public interface FallbackPacket {
|
||||
void decode(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) throws Exception;
|
||||
|
||||
/**
|
||||
* @param byteBuf ByteBuf
|
||||
* @param protocolVersion Protocol version of the player
|
||||
* @return The minimum allowed length of the decoded packet
|
||||
*/
|
||||
default int expectedMinLength(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
default int expectedMinLength(final ProtocolVersion protocolVersion) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byteBuf ByteBuf
|
||||
* @param protocolVersion Protocol version of the player
|
||||
* @return The maximum allowed length of the decoded packet
|
||||
*/
|
||||
default int expectedMaxLength(final ByteBuf byteBuf, final ProtocolVersion protocolVersion) {
|
||||
default int expectedMaxLength(final ProtocolVersion protocolVersion) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
+19
-27
@@ -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
|
||||
@@ -21,19 +21,16 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.MINECRAFT_1_20_2;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.Direction.SERVERBOUND;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.GAME;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.LOGIN;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPreparer.maxTotalPacketsSent;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.DEBUG;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.readVarInt;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
private final ProtocolVersion protocolVersion;
|
||||
private FallbackPacketRegistry.ProtocolRegistry registry;
|
||||
@@ -41,18 +38,12 @@ public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
private FallbackPacketListener listener;
|
||||
private int totalPacketsSent;
|
||||
|
||||
public FallbackPacketDecoder(final @NotNull ProtocolVersion protocolVersion) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
updateRegistry(protocolVersion.compareTo(MINECRAFT_1_20_2) >= 0 ? LOGIN : GAME);
|
||||
}
|
||||
|
||||
public void updateRegistry(final @NotNull FallbackPacketRegistry registry) {
|
||||
this.registry = registry.getProtocolRegistry(SERVERBOUND, protocolVersion);
|
||||
this.registry = registry.getProtocolRegistry(FallbackPacketRegistry.Direction.SERVERBOUND, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(final @NotNull ChannelHandlerContext ctx,
|
||||
final @NotNull Object msg) throws Exception {
|
||||
public void channelRead(final @NotNull ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
if (msg instanceof ByteBuf) {
|
||||
final ByteBuf byteBuf = (ByteBuf) msg;
|
||||
|
||||
@@ -66,11 +57,11 @@ public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
|
||||
// Don't allow the player to spam packets to overload netty
|
||||
if (++totalPacketsSent > maxTotalPacketsSent) {
|
||||
throw DEBUG ? new DecoderException("Sent too many packets") : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Sent too many packets") : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
// Read the packet ID and then create the packet from it
|
||||
final int packetId = readVarInt(byteBuf);
|
||||
final int packetId = ProtocolUtil.readVarInt(byteBuf);
|
||||
final FallbackPacket packet = registry.createPacket(packetId);
|
||||
|
||||
// Skip the packet if it's not registered within Sonar's packet registry
|
||||
@@ -79,18 +70,19 @@ public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
// Ensure that the packet isn't too large or too small
|
||||
checkPacketSize(byteBuf, packet);
|
||||
checkPacketSize(byteBuf.readableBytes(), packet);
|
||||
|
||||
try {
|
||||
// Try to decode the packet for the given protocol version
|
||||
packet.decode(byteBuf, protocolVersion);
|
||||
} catch (Throwable throwable) {
|
||||
throw DEBUG ? new DecoderException(throwable) : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException(throwable) : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
// Check if the packet still has bytes left after we decoded it
|
||||
if (byteBuf.isReadable()) {
|
||||
throw DEBUG ? new DecoderException("Could not read packet to end") : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Could not read packet to end ("
|
||||
+ byteBuf.readableBytes() + " bytes left)"): QuietDecoderException.INSTANCE;
|
||||
}
|
||||
|
||||
// Let our verification handler process the packet
|
||||
@@ -106,16 +98,16 @@ public final class FallbackPacketDecoder extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPacketSize(final @NotNull ByteBuf byteBuf,
|
||||
final @NotNull FallbackPacket packet) throws Exception {
|
||||
final int packetSize = byteBuf.readableBytes();
|
||||
final int expectedMaxLen = packet.expectedMaxLength(byteBuf, protocolVersion);
|
||||
private void checkPacketSize(final int packetSize, final @NotNull FallbackPacket packet) throws Exception {
|
||||
final int expectedMaxLen = packet.expectedMaxLength(protocolVersion);
|
||||
if (expectedMaxLen != -1 && packetSize > expectedMaxLen) {
|
||||
throw DEBUG ? new DecoderException("Packet too large: " + packetSize) : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Packet too large: " + packetSize + " max: " + expectedMaxLen)
|
||||
: QuietDecoderException.INSTANCE;
|
||||
}
|
||||
final int expectedMinLen = packet.expectedMinLength(byteBuf, protocolVersion);
|
||||
final int expectedMinLen = packet.expectedMinLength(protocolVersion);
|
||||
if (expectedMinLen != -1 && packetSize < expectedMinLen) {
|
||||
throw DEBUG ? new DecoderException("Packet too small: " + packetSize) : QuietDecoderException.INSTANCE;
|
||||
throw ProtocolUtil.DEBUG ? new DecoderException("Packet too small: " + packetSize + " min: " + expectedMinLen)
|
||||
: QuietDecoderException.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-16
@@ -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
|
||||
@@ -21,37 +21,31 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.Direction.CLIENTBOUND;
|
||||
import static xyz.jonesdev.sonar.common.fallback.protocol.FallbackPacketRegistry.LOGIN;
|
||||
import static xyz.jonesdev.sonar.common.util.ProtocolUtil.writeVarInt;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class FallbackPacketEncoder extends MessageToByteEncoder<FallbackPacket> {
|
||||
private final ProtocolVersion protocolVersion;
|
||||
@Getter
|
||||
private FallbackPacketRegistry packetRegistry;
|
||||
private FallbackPacketRegistry.ProtocolRegistry protocolRegistry;
|
||||
|
||||
public FallbackPacketEncoder(final ProtocolVersion protocolVersion) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
updateRegistry(LOGIN);
|
||||
}
|
||||
|
||||
public void updateRegistry(final @NotNull FallbackPacketRegistry packetRegistry) {
|
||||
this.packetRegistry = packetRegistry;
|
||||
this.protocolRegistry = packetRegistry.getProtocolRegistry(CLIENTBOUND, protocolVersion);
|
||||
this.protocolRegistry = packetRegistry.getProtocolRegistry(FallbackPacketRegistry.Direction.CLIENTBOUND, protocolVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx,
|
||||
final @NotNull FallbackPacket packet,
|
||||
final ByteBuf out) throws Exception {
|
||||
final FallbackPacket originalPacket = packet instanceof FallbackPacketSnapshot
|
||||
? ((FallbackPacketSnapshot) packet).getOriginalPacket() : packet;
|
||||
final int packetId = protocolRegistry.getPacketId(originalPacket.getClass());
|
||||
writeVarInt(out, packetId);
|
||||
final @NotNull ByteBuf out) throws Exception {
|
||||
final Class<? extends FallbackPacket> originalPacket = packet instanceof FallbackPacketSnapshot
|
||||
? ((FallbackPacketSnapshot) packet).getOriginalPacketClass() : packet.getClass();
|
||||
final int packetId = protocolRegistry.getPacketId(originalPacket);
|
||||
ProtocolUtil.writeVarInt(out, packetId);
|
||||
packet.encode(out, protocolVersion);
|
||||
}
|
||||
}
|
||||
+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
|
||||
|
||||
+87
-51
@@ -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
|
||||
@@ -105,7 +105,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x24, MINECRAFT_1_19_3, true),
|
||||
map(0x28, MINECRAFT_1_19_4, true),
|
||||
map(0x29, MINECRAFT_1_20_2, true),
|
||||
map(0x2B, MINECRAFT_1_20_5, true));
|
||||
map(0x2B, MINECRAFT_1_20_5, true),
|
||||
map(0x2C, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
|
||||
map(0x00, MINECRAFT_1_7_2, true),
|
||||
map(0x1F, MINECRAFT_1_9, true),
|
||||
@@ -120,7 +121,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x1F, MINECRAFT_1_19_3, true),
|
||||
map(0x23, MINECRAFT_1_19_4, true),
|
||||
map(0x24, MINECRAFT_1_20_2, true),
|
||||
map(0x26, MINECRAFT_1_20_5, true));
|
||||
map(0x26, MINECRAFT_1_20_5, true),
|
||||
map(0x27, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(DisconnectPacket.class, DisconnectPacket::new,
|
||||
map(0x40, MINECRAFT_1_7_2, true),
|
||||
map(0x1A, MINECRAFT_1_9, true),
|
||||
@@ -151,7 +153,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x38, MINECRAFT_1_19_3, true),
|
||||
map(0x3C, MINECRAFT_1_19_4, true),
|
||||
map(0x3E, MINECRAFT_1_20_2, true),
|
||||
map(0x40, MINECRAFT_1_20_5, true));
|
||||
map(0x40, MINECRAFT_1_20_5, true),
|
||||
map(0x42, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(PlayerAbilitiesPacket.class, PlayerAbilitiesPacket::new,
|
||||
map(0x39, MINECRAFT_1_7_2, true),
|
||||
map(0x2B, MINECRAFT_1_9, true),
|
||||
@@ -167,7 +170,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x30, MINECRAFT_1_19_3, true),
|
||||
map(0x34, MINECRAFT_1_19_4, true),
|
||||
map(0x36, MINECRAFT_1_20_2, true),
|
||||
map(0x38, MINECRAFT_1_20_5, true));
|
||||
map(0x38, MINECRAFT_1_20_5, true),
|
||||
map(0x3A, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(ChunkDataPacket.class, ChunkDataPacket::new,
|
||||
map(0x21, MINECRAFT_1_7_2, true),
|
||||
map(0x20, MINECRAFT_1_9, true),
|
||||
@@ -182,7 +186,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x20, MINECRAFT_1_19_3, true),
|
||||
map(0x24, MINECRAFT_1_19_4, true),
|
||||
map(0x25, MINECRAFT_1_20_2, true),
|
||||
map(0x27, MINECRAFT_1_20_5, true));
|
||||
map(0x27, MINECRAFT_1_20_5, true),
|
||||
map(0x28, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(RemoveEntitiesPacket.class, RemoveEntitiesPacket::new,
|
||||
map(0x13, MINECRAFT_1_7_2, true),
|
||||
map(0x30, MINECRAFT_1_9, true),
|
||||
@@ -200,7 +205,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x3E, MINECRAFT_1_19_4, true),
|
||||
map(0x3E, MINECRAFT_1_19_4, true),
|
||||
map(0x40, MINECRAFT_1_20_2, true),
|
||||
map(0x42, MINECRAFT_1_20_5, true));
|
||||
map(0x42, MINECRAFT_1_20_5, true),
|
||||
map(0x47, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(SetPassengersPacket.class, SetPassengersPacket::new,
|
||||
map(0x1B, MINECRAFT_1_7_2, true),
|
||||
map(0x40, MINECRAFT_1_9, true),
|
||||
@@ -215,7 +221,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x59, MINECRAFT_1_19_4, true),
|
||||
map(0x5B, MINECRAFT_1_20_2, true),
|
||||
map(0x5D, MINECRAFT_1_20_3, true),
|
||||
map(0x5F, MINECRAFT_1_20_5, true));
|
||||
map(0x5F, MINECRAFT_1_20_5, true),
|
||||
map(0x65, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
|
||||
map(0x29, MINECRAFT_1_9, true),
|
||||
map(0x2B, MINECRAFT_1_13, true),
|
||||
@@ -229,7 +236,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x2A, MINECRAFT_1_19_3, true),
|
||||
map(0x2E, MINECRAFT_1_19_4, true),
|
||||
map(0x2F, MINECRAFT_1_20_2, true),
|
||||
map(0x31, MINECRAFT_1_20_5, true));
|
||||
map(0x31, MINECRAFT_1_20_5, true),
|
||||
map(0x33, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(SpawnEntityPacket.class, SpawnEntityPacket::new,
|
||||
map(0x0E, MINECRAFT_1_7_2, true),
|
||||
map(0x00, MINECRAFT_1_9, true),
|
||||
@@ -248,7 +256,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x43, MINECRAFT_1_19_4, true),
|
||||
map(0x45, MINECRAFT_1_20_2, true),
|
||||
map(0x47, MINECRAFT_1_20_3, true),
|
||||
map(0x49, MINECRAFT_1_20_5, true));
|
||||
map(0x49, MINECRAFT_1_20_5, true),
|
||||
map(0x4E, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(TransactionPacket.class, TransactionPacket::new,
|
||||
map(0x32, MINECRAFT_1_7_2, true),
|
||||
map(0x11, MINECRAFT_1_9, true),
|
||||
@@ -262,7 +271,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x2E, MINECRAFT_1_19_3, true),
|
||||
map(0x32, MINECRAFT_1_19_4, true),
|
||||
map(0x33, MINECRAFT_1_20_2, true),
|
||||
map(0x35, MINECRAFT_1_20_5, true));
|
||||
map(0x35, MINECRAFT_1_20_5, true),
|
||||
map(0x37, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(SetDefaultSpawnPositionPacket.class, SetDefaultSpawnPositionPacket::new,
|
||||
map(0x05, MINECRAFT_1_7_2, true),
|
||||
map(0x43, MINECRAFT_1_9, true),
|
||||
@@ -279,7 +289,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x50, MINECRAFT_1_19_4, true),
|
||||
map(0x52, MINECRAFT_1_20_2, true),
|
||||
map(0x54, MINECRAFT_1_20_3, true),
|
||||
map(0x56, MINECRAFT_1_20_5, true));
|
||||
map(0x56, MINECRAFT_1_20_5, true),
|
||||
map(0x5B, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(MapDataPacket.class, MapDataPacket::new,
|
||||
map(0x34, MINECRAFT_1_7_2, true),
|
||||
map(0x24, MINECRAFT_1_9, true),
|
||||
@@ -293,7 +304,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x25, MINECRAFT_1_19_3, true),
|
||||
map(0x29, MINECRAFT_1_19_4, true),
|
||||
map(0x2A, MINECRAFT_1_20_2, true),
|
||||
map(0x2C, MINECRAFT_1_20_5, true));
|
||||
map(0x2C, MINECRAFT_1_20_5, true),
|
||||
map(0x2D, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(SetContainerSlotPacket.class, SetContainerSlotPacket::new,
|
||||
map(0x2F, MINECRAFT_1_7_2, true),
|
||||
map(0x16, MINECRAFT_1_9, true),
|
||||
@@ -321,7 +333,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x56, MINECRAFT_1_19_4, true),
|
||||
map(0x58, MINECRAFT_1_20_2, true),
|
||||
map(0x5A, MINECRAFT_1_20_3, true),
|
||||
map(0x5C, MINECRAFT_1_20_5, true));
|
||||
map(0x5C, MINECRAFT_1_20_5, true),
|
||||
map(0x61, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(SystemChatPacket.class, SystemChatPacket::new,
|
||||
map(0x02, MINECRAFT_1_7_2, true),
|
||||
map(0x0F, MINECRAFT_1_9, true),
|
||||
@@ -335,12 +348,15 @@ public enum FallbackPacketRegistry {
|
||||
map(0x64, MINECRAFT_1_19_4, true),
|
||||
map(0x67, MINECRAFT_1_20_2, true),
|
||||
map(0x69, MINECRAFT_1_20_3, true),
|
||||
map(0x6C, MINECRAFT_1_20_5, true));
|
||||
map(0x6C, MINECRAFT_1_20_5, true),
|
||||
map(0x73, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(GameEventPacket.class, GameEventPacket::new,
|
||||
map(0x20, MINECRAFT_1_20_3, true),
|
||||
map(0x22, MINECRAFT_1_20_5, true));
|
||||
map(0x22, MINECRAFT_1_20_5, true),
|
||||
map(0x23, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(TransferPacket.class, TransferPacket::new,
|
||||
map(0x73, MINECRAFT_1_20_5, true));
|
||||
map(0x73, MINECRAFT_1_20_5, true),
|
||||
map(0x7A, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(SetHeldItemPacket.class, SetHeldItemPacket::new,
|
||||
map(0x09, MINECRAFT_1_7_2, true),
|
||||
map(0x37, MINECRAFT_1_9, true),
|
||||
@@ -357,7 +373,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x4D, MINECRAFT_1_19_4, true),
|
||||
map(0x4F, MINECRAFT_1_20_2, true),
|
||||
map(0x51, MINECRAFT_1_20_3, true),
|
||||
map(0x53, MINECRAFT_1_20_5, true));
|
||||
map(0x53, MINECRAFT_1_20_5, true),
|
||||
map(0x63, MINECRAFT_1_21_2, true));
|
||||
clientbound.register(EntityAnimationPacket.class, EntityAnimationPacket::new,
|
||||
map(0x0B, MINECRAFT_1_7_2, true),
|
||||
map(0x06, MINECRAFT_1_9, true),
|
||||
@@ -366,26 +383,27 @@ 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));
|
||||
clientbound.register(UpdateTimePacket.class, UpdateTimePacket::new,
|
||||
map(0x03, MINECRAFT_1_7_2, true),
|
||||
map(0x44, MINECRAFT_1_9, true),
|
||||
map(0x46, MINECRAFT_1_12, true),
|
||||
map(0x47, MINECRAFT_1_12_1, true),
|
||||
map(0x4A, MINECRAFT_1_13, true),
|
||||
map(0x4E, MINECRAFT_1_14, true),
|
||||
map(0x4F, MINECRAFT_1_15, true),
|
||||
map(0x4E, MINECRAFT_1_16, true),
|
||||
map(0x58, MINECRAFT_1_17, true),
|
||||
map(0x59, MINECRAFT_1_18, true),
|
||||
map(0x5C, MINECRAFT_1_19_1, true),
|
||||
map(0x5A, MINECRAFT_1_19_3, true),
|
||||
map(0x5E, MINECRAFT_1_19_4, true),
|
||||
map(0x60, MINECRAFT_1_20_2, true),
|
||||
map(0x62, MINECRAFT_1_20_3, true),
|
||||
map(0x64, MINECRAFT_1_20_5, true),
|
||||
map(0x6B, MINECRAFT_1_21_2, true));
|
||||
|
||||
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),
|
||||
@@ -398,7 +416,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x28, MINECRAFT_1_19_1, false),
|
||||
map(0x2B, MINECRAFT_1_20_2, false),
|
||||
map(0x2C, MINECRAFT_1_20_3, false),
|
||||
map(0x2F, MINECRAFT_1_20_5, false));
|
||||
map(0x2F, MINECRAFT_1_20_5, 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),
|
||||
@@ -413,7 +433,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x19, MINECRAFT_1_19_4, false),
|
||||
map(0x1B, MINECRAFT_1_20_2, false),
|
||||
map(0x1C, MINECRAFT_1_20_3, false),
|
||||
map(0x1F, MINECRAFT_1_20_5, false));
|
||||
map(0x1F, MINECRAFT_1_20_5, false),
|
||||
map(0x21, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(PlayerInputPacket.class, PlayerInputPacket::new,
|
||||
map(0x0C, MINECRAFT_1_7_2, false),
|
||||
map(0x15, MINECRAFT_1_9, false),
|
||||
@@ -428,7 +449,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x1F, MINECRAFT_1_19_4, false),
|
||||
map(0x22, MINECRAFT_1_20_2, false),
|
||||
map(0x23, MINECRAFT_1_20_3, false),
|
||||
map(0x26, MINECRAFT_1_20_5, false));
|
||||
map(0x26, MINECRAFT_1_20_5, 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),
|
||||
@@ -443,7 +466,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x18, MINECRAFT_1_19_4, false),
|
||||
map(0x1A, MINECRAFT_1_20_2, false),
|
||||
map(0x1B, MINECRAFT_1_20_3, false),
|
||||
map(0x1E, MINECRAFT_1_20_5, false));
|
||||
map(0x1E, MINECRAFT_1_20_5, false),
|
||||
map(0x20, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SystemChatPacket.class, SystemChatPacket::new,
|
||||
map(0x01, MINECRAFT_1_7_2, false),
|
||||
map(0x02, MINECRAFT_1_9, false),
|
||||
@@ -453,7 +477,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x04, MINECRAFT_1_19, false),
|
||||
map(0x05, MINECRAFT_1_19_1, false),
|
||||
map(0x05, MINECRAFT_1_19_3, false),
|
||||
map(0x06, MINECRAFT_1_20_5, false));
|
||||
map(0x06, MINECRAFT_1_20_5, false),
|
||||
map(0x07, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(KeepAlivePacket.class, KeepAlivePacket::new,
|
||||
map(0x00, MINECRAFT_1_7_2, false),
|
||||
map(0x0B, MINECRAFT_1_9, false),
|
||||
@@ -469,7 +494,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x12, MINECRAFT_1_19_4, false),
|
||||
map(0x14, MINECRAFT_1_20_2, false),
|
||||
map(0x15, MINECRAFT_1_20_3, false),
|
||||
map(0x18, MINECRAFT_1_20_5, false));
|
||||
map(0x18, MINECRAFT_1_20_5, false),
|
||||
map(0x1A, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(ClientInformationPacket.class, ClientInformationPacket::new,
|
||||
map(0x15, MINECRAFT_1_7_2, false),
|
||||
map(0x04, MINECRAFT_1_9, false),
|
||||
@@ -481,7 +507,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x07, MINECRAFT_1_19_3, false),
|
||||
map(0x08, MINECRAFT_1_19_4, false),
|
||||
map(0x09, MINECRAFT_1_20_2, false),
|
||||
map(0x0A, MINECRAFT_1_20_5, false));
|
||||
map(0x0A, MINECRAFT_1_20_5, 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),
|
||||
@@ -495,7 +522,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x0C, MINECRAFT_1_19_3, false),
|
||||
map(0x0D, MINECRAFT_1_19_4, false),
|
||||
map(0x0F, MINECRAFT_1_20_2, false),
|
||||
map(0x12, MINECRAFT_1_21, false));
|
||||
map(0x12, MINECRAFT_1_21, false),
|
||||
map(0x14, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SetPlayerOnGround.class, SetPlayerOnGround::new,
|
||||
map(0x03, MINECRAFT_1_7_2, false),
|
||||
map(0x0F, MINECRAFT_1_9, false),
|
||||
@@ -511,7 +539,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x17, MINECRAFT_1_19_4, false),
|
||||
map(0x19, MINECRAFT_1_20_2, false),
|
||||
map(0x1A, MINECRAFT_1_20_3, false),
|
||||
map(0x1D, MINECRAFT_1_20_5, false));
|
||||
map(0x1D, MINECRAFT_1_20_5, false),
|
||||
map(0x1F, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SetPlayerPositionPacket.class, SetPlayerPositionPacket::new,
|
||||
map(0x04, MINECRAFT_1_7_2, false),
|
||||
map(0x0C, MINECRAFT_1_9, false),
|
||||
@@ -527,7 +556,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x14, MINECRAFT_1_19_4, false),
|
||||
map(0x16, MINECRAFT_1_20_2, false),
|
||||
map(0x17, MINECRAFT_1_20_3, false),
|
||||
map(0x1A, MINECRAFT_1_20_5, false));
|
||||
map(0x1A, MINECRAFT_1_20_5, false),
|
||||
map(0x1C, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SetPlayerRotationPacket.class, SetPlayerRotationPacket::new,
|
||||
map(0x05, MINECRAFT_1_7_2, false),
|
||||
map(0x0E, MINECRAFT_1_9, false),
|
||||
@@ -543,7 +573,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x16, MINECRAFT_1_19_4, false),
|
||||
map(0x18, MINECRAFT_1_20_2, false),
|
||||
map(0x19, MINECRAFT_1_20_3, false),
|
||||
map(0x1C, MINECRAFT_1_20_5, false));
|
||||
map(0x1C, MINECRAFT_1_20_5, false),
|
||||
map(0x1E, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(SetPlayerPositionRotationPacket.class, SetPlayerPositionRotationPacket::new,
|
||||
map(0x06, MINECRAFT_1_7_2, false),
|
||||
map(0x0D, MINECRAFT_1_9, false),
|
||||
@@ -559,7 +590,8 @@ public enum FallbackPacketRegistry {
|
||||
map(0x15, MINECRAFT_1_19_4, false),
|
||||
map(0x17, MINECRAFT_1_20_2, false),
|
||||
map(0x18, MINECRAFT_1_20_3, false),
|
||||
map(0x1B, MINECRAFT_1_20_5, false));
|
||||
map(0x1B, MINECRAFT_1_20_5, false),
|
||||
map(0x1D, MINECRAFT_1_21_2, false));
|
||||
serverbound.register(ConfirmTeleportationPacket.class, ConfirmTeleportationPacket::new,
|
||||
map(0x00, MINECRAFT_1_9, false));
|
||||
serverbound.register(TransactionPacket.class, TransactionPacket::new,
|
||||
@@ -576,7 +608,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x20, MINECRAFT_1_19_4, false),
|
||||
map(0x23, MINECRAFT_1_20_2, false),
|
||||
map(0x24, MINECRAFT_1_20_3, false),
|
||||
map(0x27, MINECRAFT_1_20_5, false));
|
||||
map(0x27, MINECRAFT_1_20_5, 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),
|
||||
@@ -589,7 +623,9 @@ public enum FallbackPacketRegistry {
|
||||
map(0x2F, MINECRAFT_1_19_1, false),
|
||||
map(0x32, MINECRAFT_1_20_2, false),
|
||||
map(0x33, MINECRAFT_1_20_3, false),
|
||||
map(0x36, MINECRAFT_1_20_5, false));
|
||||
map(0x36, MINECRAFT_1_20_5, false),
|
||||
map(0x38, MINECRAFT_1_21_2, false),
|
||||
map(0x3A, MINECRAFT_1_21_4, false));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+46
-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
|
||||
@@ -19,70 +19,74 @@ package xyz.jonesdev.sonar.common.fallback.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
import io.netty.util.collection.IntObjectHashMap;
|
||||
import io.netty.util.collection.IntObjectMap;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
|
||||
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
|
||||
|
||||
import static xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion.ID_TO_PROTOCOL_CONSTANT;
|
||||
|
||||
// https://github.com/Nan1t/NanoLimbo/blob/main/src/main/java/ua/nanit/limbo/protocol/PacketSnapshot.java
|
||||
@Getter
|
||||
public final class FallbackPacketSnapshot implements FallbackPacket {
|
||||
private final Map<Integer, Integer> mappings = new HashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
private final Map<Integer, byte[]> cachedBytes = new HashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
private final FallbackPacket originalPacket;
|
||||
private final IntObjectMap<Integer> mappings = new IntObjectHashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
private final IntObjectMap<byte[]> cachedBytes = new IntObjectHashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
@Getter
|
||||
private final Class<? extends FallbackPacket> originalPacketClass;
|
||||
|
||||
public FallbackPacketSnapshot(final @NotNull FallbackPacket originalPacket) {
|
||||
final Map<Integer, Integer> hashes = new HashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
this.originalPacketClass = originalPacket.getClass();
|
||||
|
||||
final IntObjectMap<Integer> hashedData = new IntObjectHashMap<>(ID_TO_PROTOCOL_CONSTANT.size());
|
||||
|
||||
for (final ProtocolVersion protocolVersion : ID_TO_PROTOCOL_CONSTANT.values()) {
|
||||
// Allocate a buffer for each protocol version
|
||||
final ByteBuf byteBuf = Unpooled.buffer();
|
||||
try {
|
||||
originalPacket.encode(byteBuf, protocolVersion);
|
||||
} catch (Exception exception) {
|
||||
Sonar.get().getLogger().error("Could not encode packet {} for version {}: {}",
|
||||
originalPacket.toString(), protocolVersion, exception);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
originalPacket.encode(byteBuf, protocolVersion);
|
||||
} catch (Throwable throwable) {
|
||||
Sonar.get().getLogger().error("Could not encode packet {} for version {}: {}",
|
||||
originalPacket, protocolVersion, throwable);
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure we don't unnecessarily fill the RAM
|
||||
final int protocol = protocolVersion.getProtocol();
|
||||
final int hash = byteBuf.hashCode();
|
||||
final int hashed = hashes.getOrDefault(hash, -1);
|
||||
if (hashed != -1) {
|
||||
mappings.put(protocol, hashed);
|
||||
} else {
|
||||
hashes.put(hash, protocol);
|
||||
mappings.put(protocol, protocol);
|
||||
// Cache the raw bytes of the encoded packet
|
||||
final byte[] bytes = new byte[byteBuf.readableBytes()];
|
||||
byteBuf.readBytes(bytes);
|
||||
cachedBytes.put(protocol, bytes);
|
||||
final Integer protocol = protocolVersion.getProtocol();
|
||||
final Integer hash = byteBuf.hashCode();
|
||||
final Integer hashed = hashedData.getOrDefault(hash, -1);
|
||||
|
||||
if (hashed != -1) {
|
||||
mappings.put(protocol, hashed);
|
||||
} else {
|
||||
hashedData.put(hash, protocol);
|
||||
mappings.put(protocol, protocol);
|
||||
// Cache the raw bytes of the encoded packet
|
||||
final byte[] bytes = new byte[byteBuf.readableBytes()];
|
||||
byteBuf.readBytes(bytes);
|
||||
cachedBytes.put(protocol, bytes);
|
||||
}
|
||||
} finally {
|
||||
// Make sure to release the buffer to avoid memory leaks
|
||||
byteBuf.release();
|
||||
}
|
||||
// Make sure to release the buffer to avoid memory leaks
|
||||
byteBuf.release();
|
||||
}
|
||||
this.originalPacket = originalPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(final @NotNull ByteBuf byteBuf,
|
||||
final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
final int hash = mappings.get(protocolVersion.getProtocol());
|
||||
final byte[] bytes = cachedBytes.get(hash);
|
||||
|
||||
if (bytes != null) {
|
||||
byteBuf.writeBytes(bytes);
|
||||
} else {
|
||||
Sonar.get().getLogger().error("Could not find cached packet {} for version {}",
|
||||
toString(), protocolVersion);
|
||||
throw new IllegalStateException("Unable to find cached packet. Contact the developer!");
|
||||
public void encode(final @NotNull ByteBuf byteBuf, final @NotNull ProtocolVersion protocolVersion) throws Exception {
|
||||
final Integer hash = mappings.get(protocolVersion.getProtocol());
|
||||
if (hash == null) {
|
||||
throw ProtocolUtil.DEBUG ? new EncoderException("Unable to find hash") : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
final byte[] bytes = cachedBytes.get(hash);
|
||||
if (bytes == null) {
|
||||
throw ProtocolUtil.DEBUG ? new EncoderException("Unable to find cached packet") : QuietDecoderException.INSTANCE;
|
||||
}
|
||||
byteBuf.writeBytes(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+83
-52
@@ -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
|
||||
@@ -22,15 +22,18 @@ import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.IntBinaryTag;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
import xyz.jonesdev.sonar.api.config.SonarConfiguration;
|
||||
import xyz.jonesdev.sonar.api.event.impl.CaptchaGenerationStartEvent;
|
||||
import xyz.jonesdev.sonar.api.fallback.protocol.ProtocolVersion;
|
||||
import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.block.BlockUpdate;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.captcha.CaptchaPreparer;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionRegistry;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.dimension.DimensionType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.entity.EntityType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.item.ItemType;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration.FinishConfigurationPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.configuration.RegistryDataPacket;
|
||||
import xyz.jonesdev.sonar.common.fallback.protocol.packets.login.LoginSuccessPacket;
|
||||
@@ -47,38 +50,54 @@ public class FallbackPreparer {
|
||||
public static final int PLAYER_ENTITY_ID = RANDOM.nextInt();
|
||||
public static final int VEHICLE_ENTITY_ID = RANDOM.nextInt();
|
||||
|
||||
public static final CompoundBinaryTag MAP_ITEM_NBT = CompoundBinaryTag.builder()
|
||||
.put("map", IntBinaryTag.intBinaryTag(0)) // map type
|
||||
.build();
|
||||
|
||||
public static final BlockType[] POSSIBLE_BLOCK_TYPES = BlockType.values();
|
||||
public final FallbackPacket[] BLOCKS_PACKETS = new FallbackPacket[POSSIBLE_BLOCK_TYPES.length];
|
||||
|
||||
public final int BLOCKS_PER_ROW = 8; // 8 * 8 = 64 (vanilla protocol maximum)
|
||||
public final int SPAWN_X_POSITION = 16 / 2; // middle of the chunk
|
||||
public final int SPAWN_Z_POSITION = 16 / 2; // middle of the chunk
|
||||
public final int DEFAULT_Y_COLLIDE_POSITION = 1 + RANDOM.nextInt(255); // 255 is the maximum Y position
|
||||
public final int IN_AIR_Y_POSITION = 1000 + RANDOM.nextInt(338); // High altitude (randomized)
|
||||
public final int IN_VOID_Y_POSITION = -(120 + RANDOM.nextInt(120)); // Low altitude (randomized)
|
||||
public final int PLATFORM_Y_POSITION = 1 + RANDOM.nextInt(255); // 255 is the maximum Y position
|
||||
public final int IN_AIR_Y_POSITION = 3000 + RANDOM.nextInt(500); // Random high altitude
|
||||
|
||||
public final int FIRST_TELEPORT_ID = RANDOM.nextInt();
|
||||
public final int SECOND_TELEPORT_ID = RANDOM.nextInt();
|
||||
public final int PRE_JOIN_KEEP_ALIVE_ID = RANDOM.nextInt();
|
||||
|
||||
private final int MAP_SLOT = RANDOM.nextInt(9);
|
||||
|
||||
public static final FallbackPacket CAPTCHA_SET_CONTAINER_SLOT = new SetContainerSlotPacket(
|
||||
0, 36 + MAP_SLOT, 1, ItemType.FILLED_MAP, CompoundBinaryTag.builder()
|
||||
.put("map", IntBinaryTag.intBinaryTag(0)) // map id
|
||||
.build());
|
||||
public final static FallbackPacket CAPTCHA_HELD_ITEM_SLOT = new SetHeldItemPacket(MAP_SLOT);
|
||||
public final FallbackPacket DEFAULT_ABILITIES = new PlayerAbilitiesPacket(0x00, 0, 0);
|
||||
public final FallbackPacket NO_MOVE_ABILITIES = new PlayerAbilitiesPacket(0x02, 0, 0);
|
||||
public final FallbackPacket NO_MOVE_ABILITIES_BEDROCK = new PlayerAbilitiesPacket(0x06, 0, 0);
|
||||
public final FallbackPacket CAPTCHA_POSITION = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION, 0, 90, 0, 0, false));
|
||||
SPAWN_X_POSITION, 10000, SPAWN_Z_POSITION, 0, 90, 0, 0, false, false, true));
|
||||
public final FallbackPacket EMPTY_CHUNK_DATA = new FallbackPacketSnapshot(new ChunkDataPacket(0, 0));
|
||||
public final FallbackPacket FINISH_CONFIGURATION = new FinishConfigurationPacket();
|
||||
public final FallbackPacket REGISTRY_SYNC_LEGACY = new FallbackPacketSnapshot(new RegistryDataPacket(DimensionRegistry.CODEC_1_20, null, null));
|
||||
public final FallbackPacket[] REGISTRY_SYNC_1_20_5 = RegistryDataPacket.of(DimensionRegistry.CODEC_1_20);
|
||||
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_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 CACHED_HELD_ITEM_SLOT = new SetHeldItemPacket(~4);
|
||||
public final FallbackPacket CAPTCHA_KEEP_ALIVE = new KeepAlivePacket(RANDOM.nextInt());
|
||||
public final static FallbackPacket INVALID_HELD_ITEM_SLOT = new SetHeldItemPacket(-1);
|
||||
public final FallbackPacket RANDOM_KEEP_ALIVE = new FallbackPacketSnapshot(new KeepAlivePacket(RANDOM.nextInt()));
|
||||
public static final FallbackPacket SPAWN_BOAT_ENTITY = new FallbackPacketSnapshot(new SpawnEntityPacket(
|
||||
VEHICLE_ENTITY_ID, EntityType.BOAT, SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
|
||||
0, 0, 0, 0));
|
||||
public static final FallbackPacket SPAWN_MINECART_ENTITY = new FallbackPacketSnapshot(new SpawnEntityPacket(
|
||||
VEHICLE_ENTITY_ID, EntityType.MINECART, SPAWN_X_POSITION, IN_AIR_Y_POSITION - 16, SPAWN_Z_POSITION,
|
||||
0, 0, 0, 0));
|
||||
public static final FallbackPacket REMOVE_VEHICLE = new RemoveEntitiesPacket(VEHICLE_ENTITY_ID);
|
||||
public static final FallbackPacket SET_VEHICLE_PASSENGERS = new FallbackPacketSnapshot(
|
||||
new SetPassengersPacket(VEHICLE_ENTITY_ID, PLAYER_ENTITY_ID));
|
||||
|
||||
public static FallbackPacket loginSuccess;
|
||||
public FallbackPacket loginSuccess;
|
||||
public FallbackPacket welcomeMessage;
|
||||
public FallbackPacket enterCodeMessage;
|
||||
public FallbackPacket incorrectCaptcha;
|
||||
@@ -93,14 +112,10 @@ public class FallbackPreparer {
|
||||
public FallbackPacket alreadyVerifying;
|
||||
public FallbackPacket reconnectedTooFast;
|
||||
public FallbackPacket protocolBlacklisted;
|
||||
public FallbackPacket invalidUsername;
|
||||
public FallbackPacket unsupportedVersion;
|
||||
public FallbackPacket tooManyOnlinePerIP;
|
||||
public FallbackPacket removeBoat;
|
||||
public FallbackPacket teleportMinecart;
|
||||
public FallbackPacket spawnBoatEntity;
|
||||
public FallbackPacket spawnMinecartEntity;
|
||||
public FallbackPacket setPassengers;
|
||||
public FallbackPacket[] xpCountdown;
|
||||
public FallbackPacket updateTime;
|
||||
|
||||
public static int maxMovementTick, dynamicSpawnYPosition, maxTotalPacketsSent;
|
||||
|
||||
@@ -110,16 +125,23 @@ public class FallbackPreparer {
|
||||
Sonar.get().getLogger().info("Preloading all registered packets...");
|
||||
FallbackPacketRegistry.values();
|
||||
|
||||
// Prepare LoginSuccess packet
|
||||
loginSuccess = new FallbackPacketSnapshot(new LoginSuccessPacket(UUID.randomUUID(),
|
||||
Sonar.get().getConfig().getGeneralConfig().getString("verification.cached-username")));
|
||||
// Prepare LoginSuccess packet with capped username to 16 characters
|
||||
final UUID uuid = UUID.randomUUID();
|
||||
String username = Sonar.get().getConfig().getGeneralConfig().getString("verification.cached-username");
|
||||
if (username.length() > 16) {
|
||||
username = username.substring(0, 16);
|
||||
}
|
||||
loginSuccess = new FallbackPacketSnapshot(new LoginSuccessPacket(uuid, username, true));
|
||||
|
||||
// Prepare JoinGame packet
|
||||
joinGame = new FallbackPacketSnapshot(new JoinGamePacket(PLAYER_ENTITY_ID,
|
||||
Sonar.get().getConfig().getVerification().getGamemode().getId(), RANDOM.nextLong(),
|
||||
0, 0, false, true, false,
|
||||
false, false, false, true,
|
||||
new String[]{"minecraft:overworld"}, "minecraft:overworld", "flat"));
|
||||
Sonar.get().getConfig().getVerification().getGamemode().getId(),
|
||||
-1, 0, 0,
|
||||
RANDOM.nextInt(3), 1, 0, 0,
|
||||
new String[]{"lol"}, "lol", "flat",
|
||||
DimensionType.OVERWORLD, RANDOM.nextLong() & 1337,
|
||||
false, true, false,
|
||||
false, false, false, true));
|
||||
|
||||
// Prepare the gravity check
|
||||
maxMovementTick = Sonar.get().getConfig().getVerification().getGravity().getMaxMovementTicks();
|
||||
@@ -132,18 +154,18 @@ public class FallbackPreparer {
|
||||
}
|
||||
|
||||
// Set the dynamic block and collide Y position based on the maximum fall distance
|
||||
dynamicSpawnYPosition = DEFAULT_Y_COLLIDE_POSITION + (int) Math.ceil(fallDistance);
|
||||
dynamicSpawnYPosition = PLATFORM_Y_POSITION + (int) Math.ceil(fallDistance);
|
||||
defaultSpawnPosition = new FallbackPacketSnapshot(new SetDefaultSpawnPositionPacket(
|
||||
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION));
|
||||
spawnPosition = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
|
||||
0, 0, FIRST_TELEPORT_ID, 0, false));
|
||||
0, 0, FIRST_TELEPORT_ID, 0, false, false, true));
|
||||
fallStartPosition = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, dynamicSpawnYPosition - IN_AIR_Y_POSITION, SPAWN_Z_POSITION,
|
||||
0, -90, SECOND_TELEPORT_ID, 1 << 1, false));
|
||||
0, -90, SECOND_TELEPORT_ID, 1 << 1, false, false, true));
|
||||
fallStartPositionLegacy = new FallbackPacketSnapshot(new SetPlayerPositionRotationPacket(
|
||||
SPAWN_X_POSITION, dynamicSpawnYPosition, SPAWN_Z_POSITION,
|
||||
0, -90, 0, 0, false));
|
||||
0, -90, 0, 0, false, false, true));
|
||||
|
||||
// Prepare collision platform positions
|
||||
final int length = BLOCKS_PER_ROW / 2;
|
||||
@@ -154,21 +176,21 @@ public class FallbackPreparer {
|
||||
for (int x = 0; x < BLOCKS_PER_ROW; x++) {
|
||||
for (int z = 0; z < BLOCKS_PER_ROW; z++) {
|
||||
final BlockUpdate.BlockPosition position = new BlockUpdate.BlockPosition(
|
||||
x + length, DEFAULT_Y_COLLIDE_POSITION, z + length, 0, 0);
|
||||
x + length, PLATFORM_Y_POSITION, z + length, 0, 0);
|
||||
blocks[index++] = new BlockUpdate(position, POSSIBLE_BLOCK_TYPES[i]);
|
||||
}
|
||||
}
|
||||
BLOCKS_PACKETS[i] = new UpdateSectionBlocksPacket(0, 0, blocks);
|
||||
BLOCKS_PACKETS[i] = new FallbackPacketSnapshot(new UpdateSectionBlocksPacket(0, 0, blocks));
|
||||
}
|
||||
|
||||
// Prepare disconnect packets during login
|
||||
blacklisted = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getBlacklisted(), true));
|
||||
alreadyVerifying = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getAlreadyVerifying(), true));
|
||||
alreadyQueued = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getAlreadyQueued(), true));
|
||||
protocolBlacklisted = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getProtocolBlacklisted(), true));
|
||||
reconnectedTooFast = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getTooFastReconnect(), true));
|
||||
invalidUsername = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getVerification().getInvalidUsername(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(DisconnectPacket.create(Sonar.get().getConfig().getTooManyOnlinePerIp(), true));
|
||||
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));
|
||||
unsupportedVersion = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getVerification().getUnsupportedVersion(), true));
|
||||
tooManyOnlinePerIP = new FallbackPacketSnapshot(new DisconnectPacket(Sonar.get().getConfig().getTooManyOnlinePerIp(), true));
|
||||
|
||||
// Prepare transfer packet
|
||||
if (Sonar.get().getConfig().getGeneralConfig().getBoolean("verification.transfer.enabled")) {
|
||||
@@ -179,17 +201,13 @@ public class FallbackPreparer {
|
||||
transferToOrigin = null;
|
||||
}
|
||||
|
||||
// Prepare packets for the vehicle check
|
||||
removeBoat = new RemoveEntitiesPacket(VEHICLE_ENTITY_ID);
|
||||
teleportMinecart = new TeleportEntityPacket(
|
||||
VEHICLE_ENTITY_ID, SPAWN_X_POSITION, IN_VOID_Y_POSITION, SPAWN_Z_POSITION, false);
|
||||
spawnBoatEntity = new FallbackPacketSnapshot(new SpawnEntityPacket(VEHICLE_ENTITY_ID,
|
||||
EntityType.BOAT, RANDOM.nextInt(16), IN_AIR_Y_POSITION, RANDOM.nextInt(16),
|
||||
0, 0, 0, 0));
|
||||
spawnMinecartEntity = new FallbackPacketSnapshot(new SpawnEntityPacket(VEHICLE_ENTITY_ID,
|
||||
EntityType.MINECART, RANDOM.nextInt(16), IN_AIR_Y_POSITION, RANDOM.nextInt(16),
|
||||
0, 0, 0, 0));
|
||||
setPassengers = new FallbackPacketSnapshot(new SetPassengersPacket(VEHICLE_ENTITY_ID, PLAYER_ENTITY_ID));
|
||||
// Prepare update time packet
|
||||
final int timeOfDay = Sonar.get().getConfig().getVerification().getTimeOfDay();
|
||||
if (timeOfDay != 1000) {
|
||||
updateTime = new UpdateTimePacket(0L, timeOfDay, false);
|
||||
} else {
|
||||
updateTime = null;
|
||||
}
|
||||
|
||||
// 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");
|
||||
@@ -250,4 +268,17 @@ public class FallbackPreparer {
|
||||
+ Sonar.get().getConfig().getVerification().getMap().getMaxTries()
|
||||
+ 150 /* some arbitrary leeway */;
|
||||
}
|
||||
|
||||
public static FallbackPacket[] getRegistryPackets(final @NotNull ProtocolVersion protocolVersion) {
|
||||
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;
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_21)) {
|
||||
return REGISTRY_SYNC_1_21;
|
||||
} else if (protocolVersion.greaterThanOrEquals(ProtocolVersion.MINECRAFT_1_20_5)) {
|
||||
return REGISTRY_SYNC_1_20_5;
|
||||
}
|
||||
return REGISTRY_SYNC_1_20;
|
||||
}
|
||||
}
|
||||
+125
-83
@@ -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,251 +36,293 @@ public enum BlockType {
|
||||
// - https://github.com/ViaVersion/Mappings/tree/main/mappings
|
||||
//STONE(protocolVersion -> 1, 1),
|
||||
ENCHANTMENT_TABLE(protocolVersion -> {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 116;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 4612;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 4613;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 5116;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 5132;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 5136;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 5333;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 5719;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 7159;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 7385;
|
||||
}
|
||||
return 7389;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 7389;
|
||||
}
|
||||
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
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_7_6) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_7_6)) {
|
||||
return 96;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 167;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 6509;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 6510;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 7016;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 7552;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 7556;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 7802;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 8293;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 9937;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 10269;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_20) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_20)) {
|
||||
return 10273;
|
||||
}
|
||||
return 10414;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 10414;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 10749;
|
||||
}
|
||||
return 11293;
|
||||
}, protocolVersion -> 0.1875),
|
||||
END_PORTAL_FRAME(protocolVersion -> {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 120;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 4633;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 4634;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 5137;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 5153;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 5157;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 5358;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 5744;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 7184;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 7410;
|
||||
}
|
||||
return 7414;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 7414;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 7644;
|
||||
}
|
||||
return 8185;
|
||||
}, protocolVersion -> 0.8125),
|
||||
DAYLIGHT_SENSOR(protocolVersion -> {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 151;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 5651;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 5652;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 6158;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 6694;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 6698;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 6916;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 7327;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 8811;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 9063;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_20) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_20)) {
|
||||
return 9067;
|
||||
}
|
||||
return 9207;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 9207;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 9462;
|
||||
}
|
||||
return 10006;
|
||||
}, protocolVersion -> 0.375),
|
||||
COBBLESTONE_WALL(protocolVersion -> {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 139;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 5196;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 5197;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 5700;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 5660;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 5664;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 5866;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 6252;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 7692;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 7918;
|
||||
}
|
||||
return 7922;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 7922;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 8152;
|
||||
}
|
||||
return 8696;
|
||||
}, protocolVersion -> 1.5),
|
||||
STONE_SLABS(protocolVersion -> {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 44;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 7296;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 7297;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 7809;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 8345;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 8349;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 8595;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 9092;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 10748;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 11086;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_20) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_20)) {
|
||||
return 11090;
|
||||
}
|
||||
return 11231;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 11231;
|
||||
}
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21_2)) {
|
||||
return 11566;
|
||||
}
|
||||
return 12110;
|
||||
}, protocolVersion -> 0.5),
|
||||
WHITE_CARPET(protocolVersion -> {
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_12_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_12_2)) {
|
||||
return 171;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_1)) {
|
||||
return 6823;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_13_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_13_2)) {
|
||||
return 6824;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_15_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_15_2)) {
|
||||
return 7330;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_1)) {
|
||||
return 7866;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_16_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_16_4)) {
|
||||
return 7870;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_18_2) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_18_2)) {
|
||||
return 8116;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_1) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_1)) {
|
||||
return 8607;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_3) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_3)) {
|
||||
return 10251;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_19_4) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_19_4)) {
|
||||
return 10583;
|
||||
}
|
||||
if (protocolVersion.compareTo(MINECRAFT_1_20) <= 0) {
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_20)) {
|
||||
return 10587;
|
||||
}
|
||||
return 10728;
|
||||
if (protocolVersion.lessThanOrEquals(MINECRAFT_1_21)) {
|
||||
return 10728;
|
||||
}
|
||||
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;
|
||||
|
||||
+2
-4
@@ -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
|
||||
@@ -19,12 +19,11 @@ package xyz.jonesdev.sonar.common.fallback.protocol.block;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Getter
|
||||
public final class BlockUpdate {
|
||||
private final @NotNull BlockPosition position;
|
||||
private final BlockPosition position;
|
||||
private final BlockType blockType;
|
||||
private final int legacyBlockState, blockState;
|
||||
|
||||
@@ -39,7 +38,6 @@ public final class BlockUpdate {
|
||||
}
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public static final class BlockPosition {
|
||||
private final int x, y, z;
|
||||
|
||||
+8
-16
@@ -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,10 +18,8 @@
|
||||
package xyz.jonesdev.sonar.common.fallback.protocol.dimension;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.kyori.adventure.nbt.BinaryTag;
|
||||
import net.kyori.adventure.nbt.BinaryTagIO;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
import net.kyori.adventure.nbt.ListBinaryTag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jonesdev.sonar.api.Sonar;
|
||||
|
||||
@@ -37,10 +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 DimensionInfo DEFAULT_DIMENSION_1_16_2;
|
||||
public final DimensionInfo DEFAULT_DIMENSION_1_18_2;
|
||||
public final CompoundBinaryTag CODEC_1_21_2;
|
||||
public final CompoundBinaryTag CODEC_1_21_4;
|
||||
|
||||
static {
|
||||
CODEC_1_16 = getCodec("codec_1_16.nbt");
|
||||
@@ -50,24 +48,18 @@ 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");
|
||||
|
||||
DEFAULT_DIMENSION_1_16_2 = getDimension(CODEC_1_16_2);
|
||||
DEFAULT_DIMENSION_1_18_2 = getDimension(CODEC_1_18_2);
|
||||
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);
|
||||
throw new IllegalStateException(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull DimensionInfo getDimension(final @NotNull CompoundBinaryTag tag) {
|
||||
final ListBinaryTag dimensions = tag.getCompound("minecraft:dimension_type").getList("value");
|
||||
final BinaryTag elementTag = ((CompoundBinaryTag) dimensions.get(0)).get("element");
|
||||
return new DimensionInfo("minecraft:overworld", 0, (CompoundBinaryTag) elementTag);
|
||||
}
|
||||
}
|
||||
+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
|
||||
@@ -19,14 +19,14 @@ package xyz.jonesdev.sonar.common.fallback.protocol.dimension;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import net.kyori.adventure.nbt.CompoundBinaryTag;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public final class DimensionInfo {
|
||||
private final String identifier;
|
||||
private final int id;
|
||||
private final CompoundBinaryTag tag;
|
||||
public enum DimensionType {
|
||||
OVERWORLD("minecraft:overworld", 0, 0),
|
||||
THE_NETHER("minecraft:the_nether", -1, 1),
|
||||
THE_END("minecraft:the_end", 1, 2);
|
||||
|
||||
private final String key;
|
||||
private final int legacyId, id;
|
||||
}
|
||||
Loaded 100 of 212 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user