Compare commits

..
10 Commits
Author SHA1 Message Date
dependabot[bot] 32f3cc51b1 Bump gradle-wrapper from 9.8.1 to 9.8.2 (#650)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.8.1 to 9.8.2.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.8.1...v9.8.2)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.8.2
  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-10-27 14:57:56 +01:00
Akkariin 76dc4f0232 fix(protocol): correct PlayerInputPacket ID on 26.1+ to fix F3+3 disconnect (#648) (#649)
In Minecraft 26.1, 26.2, and 26.3, ServerboundPlayerInputPacket is registered
at packet ID 0x2B, while 0x26 is ServerboundPingRequestPacket.

Previously, PlayerInputPacket was incorrectly mapped to 0x26 for MINECRAFT_26_1.
When a client joined with the F3+3 network chart open or toggled F3+3 during
verification, the client sent ServerboundPingRequestPacket (0x26, 8 bytes).
Sonar attempted to decode it as PlayerInputPacket (which only reads 1 byte in
1.21.2+), leaving 7 unread bytes. SonarPacketDecoder threw QuietDecoderException,
causing TailExceptionsHandler to silently close the channel, resulting in a client
disconnection with 'Disconnected' without any server-side stack trace.

This commit updates PlayerInputPacket's ID on 26.1+ to 0x2B, allowing PingRequest
(0x26) to be safely ignored by SonarPacketDecoder.
2026-10-25 17:57:46 +01:00
Jones 3497cb116c chore(release): bump version to 2.1.53 (#646) 2026-10-17 18:31:48 +02:00
Jones 4d491531bb feat(captcha): increase generation randomness 2026-10-17 18:27:38 +02:00
FeGmbHandJones 7b2d2db614 Remove adventure-platform to prevent Adventure 4.x/5.x class conflict (#642)
* Remove adventure platform dependencies

Removed adventure-platform-bukkit and adventure-platform-bungee dependencies.

* fix(bungee): remove adventure-platform to prevent Adventure 4.x/5.x class conflict

* fix(bukkit): restore missing adventure-platform-bukkit catalog entry

* Remove adventure-platform-bukkit dependency

Removed adventure-platform-bukkit dependency from libs.versions.toml

* Readd adventure-platform-bukkit dependency

* Update copyright year and refactor action bar method

Updated copyright year from 2025 to 2026 and refactored action bar message sending as commented by @jonesdevelopment

* Refactor title code as commented

* I forgot a closing bracket :(

* Change LibraryLoader to public class with state management

Refactor LibraryLoader to a public class and add loaded state management.

* Update copyright year and load libraries earlier

* Add imports for BungeeLibraryManager and SonarPlatform

* Avoid double library loading without tracking state

* Invert BungeeAudience#showTitle player check

* Now makes use of Java 17+ features

* Avoid storing extra 1.16 protocol version ID

---------

Co-authored-by: Jones <admin@jonesdev.xyz>
2026-10-13 13:45:41 +02:00
dependabot[bot] 4547b1632d Bump com.diffplug.spotless from 8.10.3 to 8.10.4 (#643)
Bumps [com.diffplug.spotless](https://github.com/diffplug/spotless) from 8.10.3 to 8.10.4.
- [Release notes](https://github.com/diffplug/spotless/releases)
- [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md)
- [Commits](https://github.com/diffplug/spotless/compare/gradle/8.10.3...gradle/8.10.4)

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.4
  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-10-12 14:18:31 +02:00
dependabot[bot] 943872ed62 Bump io.netty:netty-all from 4.2.18.Final to 4.2.19.Final (#645)
Bumps [io.netty:netty-all](https://github.com/netty/netty) from 4.2.18.Final to 4.2.19.Final.
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](https://github.com/netty/netty/compare/netty-4.2.18.Final...netty-4.2.19.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-all
  dependency-version: 4.2.19.Final
  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-10-12 14:18:14 +02:00
dependabot[bot] f1239a7412 Bump gradle-wrapper from 9.8.0 to 9.8.1 (#644)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.8.0 to 9.8.1.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.8.0...v9.8.1)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.8.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-10-12 14:18:12 +02:00
dependabot[bot] 1794a2f24e Bump com.diffplug.spotless from 8.10.2 to 8.10.3 (#640)
Bumps [com.diffplug.spotless](https://github.com/diffplug/spotless) from 8.10.2 to 8.10.3.
- [Release notes](https://github.com/diffplug/spotless/releases)
- [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md)
- [Commits](https://github.com/diffplug/spotless/compare/gradle/8.10.2...gradle/8.10.3)

---
updated-dependencies:
- dependency-name: com.diffplug.spotless
  dependency-version: 8.10.3
  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-10-05 16:13:47 +02:00
dependabot[bot] 18f40fea3e Bump gradle-wrapper from 9.7.1 to 9.8.0 (#638)
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.7.1 to 9.8.0.
- [Release notes](https://github.com/gradle/gradle/releases)
- [Commits](https://github.com/gradle/gradle/compare/v9.7.1...v9.8.0)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-28 21:57:19 +02:00
14 changed files with 193 additions and 62 deletions

No files matched your search

-3
View File
@@ -15,9 +15,6 @@ dependencies {
compileOnly(rootProject.libs.bungeecord)
implementation(rootProject.libs.adventure.platform.bungee) {
exclude(module = "adventure-nbt")
}
implementation(rootProject.libs.bstats.bungee)
implementation(rootProject.libs.libby.bungee)
}
@@ -0,0 +1,92 @@
/*
* 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.bungee;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.title.Title;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.chat.ComponentSerializer;
import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.antibot.protocol.ProtocolVersion;
import java.time.Duration;
/**
* Minimal {@link Audience} implementation backed by the native BungeeCord chat API.
* <br>
* BungeeCord does not ship Adventure, so we used to bundle adventure-platform-bungeecord (Adventure 4.x).
* That conflicted with the Adventure 5.x libraries Sonar loads at runtime, because both end up
* in the same relocated package. Converting components to JSON and passing them to BungeeCord's own
* {@link ComponentSerializer} allows us to depend on exactly one Adventure version.
*/
final class BungeeAudience implements Audience {
private final CommandSender sender;
BungeeAudience(final @NotNull CommandSender sender) {
this.sender = sender;
}
@Override
public void sendMessage(final @NotNull Component message) {
sender.sendMessage(toBungee(message));
}
@Override
public void sendActionBar(final @NotNull Component message) {
// Only players have an action bar
if (sender instanceof ProxiedPlayer player) {
player.sendMessage(ChatMessageType.ACTION_BAR, toBungee(message));
}
}
@Override
public void showTitle(final @NotNull Title title) {
// Only players can see titles
if (sender instanceof ProxiedPlayer player) {
final Title.Times times = title.times();
ProxyServer.getInstance().createTitle()
.title(toBungee(title.title()))
.subTitle(toBungee(title.subtitle()))
// Use the same defaults as Title#DEFAULT_TIMES (0.5s, 3.5s, 1s)
.fadeIn(times == null ? 10 : toTicks(times.fadeIn()))
.stay(times == null ? 70 : toTicks(times.stay()))
.fadeOut(times == null ? 20 : toTicks(times.fadeOut()))
.send(player);
}
}
private static int toTicks(final @NotNull Duration duration) {
return (int) (duration.toMillis() / 50L);
}
private @NotNull BaseComponent[] toBungee(final @NotNull Component component) {
// Downsample hex colors for clients that do not support them
final boolean legacyClient = sender instanceof ProxiedPlayer player
&& player.getPendingConnection().getVersion() < ProtocolVersion.MINECRAFT_1_16.getProtocol();
final GsonComponentSerializer serializer = legacyClient
? GsonComponentSerializer.colorDownsamplingGson()
: GsonComponentSerializer.gson();
return ComponentSerializer.parse(serializer.serialize(component));
}
}
@@ -20,8 +20,8 @@ package xyz.jonesdev.sonar.bungee;
import com.alessiodp.libby.BungeeLibraryManager;
import lombok.Getter;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import org.jetbrains.annotations.NotNull;
@@ -36,26 +36,22 @@ import java.util.UUID;
@Getter
public final class SonarBungee extends SonarBootstrap<SonarBungeePlugin> {
public SonarBungee(final @NotNull SonarBungeePlugin plugin) {
super(plugin, SonarPlatform.BUNGEE, plugin.getDataFolder(), new BungeeLibraryManager(plugin));
public SonarBungee(final @NotNull SonarBungeePlugin plugin, final @NotNull BungeeLibraryManager libraryManager) {
super(plugin, SonarPlatform.BUNGEE, plugin.getDataFolder(), libraryManager);
}
/**
* Wrapper for BungeeCord audiences
*/
private final BungeeAudiences bungeeAudiences = BungeeAudiences.create(getPlugin());
@Override
public @Nullable Audience audience(final @Nullable UUID uniqueId) {
if (uniqueId == null) {
return null;
}
return bungeeAudiences.player(uniqueId);
final ProxiedPlayer player = getPlugin().getServer().getPlayer(uniqueId);
return player == null ? null : new BungeeAudience(player);
}
@Override
public @NotNull Audience sender(final @NotNull Object object) {
return bungeeAudiences.sender((CommandSender) object);
return new BungeeAudience((CommandSender) object);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2025 Sonar Contributors
* 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
@@ -17,9 +17,12 @@
package xyz.jonesdev.sonar.bungee;
import com.alessiodp.libby.BungeeLibraryManager;
import lombok.Getter;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import xyz.jonesdev.sonar.api.SonarPlatform;
import xyz.jonesdev.sonar.common.boot.LibraryLoader;
@Getter
public final class SonarBungeePlugin extends Plugin {
@@ -30,7 +33,13 @@ public final class SonarBungeePlugin extends Plugin {
public void onEnable() {
server = ProxyServer.getInstance();
bootstrap = new SonarBungee(this);
// HACK:
// Adventure is not bundled in the jar, so the libraries have to be on the classpath
// before SonarBungee is loaded. The JVM resolves its Adventure types during class verification.
final BungeeLibraryManager libraryManager = new BungeeLibraryManager(this);
LibraryLoader.loadLibraries(libraryManager, SonarPlatform.BUNGEE);
bootstrap = new SonarBungee(this, libraryManager);
bootstrap.initialize();
}
@@ -54,13 +54,13 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
static {
FONT = TTFFontProvider.loadFont("/assets/fonts/Kingthings_Trypewriter_2.ttf");
FBM.setAmount(0.6f);
FBM.setScale(15);
FBM.setAmount(0.55f + RANDOM.nextFloat(0.15f));
FBM.setScale(10 + RANDOM.nextFloat(10));
SMEAR.setShape(SmearFilter.SQUARES);
SMEAR.setDensity(0.1f);
SMEAR.setDistance(0);
SMEAR.setMix(0.35f);
SMEAR.setMix(0.25f + RANDOM.nextFloat(0.25f));
// Create fractions based on the number of colors
for (int i = 0; i < COLOR_FRACTIONS.length; i++) {
@@ -111,7 +111,7 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
private void applyRandomColorGradient(final @NotNull Graphics2D graphics) {
// Randomize the colors for the gradient effect
for (int i = 0; i < COLORS.length; i++) {
final float random = 0.9f + RANDOM.nextFloat() * 0.1f;
final float random = 0.8f + RANDOM.nextFloat() * 0.2f;
COLORS[i] = Color.getHSBColor(RANDOM.nextFloat(), random * 0.8f, random);
}
@@ -161,8 +161,8 @@ public final class StandardCaptchaGenerator implements CaptchaGenerator {
}
private void createGlyphOutline(final @NotNull Graphics2D graphics, final @NotNull Shape shape) {
final float txy = 1.25f + RANDOM.nextFloat();
final float width = 1 + RANDOM.nextFloat();
final float txy = RANDOM.nextFloat(0.1f, 2f);
final float width = RANDOM.nextFloat(0.5f, 2f);
// Create a randomly translated and stroked shape based on the original glyph shape
final AffineTransform translation = AffineTransform.getTranslateInstance(txy, txy);
+2 -2
View File
@@ -17,7 +17,7 @@
import lombok.experimental.UtilityClass;
import xyz.jonesdev.sonar.api.antibot.captcha.CaptchaGenerator;
import xyz.jonesdev.sonar.captcha.complex.ComplexCaptchaGenerator;
import xyz.jonesdev.sonar.captcha.StandardCaptchaGenerator;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
@@ -29,7 +29,7 @@ import java.util.Random;
public class Main {
public void main(final String... args) throws IOException {
final Random random = new Random();
final CaptchaGenerator standardCaptchaGenerator = new ComplexCaptchaGenerator(null);
final CaptchaGenerator standardCaptchaGenerator = new StandardCaptchaGenerator(null);
final long start = System.currentTimeMillis();
final char[] dictionary = {'a', 'b', 'c', 'd', 'e', 'f'/*, 'g'*/, 'h'/*, 'i'*/, 'j',
@@ -24,8 +24,8 @@ import org.jetbrains.annotations.NotNull;
import xyz.jonesdev.sonar.api.SonarPlatform;
@UtilityClass
class LibraryLoader {
void loadLibraries(final @NotNull LibraryManager libraryManager, final @NotNull SonarPlatform platform) {
public class LibraryLoader {
public void loadLibraries(final @NotNull LibraryManager libraryManager, final @NotNull SonarPlatform platform) {
libraryManager.addMavenCentral();
libraryManager.addJitPack();
libraryManager.loadLibraries(
@@ -69,25 +69,14 @@ class LibraryLoader {
// Only load adventure if not on Velocity
if (platform != SonarPlatform.VELOCITY) {
if (platform != SonarPlatform.PAPER) {
// BungeeCord does not ship Adventure, and we do not bundle adventure-platform there anymore
// (mixing Adventure 4.x and 5.x in the same relocated package causes NoSuchMethodErrors).
// Therefore, adventure-api and everything else Adventure needs has to be resolved at runtime.
final boolean resolveTransitive = platform == SonarPlatform.BUNGEE;
libraryManager.loadLibraries(
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-minimessage")
.version("5.2.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-text-serializer-gson")
.version("5.2.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build(),
Library.builder()
.groupId("net{}kyori")
.artifactId("adventure-nbt")
.version("5.2.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori")
.build()
adventureLibrary("adventure-text-minimessage", resolveTransitive),
adventureLibrary("adventure-text-serializer-gson", resolveTransitive),
adventureLibrary("adventure-nbt", resolveTransitive)
);
} else {
// On Paper, we only relocate the nbt package since the rest of adventure is bundled with the server.
@@ -102,4 +91,18 @@ class LibraryLoader {
}
}
}
private @NotNull Library adventureLibrary(final @NotNull String artifactId, final boolean resolveTransitive) {
final Library.Builder builder = Library.builder()
.groupId("net{}kyori")
.artifactId(artifactId)
.version("5.2.0")
.relocate("net{}kyori", "xyz{}jonesdev{}sonar{}libs{}kyori");
if (resolveTransitive) {
builder.resolveTransitiveDependencies(true)
// Gson is already provided by the proxy, so we must not load another copy
.excludeTransitiveDependency("com.google.code.gson", "gson");
}
return builder.build();
}
}
@@ -68,7 +68,13 @@ public abstract class SonarBootstrap<T> implements Sonar {
final @NotNull File dataDirectory,
final @NotNull LibraryManager libraryManager) {
// Load all libraries before anything else
LibraryLoader.loadLibraries(libraryManager, platform);
// HACK:
// We manually load the libraries on BungeeCord beforehand,
// so we skip this call to avoid loading libraries twice.
// See SonarBungeePlugin.java#L40
if (platform != SonarPlatform.BUNGEE) {
LibraryLoader.loadLibraries(libraryManager, platform);
}
this.libraryManager = libraryManager;
// Check if Netty is up to date
ProtocolUtil.checkNettyVersion();
@@ -544,8 +544,7 @@ public enum SonarPacketRegistry {
map(0x28, MINECRAFT_1_21_2, false),
map(0x29, MINECRAFT_1_21_4, false),
map(0x2A, MINECRAFT_1_21_6, false),
map(0x26, MINECRAFT_26_1, false),
map(0x2B, MINECRAFT_26_3, false));
map(0x2B, MINECRAFT_26_1, false));
// minecraft:move_vehicle
serverbound.register(VehicleMovePacket.class, VehicleMovePacket::new,
map(0x10, MINECRAFT_1_9, false),
+1 -1
View File
@@ -1,3 +1,3 @@
group=xyz.jonesdev
version=2.1.52
version=2.1.53
description=A lightweight, effective, and easy-to-use anti-bot plugin for Velocity, BungeeCord, and Bukkit.
+2 -3
View File
@@ -1,5 +1,5 @@
[versions]
netty = "4.2.18.Final"
netty = "4.2.19.Final"
adventure = "5.2.0"
adventure-platform = "4.4.1"
bstats = "3.2.1"
@@ -9,7 +9,7 @@ pluginyml = "0.6.0"
[plugins]
indra-git = "net.kyori.indra.git:3.2.0"
shadow = "com.gradleup.shadow:9.6.1"
spotless = "com.diffplug.spotless:8.10.2"
spotless = "com.diffplug.spotless:8.10.4"
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" }
@@ -20,7 +20,6 @@ adventure-minimessage = { module = "net.kyori:adventure-text-minimessage", versi
adventure-serializer = { module = "net.kyori:adventure-text-serializer-gson", version.ref = "adventure" }
adventure-nbt = { module = "net.kyori:adventure-nbt", version.ref = "adventure" }
adventure-platform-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform" }
adventure-platform-bungee = { module = "net.kyori:adventure-platform-bungeecord", version.ref = "adventure-platform" }
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" }
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-9.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.2-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
Vendored
+41 -11
View File
@@ -26,6 +26,33 @@
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
@rem Catch executions from older scripts and ensure they exit cleanly.
@rem This can be removed once we can be reasonably confident that few people
@rem will be migrating directly to this new wrapper.
goto afterSafetyNet
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
goto exitWithErrorLevel
:afterSafetyNet
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
@@ -45,13 +72,14 @@ 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
1>&2 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.
"%COMSPEC%" /c exit 1
goto exitWithErrorLevel
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -59,13 +87,14 @@ 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
1>&2 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.
"%COMSPEC%" /c exit 1
goto exitWithErrorLevel
:execute
@rem Setup the command line
@@ -75,8 +104,9 @@ echo location of your Java installation. 1>&2
@rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel
@rem This label must not be changed. We rely on old scripts being able to jump to this point.
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%