Compare commits

..
18 Commits
Author SHA1 Message Date
Jones 70506aaf64 Release 2.1.45 (#553) 2026-02-02 14:58:32 +01:00
Jones 873d9f8c10 Use JDK 21 for GitHub Actions 2026-02-02 14:55:08 +01:00
Jones 8f40552dc5 Replace broken sonatype OSS repository link 2026-02-02 14:50:52 +01:00
dependabot[bot] 6302888a33 Bump gradle-wrapper from 9.3.0 to 9.3.1 (#552)
Bumps gradle-wrapper from 9.3.0 to 9.3.1.

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 14:46:37 +01:00
dependabot[bot] ea7cc9a9f3 Bump com.diffplug.spotless from 8.2.0 to 8.2.1 (#551)
Bumps com.diffplug.spotless from 8.2.0 to 8.2.1.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-02 14:46:27 +01:00
Jones ea928ce6db Add experimental config option for checking Eagler players 2026-02-01 10:29:17 +01:00
Jones d19ee78c41 Bump velocity-proxy from 3.4.0-SNAPSHOT to 3.5.0-SNAPSHOT 2026-02-01 10:20:10 +01:00
Jones 924f4e7344 Bump caffeine from 3.2.2/3.2.0 to 3.2.3 2026-02-01 10:15:54 +01:00
dependabot[bot] 6e4c938767 Bump gradle-wrapper from 8.14.3 to 9.3.0 (#549)
Bumps gradle-wrapper from 8.14.3 to 9.3.0.

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.3.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-01 10:08:06 +01:00
dependabot[bot] e534738336 Bump com.diffplug.spotless from 7.2.1 to 8.2.0 (#550)
Bumps com.diffplug.spotless from 7.2.1 to 8.2.0.

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 16:05:09 +01:00
bobhenl 92d40ca4cf Fix skipping EaglerCraft players & error on join (#547)
* fix: fix skipping EaglerCraft players & error on join

* docs: improve eagler comment
2026-01-15 21:00:12 +01:00
Jones 0fd7f0c173 Release 2.1.44 (#545) 2026-01-10 22:25:43 +01:00
Jones f197260426 Always skip EaglerCraft players 2026-01-10 22:10:15 +01:00
Squesly cbae477982 Fix connection has already been closed (#544)
* Fixed a MySQL issue: connection has already been closed.

* Fixed import
2026-01-10 09:55:51 +01:00
JohnandJones 878789b2c1 Add Paper platform (#541)
* Add paper platform

* Fix package name for Paper module

* Load adventure-nbt library on paper

* Add missing license header

---------

Co-authored-by: Jones <admin@jonesdev.xyz>
2026-01-05 15:04:59 +01:00
Jones 2a98d4bdb0 Remove mentions of nonexistent tests in dependencies 2026-01-01 13:37:17 +01:00
Jones 790d233870 Make LibraryLoader use correct MiniMessage versions 2026-01-01 13:10:54 +01:00
Jones e732da6af2 [skip ci] Update sponsors 2025-12-27 00:42:30 +01:00
34 changed files with 485 additions and 139 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
patreon: jonesdev
+2 -3
View File
@@ -55,12 +55,11 @@ Sonar is unlikely to ever falsely prevent a player from joining the server since
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/Chumb3x"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/79834154?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
If you are interested in sponsoring this project, please contact me via [Discord](https://jonesdev.xyz/discord/).
### Past Sponsors
<a href="https://github.com/Chumb3x"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/79834154?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
<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>
<a href="https://github.com/ItzErpandX"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/84748484?v=4?s=400?v=4&h=50&w=50&fit=cover&mask=circle&maxage=7d" alt="logo" align="center"></a>
+2 -2
View File
@@ -23,10 +23,10 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
- name: Setup Gradle
@@ -30,6 +30,8 @@ public enum SonarPlatform {
pipeline -> pipeline.context("outbound_config") != null ? "outbound_config" : "encoder"),
BUNGEE("BungeeCord", 19109, "inbound-boss",
pipeline -> "packet-encoder"),
PAPER("Paper", 19110, "packet_handler",
pipeline -> pipeline.context("outbound_config") != null ? "outbound_config" : "encoder"),
VELOCITY("Velocity", 19107, "handler",
pipeline -> "minecraft-encoder");
@@ -201,6 +201,7 @@ public final class SonarConfiguration {
verification.validNameRegex = Pattern.compile(generalConfig.getString("verification.checks.valid-name-regex"));
verification.checkGeyser = generalConfig.getBoolean("verification.check-geyser-players");
verification.checkEagler = generalConfig.getBoolean("verification.check-eagler-players");
verification.logConnections = generalConfig.getBoolean("verification.log-connections");
verification.logDuringAttack = generalConfig.getBoolean("verification.log-during-attack");
verification.debugXYZPositions = generalConfig.getBoolean("verification.debug-xyz-positions");
@@ -415,6 +416,7 @@ public final class SonarConfiguration {
private int timeOfDay;
private boolean checkGeyser;
private boolean checkEagler;
private boolean logConnections;
private boolean logDuringAttack;
private boolean debugXYZPositions;
@@ -20,7 +20,7 @@ package xyz.jonesdev.sonar.api.database.controller;
import com.alessiodp.libby.LibraryManager;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.jdbc.JdbcPooledConnectionSource;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
@@ -93,7 +93,7 @@ public final class VerifiedPlayerController {
"?autoReconnect=true");
}
connectionSource = new JdbcConnectionSource(jdbcURL,
connectionSource = new JdbcPooledConnectionSource(jdbcURL,
Sonar.get0().getConfig().getGeneralConfig().getString("database.username"),
Sonar.get0().getConfig().getGeneralConfig().getString("database.password"),
cachedDatabaseType.getDatabaseType());
+2 -2
View File
@@ -11,7 +11,7 @@ allprojects {
repositories {
mavenCentral()
maven(url = "https://repo.jonesdev.xyz/releases/") // Bungee & Velocity proxy module
maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") // libby
maven(url = "https://repo.alessiodp.com/snapshots/") // libby
}
apply(plugin = "java")
@@ -102,7 +102,7 @@ allprojects {
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 subprojects = listOf("api", "captcha", "common", "bukkit", "bungeecord", "paper", "velocity")
val buildTasks = subprojects.flatMap { listOf("$it:clean", "$it:spotlessApply", "$it:shadowJar") }
dependsOn(buildTasks)
}
-1
View File
@@ -32,7 +32,6 @@ dependencies {
implementation(project(":common"))
compileOnly(rootProject.libs.spigot)
testCompileOnly(rootProject.libs.spigot)
implementation(rootProject.libs.adventure.platform.bukkit) {
exclude(module = "adventure-nbt")
-1
View File
@@ -14,7 +14,6 @@ dependencies {
implementation(project(":common"))
compileOnly(rootProject.libs.bungeecord)
testCompileOnly(rootProject.libs.bungeecord)
implementation(rootProject.libs.adventure.platform.bungee) {
exclude(module = "adventure-nbt")
@@ -30,6 +30,7 @@ import xyz.jonesdev.sonar.common.protocol.SonarPacket;
import xyz.jonesdev.sonar.common.protocol.SonarPacketEncoder;
import xyz.jonesdev.sonar.common.protocol.SonarPacketRegistry;
import xyz.jonesdev.sonar.common.statistics.GlobalSonarStatistics;
import xyz.jonesdev.sonar.common.util.EaglerUtil;
import xyz.jonesdev.sonar.common.util.GeyserUtil;
import xyz.jonesdev.sonar.common.util.ProtocolUtil;
import xyz.jonesdev.sonar.common.util.exception.QuietDecoderException;
@@ -132,6 +133,13 @@ public abstract class InboundHandlerAdapter extends ChannelInboundHandlerAdapter
return;
}
// Completely skip EaglercraftX connections if configured
if (EaglerUtil.isEaglerConnection(ctx.channel())
&& !Sonar.get0().getConfig().getVerification().isCheckEagler()) {
initialLogin(ctx.channel(), inetAddress, initialLoginAction);
return;
}
// Make sure we actually have to verify the player
final String fingerprint = FingerprintingUtil.getFingerprint(username, hostAddress);
if (Sonar.get0().getVerifiedPlayerController().getCache().contains(fingerprint)) {
@@ -191,6 +199,7 @@ public abstract class InboundHandlerAdapter extends ChannelInboundHandlerAdapter
// Don't remove floodgate's pipelines
|| entry.getKey().startsWith("geyser")
|| entry.getKey().startsWith("floodgate")
|| entry.getKey().startsWith("eagler")
|| entry.getKey().equals("DefaultChannelPipeline$TailContext#0")) {
continue;
}
@@ -47,7 +47,7 @@ class LibraryLoader {
Library.builder()
.groupId("com{}github{}ben-manes{}caffeine")
.artifactId("caffeine")
.version("3.2.0")
.version("3.2.3")
.relocate("com{}github{}benmanes{}caffeine", "xyz{}jonesdev{}sonar{}libs{}caffeine")
.build(),
// ORMLite
@@ -68,26 +68,38 @@ class LibraryLoader {
// Only load adventure if not on Velocity
if (platform != SonarPlatform.VELOCITY) {
libraryManager.loadLibraries(
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-minimessage")
.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.18.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("4.18.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build()
);
if (platform != SonarPlatform.PAPER) {
libraryManager.loadLibraries(
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-minimessage")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-serializer-gson")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("4.21.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build()
);
} else {
// On Paper, we only relocate the nbt package since the rest of adventure is bundled with the server.
libraryManager.loadLibrary(
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("4.21.0")
.relocate("net{}kyori{}adventure{}nbt", "xyz{}jonesdev{}sonar{}libs{}kyori{}adventure{}nbt")
.build()
);
}
}
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2025 Sonar Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package xyz.jonesdev.sonar.common.util;
import io.netty.channel.Channel;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
@UtilityClass
public class EaglerUtil {
// Detect EaglerXServer WebSocket connections by checking for Eagler-specific pipeline handlers.
private static final String H_EAGLER_HANDSHAKE = "eagler-handshake";
private static final String H_EAGLER_FRAME_CODEC = "eagler-frame-codec";
public boolean isEaglerConnection(final @NotNull Channel channel) {
return channel.pipeline().get(H_EAGLER_HANDSHAKE) != null
|| channel.pipeline().get(H_EAGLER_FRAME_CODEC) != null;
}
}
@@ -187,6 +187,9 @@ verification:
# Tato funkce je experimentální a může způsobit problémy
# Pokud je toto zakázáno, hráči Bedrock budou přeskočeni
check-geyser-players: false
# Měl by Sonar kontrolovat také hráče EaglercraftX?
# Tato funkce je experimentální a může způsobit problémy.
check-eagler-players: false
# Doba, za kterou hráč přestal odesílat pakety před odpojením
# (Hodnota udávaná v milisekundách: 1 sekunda = 1000 milisekund)
read-timeout: 8000
@@ -184,6 +184,9 @@ verification:
# Diese Funktion ist experimentell und kann Probleme verursachen
# Wenn dies deaktiviert ist, werden Bedrock-Spieler übersprungen
check-geyser-players: false
# Sollte Sonar auch EaglercraftX-Spieler überprüfen?
# Diese Funktion ist experimentell und kann zu Problemen führen.
check-eagler-players: false
# Die Zeit, seit der der Spieler keine Pakete mehr sendet, bevor er die Verbindung trennt
# (Dieser Wert stellt die Zeit in Millisekunden dar: 1 Sekunde = 1000 Millisekunden)
read-timeout: 8000
@@ -187,6 +187,9 @@ verification:
# This feature is experimental and might cause issues
# If this is disabled, Bedrock players will be skipped
check-geyser-players: false
# Should Sonar also check EaglercraftX players?
# This feature is experimental and might cause issues
check-eagler-players: false
# The time since the player stopped sending packets before disconnecting
# (This value represents the time in milliseconds: 1 second = 1000 milliseconds)
read-timeout: 8000
@@ -186,6 +186,9 @@ verification:
# Cette fonctionnalité est expérimentale et peut causer des problèmes
# Si cela est désactivé, les joueurs Bedrock seront ignorés
check-geyser-players: false
# Sonar devrait-il également vérifier les joueurs EaglercraftX ?
# Cette fonctionnalité est expérimentale et peut causer des problèmes.
check-eagler-players: false
# Temps écoulé depuis que le joueur a cessé d'envoyer des paquets avant de se déconnecter
# (Cette valeur représente le temps en millisecondes : 1 seconde = 1000 millisecondes)
read-timeout: 8000
@@ -185,6 +185,9 @@ verification:
# ეს ფუნქცია ექსპერიმენტულია და შეიძლება გამოიწვიოს პრობლემები
# თუ ეს გამორთულია, Bedrock მოთამაშეები გამოვლენილი იქნება
check-geyser-players: false
# უნდა შეამოწმოს Sonar-მა EaglercraftX-ის მოთამაშეებიც?
# ეს ფუნქცია ექსპერიმენტულია და შესაძლოა პრობლემები გამოიწვიოს
check-eagler-players: false
# დროის ოდენობა, რომელიც უნდა გავიდეს, სერვერთან კავშირის გარეშე, სანამ მოთამაშე დროებით გავარდება სერვერიდან.
# (ეს არის ნაჩვენები მილიწამებში: 1 წამი = 1000 მილიწამი)
read-timeout: 8000
@@ -182,6 +182,9 @@ verification:
# Moet Sonar elke beweging/positieverandering tijdens de verificatie registreren?
# Dit wordt niet aanbevolen voor productieservers, maar kan nuttig zijn bij het opsporen van fouten.
debug-xyz-positions: false
# Moet Sonar ook EaglercraftX-spelers controleren?
# Deze functie is experimenteel en kan problemen veroorzaken.
check-eagler-players: false
# Moet Sonar ook Geyser (Bedrock) spelers controleren?
# Deze functie is experimenteel en kan problemen veroorzaken
# Als dit is uitgeschakeld, worden Bedrock-spelers overgeslagen
@@ -186,6 +186,9 @@ verification:
# Ta funkcja jest eksperymentalna i może powodować problemy
# Jeśli ta opcja jest wyłączona, gracze Bedrock będą pomijani
check-geyser-players: false
# Czy Sonar powinien również sprawdzać graczy EaglercraftX?
# Ta funkcja jest eksperymentalna i może powodować problemy.
check-eagler-players: false
# Czas, jaki ma upłynąć od zatrzymania wysyłania pakietów przez gracza do wyrzucenia.
# (Wartość ta reprezentuje czas w milisekundach: 1 sekunda = 1000 milisekund)
read-timeout: 8000
@@ -186,6 +186,9 @@ verification:
# Este recurso é experimental e pode causar problemas
# Se isso estiver desativado, jogadores Bedrock serão ignorados
check-geyser-players: false
# O Sonar também deve verificar os jogadores do EaglercraftX?
# Este recurso é experimental e pode causar problemas.
check-eagler-players: false
# O tempo desde que o jogador parou de enviar pacotes antes de desconectar
# (Este valor representa o tempo em milissegundos: 1 segundo = 1000 milissegundos)
read-timeout: 8000
@@ -185,6 +185,9 @@ verification:
# Эта функция экспериментальна и может вызывать проблемы
# Если это отключено, игроки Bedrock будут пропущены
check-geyser-players: false
# Должен ли Sonar также проверять игроков EaglercraftX?
# Эта функция является экспериментальной и может вызывать проблемы.
check-eagler-players: false
# Время, прошедшее с момента прекращения отправки пакетов игроком до отключения.
# (Это значение представляет время в миллисекундах: 1 секунда = 1000 миллисекунд)
read-timeout: 8000
@@ -108,9 +108,9 @@ verification:
# 如果未找到指定的图片, 则自动通过噪音生成一个随机的背景图片.
# 如果图片在该插件的配置文件夹下, 则可以简单地输入图片的文件名.
background: ''
# 地图验证码的风格(默认:'modern').
# 地图验证码的风格(默认: 'modern').
# 要使用旧设计, 请将其设置为 'legacy'.
# To use an experimental design, set this to 'complex'.
# 要使用实验设计, 请将此项设置为 'complex'.
style: 'modern'
# Sonar 应该一次准备多少个验证码?
precompute: 500
@@ -182,6 +182,9 @@ verification:
# 此功能是实验性的. 请报告任何因为误判而导致无法通过检查的问题
# 如果关闭该选项 Sonar 将不检查这些玩家以便直接连接到服务器.
check-geyser-players: false
# 声纳是否也应检测 EaglercraftX 玩家?
# 此功能尚在试验阶段, 可能引发问题
check-eagler-players: false
# 播放器断开连接前停止发送数据包的时间
# (该值为毫秒. 1秒等于1000毫秒.)
read-timeout: 8000
+1 -1
View File
@@ -1,3 +1,3 @@
group=xyz.jonesdev
version=2.1.43
version=2.1.45
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
+6 -3
View File
@@ -9,9 +9,10 @@ pluginyml = "0.6.0"
[plugins]
indra-git = "net.kyori.indra.git:3.2.0"
shadow = "com.gradleup.shadow:8.3.8"
spotless = "com.diffplug.spotless:7.2.1"
spotless = "com.diffplug.spotless:8.2.1"
pluginyml-bungee = { id = "net.minecrell.plugin-yml.bungee", version.ref = "pluginyml" }
pluginyml-bukkit = { id = "net.minecrell.plugin-yml.bukkit", version.ref = "pluginyml" }
pluginyml-paper = { id = "net.minecrell.plugin-yml.paper", version.ref = "pluginyml" }
[libraries]
netty = { module = "io.netty:netty-all", version.ref = "netty" }
@@ -23,17 +24,19 @@ adventure-platform-bungee = { module = "net.kyori:adventure-platform-bungeecord"
libby-core = { module = "com.alessiodp.libby:libby-core", version.ref = "libby" }
libby-bungee = { module = "com.alessiodp.libby:libby-bungee", version.ref = "libby" }
libby-bukkit = { module = "com.alessiodp.libby:libby-bukkit", version.ref = "libby" }
libby-paper = { module = "com.alessiodp.libby:libby-paper", version.ref = "libby" }
libby-velocity = { module = "com.alessiodp.libby:libby-velocity", version.ref = "libby" }
bstats-bungee = { module = "org.bstats:bstats-bungeecord", version.ref = "bstats" }
bstats-bukkit = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" }
bstats-velocity = { module = "org.bstats:bstats-velocity", version.ref = "bstats" }
imagefilters = "com.jhlabs:filters:2.0.235-1"
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.2"
caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3"
annotations = "org.jetbrains:annotations:26.0.2"
simpleyaml = "com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4"
ormlite = "com.j256.ormlite:ormlite-jdbc:6.1"
lombok = "org.projectlombok:lombok:1.18.42"
bungeecord = "net.md-5:bungeecord-proxy:1.21-SNAPSHOT"
velocity = "io.papermc.velocity:velocity-proxy:3.4.0-SNAPSHOT"
velocity = "io.papermc.velocity:velocity-proxy:3.5.0-SNAPSHOT"
paper = "io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT"
# We have to use 1.16.5 for backwards compatibility
spigot = "org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT"
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -4
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
Vendored Regular → Executable
+93 -94
View File
@@ -1,94 +1,93 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+52
View File
@@ -0,0 +1,52 @@
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
plugins {
alias(libs.plugins.pluginyml.paper) apply true
}
paper {
name = rootProject.name
main = "xyz.jonesdev.sonar.paper.SonarPaperPlugin"
authors = listOf("Jones Development", "Sonar Contributors")
website = "https://jonesdev.xyz/discord/"
load = BukkitPluginDescription.PluginLoadOrder.POSTWORLD
apiVersion = "1.21" // ignore legacy plugin warning
foliaSupported = true
serverDependencies {
listOf("Geyser-Spigot", "floodgate", "Protocolize", "ProtocolSupport",
"ViaVersion", "packetevents", "ProtocolLib", "FastLogin").forEach {
register(it) {
required = false
}
}
}
}
java {
// Modern Paper requires Java 21
java.sourceCompatibility = JavaVersion.VERSION_21
java.targetCompatibility = JavaVersion.VERSION_21
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
}
repositories {
maven(url = "https://repo.papermc.io/repository/maven-public/") // Paper
}
dependencies {
implementation(project(":api"))
implementation(project(":common"))
implementation(project(":bukkit"))
compileOnly(rootProject.libs.paper)
implementation(rootProject.libs.bstats.bukkit)
implementation(rootProject.libs.libby.paper)
}
tasks {
shadowJar {
relocate("net.kyori.adventure.nbt", "xyz.jonesdev.sonar.libs.kyori.adventure.nbt")
}
}
@@ -0,0 +1,117 @@
/*
* Copyright (C) 2026 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.paper;
import com.alessiodp.libby.PaperLibraryManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import lombok.Getter;
import net.kyori.adventure.audience.Audience;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.jonesdev.sonar.paper.command.PaperSonarCommand;
import xyz.jonesdev.sonar.api.SonarPlatform;
import xyz.jonesdev.sonar.api.logger.LoggerWrapper;
import xyz.jonesdev.sonar.bukkit.SonarBukkit;
import xyz.jonesdev.sonar.bukkit.antibot.BukkitInjector;
import xyz.jonesdev.sonar.bukkit.listener.BukkitJoinListener;
import xyz.jonesdev.sonar.common.boot.SonarBootstrap;
import java.util.UUID;
@Getter
public final class SonarPaper extends SonarBootstrap<SonarPaperPlugin> {
private final LoggerWrapper logger = new LoggerWrapper() {
@Override
public void info(final String message, final Object... args) {
getPlugin().getLogger().info(buildFullMessage(message, args));
}
@Override
public void warn(final String message, final Object... args) {
getPlugin().getLogger().warning(buildFullMessage(message, args));
}
@Override
public void error(final String message, final Object... args) {
getPlugin().getLogger().severe(buildFullMessage(message, args));
}
};
private Metrics metrics;
public SonarPaper(final @NotNull SonarPaperPlugin plugin) {
super(plugin, SonarPlatform.PAPER, plugin.getDataFolder(), new PaperLibraryManager(plugin));
}
@Override
public @Nullable Audience audience(@Nullable final UUID uniqueId) {
if (uniqueId == null) return null;
return Bukkit.getPlayer(uniqueId);
}
@Override
public @NotNull Audience sender(@NotNull final Object object) {
return (Audience) object;
}
@Override
public @NotNull LoggerWrapper getLogger() {
return logger;
}
@Override
public void enable() {
// Initialize bStats.org metrics
metrics = new Metrics(getPlugin(), getPlatform().getMetricsId());
// Add charts for some configuration options
metrics.addCustomChart(new SimplePie("verification",
() -> getConfig().getVerification().getTiming().getDisplayName()));
metrics.addCustomChart(new SimplePie("captcha",
() -> getConfig().getVerification().getMap().getTiming().getDisplayName()));
metrics.addCustomChart(new SimplePie("language",
() -> getConfig().getLanguage().getName()));
metrics.addCustomChart(new SimplePie("database_type",
() -> getConfig().getDatabase().getType().getDisplayName()));
// Register Sonar command
getPlugin().getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event ->
event.registrar().register("sonar", new PaperSonarCommand()));
// Try to inject into the server
if (BukkitInjector.isLateBindEnabled()) {
getPlugin().getServer().getScheduler().runTask(getPlugin(), BukkitInjector::inject);
} else {
getPlugin().getServer().getPluginManager().registerEvents(new BukkitJoinListener(), getPlugin());
}
// Let the injector know that the plugin has been enabled
SonarBukkit.INITIALIZE_LISTENER.complete(null);
}
@Override
public void disable() {
// Make sure to properly stop the metrics
if (metrics != null) {
metrics.shutdown();
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2026 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.paper;
import org.bukkit.plugin.java.JavaPlugin;
import xyz.jonesdev.sonar.bukkit.antibot.BukkitInjector;
public final class SonarPaperPlugin extends JavaPlugin {
private SonarPaper bootstrap;
@Override
public void onLoad() {
// Inject early if late-bind is disabled
if (!BukkitInjector.isLateBindEnabled()) {
BukkitInjector.inject();
}
}
@Override
public void onEnable() {
bootstrap = new SonarPaper(this);
bootstrap.initialize();
}
@Override
public void onDisable() {
bootstrap.shutdown();
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2026 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.paper.command;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jspecify.annotations.NonNull;
import xyz.jonesdev.sonar.api.command.InvocationSource;
import xyz.jonesdev.sonar.api.command.SonarCommand;
import java.util.Collection;
import java.util.Collections;
public final class PaperSonarCommand implements BasicCommand, SonarCommand {
@Override
public void execute(final CommandSourceStack commandSourceStack, final String @NonNull [] args) {
final CommandSender sender = commandSourceStack.getSender();
final InvocationSource invocationSource = new InvocationSource(
sender instanceof Player ? ((Player) sender).getUniqueId() : null,
sender,
sender::hasPermission
);
handle(invocationSource, args);
}
@Override
public @NonNull Collection<String> suggest(final CommandSourceStack commandSourceStack, final String @NonNull [] args) {
// Do not allow tab completion if the player does not have the required permission
return commandSourceStack.getSender().hasPermission("sonar.command") ?
getCachedTabSuggestions(args) : Collections.emptyList();
}
}
+1
View File
@@ -6,6 +6,7 @@ sequenceOf(
"common",
"bukkit",
"bungeecord",
"paper",
"velocity"
).forEach {
include(":$it")
-1
View File
@@ -3,7 +3,6 @@ dependencies {
implementation(project(":common"))
compileOnly(rootProject.libs.velocity)
testCompileOnly(rootProject.libs.velocity)
implementation(rootProject.libs.bstats.velocity)
implementation(rootProject.libs.libby.velocity)