From cecbd68c2fdab4b2d57dcca35dcdaf878a5bbde0 Mon Sep 17 00:00:00 2001 From: Lynx Date: Tue, 6 Jan 2026 14:02:41 -0800 Subject: [PATCH 1/6] add update checker --- .../admintoolbox/AdminToolboxPlugin.java | 44 ++++++ .../admintoolbox/ModrinthUpdateChecker.java | 144 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java diff --git a/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java b/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java index 4ea88e0..6f5ecb4 100644 --- a/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java +++ b/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java @@ -1,5 +1,8 @@ package org.modernbeta.admintoolbox; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.luckperms.api.LuckPerms; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; @@ -47,6 +50,7 @@ public class AdminToolboxPlugin extends JavaPlugin { public static final String BROADCAST_EXEMPT_PERMISSION = "admintoolbox.broadcast.exempt"; private static final int BSTATS_PLUGIN_ID = 26406; + private static final String MODRINTH_PROJECT_ID = "TYi0LZWN"; @Override public void onEnable() { @@ -75,6 +79,42 @@ public void onEnable() { initializeConfig(); + if (getConfig().getBoolean("check-updates", false)) { + Optional newerVersion = ModrinthUpdateChecker.getNewerVersion( + getPluginMeta().getVersion(), MODRINTH_PROJECT_ID, + Bukkit.getName().toLowerCase(), Bukkit.getMinecraftVersion()); + + Component updateMessage = newerVersion + .map(version -> { + ModrinthUpdateChecker.ModrinthFile primaryFile; + for (ModrinthUpdateChecker.ModrinthFile file : version.files()) { + if (file.primary()) { + primaryFile = file; + break; + } + } + + return Component.text() + .color(NamedTextColor.GOLD) + .appendNewline() + .append(Component.text("Version " + + version.versionNumber() + + " of " + + getPluginMeta().getName() + + " is now available!" + ).decorate(TextDecoration.BOLD)) + .appendNewline() + .append(Component.text("You are running version " + + getPluginMeta().getVersion() + ".")) + .appendNewline() + .append(Component.text("Download it here: " + version.files())) + .build(); + }) + .orElseGet(() -> Component.text("No updates are available for " + getPluginMeta().getName() + ".")); + + getComponentLogger().info(updateMessage); + } + try { RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); if (provider != null) { @@ -185,6 +225,10 @@ public void reloadConfig() { public Configuration getConfigDefaults() { Configuration defaults = new YamlConfiguration(); + defaults.set("check-updates", true); + defaults.setComments("check-updates", List.of("Enable update check. When enabled, AdminToolbox will notify via the server console that a new version is available.")); + + // streamer-mode section { ConfigurationSection streamerMode = defaults.createSection("streamer-mode"); streamerMode.set("allow", true); diff --git a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java new file mode 100644 index 0000000..24bf94d --- /dev/null +++ b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java @@ -0,0 +1,144 @@ +package org.modernbeta.admintoolbox; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.format.DateTimeParseException; +import java.util.*; +import java.util.stream.Collectors; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class ModrinthUpdateChecker { + private static final int SEMVER_LENGTH = 3; + + private static final Gson GSON = new Gson(); + + public static Optional getNewerVersion(String currentVersion, String projectId, String loader, String gameVersion) { + int[] currentVersionParsed; + try { + currentVersionParsed = parseSemverParts(currentVersion); + } catch (NumberFormatException e) { + return Optional.empty(); + } + + List compatibleVersions = getCompatibleVersions(projectId, loader, gameVersion); + + for (ModrinthVersion version : compatibleVersions) { + int[] versionParsed = parseSemverParts(version.versionNumber); + if (isGreaterVersion(versionParsed, currentVersionParsed)) { + return Optional.of(version); + } + } + + return Optional.empty(); // no newer version found + } + + private static @Nonnull List getCompatibleVersions(String projectId, String loader, String gameVersion) { + try (HttpClient client = HttpClient.newHttpClient()) { + // modrinth api has stupid non-standard query param expectations, + // so we must wrap them in javascript arrays + String queryString = Map.of( + "loaders", "[\"" + loader + "\"]", + "game_versions", "[\"" + gameVersion + "\"]" + ) + .entrySet().stream() + .map(entry -> + URLEncoder.encode(entry.getKey(), UTF_8) + "=" + + URLEncoder.encode(entry.getValue(), UTF_8)) + .collect(Collectors.joining("&")); + + URI requestUri = new URI( + "https", + "api.modrinth.com", + "/v2/project/" + URLEncoder.encode(projectId, StandardCharsets.UTF_8) + "/version", + queryString, + null + ); + HttpRequest req = HttpRequest.newBuilder() + .uri(requestUri) + .GET() + .build(); + + HttpResponse res = client.send(req, HttpResponse.BodyHandlers.ofString()); + String rawBody = res.body(); + + List versions = new ArrayList<>(); + JsonArray rawVersionList = GSON.fromJson(rawBody, JsonArray.class); + for (JsonElement element : rawVersionList) { + if (!element.isJsonObject()) continue; + + JsonObject object = element.getAsJsonObject(); + String versionNumber = object.get("version_number").getAsString(); + String versionType = object.get("version_type").getAsString(); + String status = object.get("status").getAsString(); + Instant datePublished = Instant.parse(object.get("date_published").getAsString()); + + List files = new ArrayList<>(); + for (JsonElement rawFile : object.get("files").getAsJsonArray()) { + if (!rawFile.isJsonObject()) continue; + + JsonObject fileObject = rawFile.getAsJsonObject(); + String url = fileObject.get("url").getAsString(); + boolean primary = fileObject.get("primary").getAsBoolean(); + + files.add(new ModrinthFile(url, primary)); + } + + versions.add(new ModrinthVersion(versionNumber, versionType, status, datePublished, files)); + } + + return versions; + } catch (IOException | InterruptedException e) { + return List.of(); // request failed; fail check silently + } catch (DateTimeParseException e) { + // TODO: log date parse failure + return List.of(); + } catch (URISyntaxException e) { + // TODO: log uri build failure + return List.of(); + } + } + + public record ModrinthVersion(String versionNumber, String versionType, String status, + Instant datePublished, List files) { + } + + public record ModrinthFile(String url, boolean primary) { + } + + private static boolean isGreaterVersion(int[] a, int[] b) throws IllegalArgumentException { + if (a.length != SEMVER_LENGTH || b.length != SEMVER_LENGTH) + throw new IllegalArgumentException("Compared semver version has incorrect size!"); + + for (int i = 0; i < SEMVER_LENGTH; i++) { + if (a[i] > b[i]) return true; + if (a[i] < b[i]) return false; + } + return false; // versions are equal + } + + private static int[] parseSemverParts(String version) throws NumberFormatException { + final String[] parts = version.split("\\."); + if (parts.length != SEMVER_LENGTH) + throw new NumberFormatException("Version is not valid untagged semver! (expected: x.x.x)"); + + return new int[]{ + Integer.parseInt(parts[0]), + Integer.parseInt(parts[1]), + Integer.parseInt(parts[2]), + }; + } +} From 0a6dabcc5bf1a0453390b016fe6e8e1c0d73ca48 Mon Sep 17 00:00:00 2001 From: Lynx Date: Tue, 6 Jan 2026 17:05:04 -0800 Subject: [PATCH 2/6] flatten update checker logic & add better logging --- .../admintoolbox/AdminToolboxPlugin.java | 46 +------ .../admintoolbox/ModrinthUpdateChecker.java | 130 ++++++++++++------ 2 files changed, 92 insertions(+), 84 deletions(-) diff --git a/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java b/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java index 6f5ecb4..effcc93 100644 --- a/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java +++ b/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java @@ -1,8 +1,5 @@ package org.modernbeta.admintoolbox; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; import net.luckperms.api.LuckPerms; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; @@ -31,6 +28,8 @@ public class AdminToolboxPlugin extends JavaPlugin { static AdminToolboxPlugin instance; + private ModrinthUpdateChecker updateChecker; + private AdminManager adminManager; private FreezeManager freezeManager; private @Nullable StreamerModeManager streamerModeManager; @@ -56,6 +55,11 @@ public class AdminToolboxPlugin extends JavaPlugin { public void onEnable() { instance = this; + boolean shouldCheckUpdates = getConfig().getBoolean("check-updates", false); + if (shouldCheckUpdates) + getComponentLogger() + .info(new ModrinthUpdateChecker().getUpdateMessage(MODRINTH_PROJECT_ID)); + this.adminManager = new AdminManager(); this.freezeManager = new FreezeManager(); this.broadcastAudience = new PermissionAudience(BROADCAST_AUDIENCE_PERMISSION); @@ -79,42 +83,6 @@ public void onEnable() { initializeConfig(); - if (getConfig().getBoolean("check-updates", false)) { - Optional newerVersion = ModrinthUpdateChecker.getNewerVersion( - getPluginMeta().getVersion(), MODRINTH_PROJECT_ID, - Bukkit.getName().toLowerCase(), Bukkit.getMinecraftVersion()); - - Component updateMessage = newerVersion - .map(version -> { - ModrinthUpdateChecker.ModrinthFile primaryFile; - for (ModrinthUpdateChecker.ModrinthFile file : version.files()) { - if (file.primary()) { - primaryFile = file; - break; - } - } - - return Component.text() - .color(NamedTextColor.GOLD) - .appendNewline() - .append(Component.text("Version " - + version.versionNumber() - + " of " - + getPluginMeta().getName() - + " is now available!" - ).decorate(TextDecoration.BOLD)) - .appendNewline() - .append(Component.text("You are running version " - + getPluginMeta().getVersion() + ".")) - .appendNewline() - .append(Component.text("Download it here: " + version.files())) - .build(); - }) - .orElseGet(() -> Component.text("No updates are available for " + getPluginMeta().getName() + ".")); - - getComponentLogger().info(updateMessage); - } - try { RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); if (provider != null) { diff --git a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java index 24bf94d..644c37f 100644 --- a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java +++ b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java @@ -1,11 +1,13 @@ package org.modernbeta.admintoolbox; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import javax.annotation.Nonnull; +import com.google.gson.*; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Bukkit; + +import javax.annotation.Nullable; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -16,7 +18,10 @@ import java.nio.charset.StandardCharsets; import java.time.Instant; import java.time.format.DateTimeParseException; -import java.util.*; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.nio.charset.StandardCharsets.UTF_8; @@ -24,34 +29,54 @@ public class ModrinthUpdateChecker { private static final int SEMVER_LENGTH = 3; - private static final Gson GSON = new Gson(); + private final AdminToolboxPlugin plugin = AdminToolboxPlugin.getInstance(); + private final Gson gson = new Gson(); + + public TextComponent getUpdateMessage(String projectId) { + String pluginName = plugin.getPluginMeta().getName(); + String currentVersion = plugin.getPluginMeta().getVersion(); + String loader = Bukkit.getName(); + String gameVersion = Bukkit.getServer().getMinecraftVersion(); + + Optional newestCompatibleVersion = + getNewestCompatibleVersion(projectId, currentVersion, loader, gameVersion); + + return newestCompatibleVersion.map((version) -> { + TextComponent.Builder builder = Component.text() + .color(NamedTextColor.GOLD) + .appendNewline() + .append(Component.text("Version " + version.versionNumber() + + " of " + pluginName + " is now available!" + ).decorate(TextDecoration.BOLD)) + .appendNewline() + .append(Component.text("You are running version " + currentVersion + ".")); + + if (version.downloadUrl() != null) + builder + .appendNewline() + .append(Component.text("Download it here: " + version.downloadUrl())); + + return builder.appendNewline().build(); + }).orElseGet(() -> Component.text("You're running the latest release of " + pluginName + ".")); + } - public static Optional getNewerVersion(String currentVersion, String projectId, String loader, String gameVersion) { + public Optional getNewestCompatibleVersion(String projectId, String currentVersion, String loader, String gameVersion) { int[] currentVersionParsed; try { currentVersionParsed = parseSemverParts(currentVersion); } catch (NumberFormatException e) { + plugin.getLogger().warning("Could not parse current version: " + currentVersion); return Optional.empty(); } - List compatibleVersions = getCompatibleVersions(projectId, loader, gameVersion); - - for (ModrinthVersion version : compatibleVersions) { - int[] versionParsed = parseSemverParts(version.versionNumber); - if (isGreaterVersion(versionParsed, currentVersionParsed)) { - return Optional.of(version); - } - } - - return Optional.empty(); // no newer version found - } + plugin.getLogger() + .info("Checking for updates compatible with " + loader + " " + gameVersion + "..."); - private static @Nonnull List getCompatibleVersions(String projectId, String loader, String gameVersion) { try (HttpClient client = HttpClient.newHttpClient()) { // modrinth api has stupid non-standard query param expectations, // so we must wrap them in javascript arrays String queryString = Map.of( - "loaders", "[\"" + loader + "\"]", + "loaders", "[\"" + loader.toLowerCase() + "\"]", "game_versions", "[\"" + gameVersion + "\"]" ) .entrySet().stream() @@ -67,6 +92,7 @@ public static Optional getNewerVersion(String currentVersion, S queryString, null ); + HttpRequest req = HttpRequest.newBuilder() .uri(requestUri) .GET() @@ -75,48 +101,62 @@ public static Optional getNewerVersion(String currentVersion, S HttpResponse res = client.send(req, HttpResponse.BodyHandlers.ofString()); String rawBody = res.body(); - List versions = new ArrayList<>(); - JsonArray rawVersionList = GSON.fromJson(rawBody, JsonArray.class); + JsonArray rawVersionList = gson.fromJson(rawBody, JsonArray.class); for (JsonElement element : rawVersionList) { if (!element.isJsonObject()) continue; JsonObject object = element.getAsJsonObject(); - String versionNumber = object.get("version_number").getAsString(); + String versionType = object.get("version_type").getAsString(); + if (!versionType.equals("release")) continue; + String status = object.get("status").getAsString(); + if (!status.equals("listed")) continue; + + String versionNumber = object.get("version_number").getAsString(); Instant datePublished = Instant.parse(object.get("date_published").getAsString()); - List files = new ArrayList<>(); - for (JsonElement rawFile : object.get("files").getAsJsonArray()) { - if (!rawFile.isJsonObject()) continue; + if (isGreaterVersion(parseSemverParts(versionNumber), currentVersionParsed)) { + String downloadUrl = null; + for (JsonElement rawFile : object.get("files").getAsJsonArray()) { + if (!rawFile.isJsonObject()) continue; - JsonObject fileObject = rawFile.getAsJsonObject(); - String url = fileObject.get("url").getAsString(); - boolean primary = fileObject.get("primary").getAsBoolean(); + JsonObject fileObject = rawFile.getAsJsonObject(); + boolean primary = fileObject.get("primary").getAsBoolean(); + if (!primary) continue; - files.add(new ModrinthFile(url, primary)); - } + downloadUrl = fileObject.get("url").getAsString(); + break; + } - versions.add(new ModrinthVersion(versionNumber, versionType, status, datePublished, files)); + return Optional.of( + new ModrinthVersion(versionNumber, datePublished, downloadUrl)); + } + ; } - - return versions; } catch (IOException | InterruptedException e) { - return List.of(); // request failed; fail check silently + plugin.getLogger().severe("Failed request plugin versions from Modrinth!"); + plugin.getLogger().severe(e.toString()); + return Optional.empty(); + } catch (JsonParseException e) { + plugin.getLogger().severe("Failed to parse plugin versions response from Modrinth!"); + plugin.getLogger().severe(e.toString()); + return Optional.empty(); } catch (DateTimeParseException e) { - // TODO: log date parse failure - return List.of(); + plugin.getLogger().severe("Failed to parse version published_date from Modrinth!"); + plugin.getLogger().severe(e.toString()); + return Optional.empty(); } catch (URISyntaxException e) { - // TODO: log uri build failure - return List.of(); + plugin.getLogger().severe("Failed to create URL to check updates from Modrinth!"); + plugin.getLogger().severe(e.toString()); + return Optional.empty(); } - } - public record ModrinthVersion(String versionNumber, String versionType, String status, - Instant datePublished, List files) { + return Optional.empty(); // no newer version found } - public record ModrinthFile(String url, boolean primary) { + public record ModrinthVersion(String versionNumber, Instant datePublished, + @Nullable String downloadUrl) { } private static boolean isGreaterVersion(int[] a, int[] b) throws IllegalArgumentException { From e9e1f7f562d63b2f9fa3bb3f812b62cbea0c8907 Mon Sep 17 00:00:00 2001 From: Lynx Date: Tue, 6 Jan 2026 17:05:25 -0800 Subject: [PATCH 3/6] use regex to parse semver --- .../admintoolbox/ModrinthUpdateChecker.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java index 644c37f..ea4a873 100644 --- a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java +++ b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java @@ -170,15 +170,17 @@ private static boolean isGreaterVersion(int[] a, int[] b) throws IllegalArgument return false; // versions are equal } + private static final Pattern SEMVER_PATTERN = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)"); + private static int[] parseSemverParts(String version) throws NumberFormatException { - final String[] parts = version.split("\\."); - if (parts.length != SEMVER_LENGTH) - throw new NumberFormatException("Version is not valid untagged semver! (expected: x.x.x)"); + Matcher matcher = SEMVER_PATTERN.matcher(version); + if (!matcher.find()) + throw new NumberFormatException("Version is not valid semantic version! (expected: x.x.x)"); return new int[]{ - Integer.parseInt(parts[0]), - Integer.parseInt(parts[1]), - Integer.parseInt(parts[2]), + Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)), }; } } From c283bf24d092b2879aaf398d9532930317ad007d Mon Sep 17 00:00:00 2001 From: Lynx Date: Tue, 6 Jan 2026 18:00:49 -0800 Subject: [PATCH 4/6] fix comment on check-updates option --- .../java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java b/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java index effcc93..7dd29ec 100644 --- a/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java +++ b/src/main/java/org/modernbeta/admintoolbox/AdminToolboxPlugin.java @@ -194,7 +194,7 @@ public Configuration getConfigDefaults() { Configuration defaults = new YamlConfiguration(); defaults.set("check-updates", true); - defaults.setComments("check-updates", List.of("Enable update check. When enabled, AdminToolbox will notify via the server console that a new version is available.")); + defaults.setInlineComments("check-updates", List.of("Enable update check. When enabled, AdminToolbox will notify via the server console that a new version is available.")); // streamer-mode section { From 2809a9f9157055d6aa98221948c33728e7baac77 Mon Sep 17 00:00:00 2001 From: Lynx Date: Tue, 6 Jan 2026 18:01:03 -0800 Subject: [PATCH 5/6] reduce logged exception info when update check request fails --- .../admintoolbox/ModrinthUpdateChecker.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java index ea4a873..5741bb3 100644 --- a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java +++ b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java @@ -132,23 +132,18 @@ public Optional getNewestCompatibleVersion(String projectId, St return Optional.of( new ModrinthVersion(versionNumber, datePublished, downloadUrl)); } - ; } } catch (IOException | InterruptedException e) { - plugin.getLogger().severe("Failed request plugin versions from Modrinth!"); - plugin.getLogger().severe(e.toString()); + plugin.getLogger().severe("Failed request plugin versions from Modrinth: " + e.getMessage()); return Optional.empty(); } catch (JsonParseException e) { - plugin.getLogger().severe("Failed to parse plugin versions response from Modrinth!"); - plugin.getLogger().severe(e.toString()); + plugin.getLogger().severe("Failed to parse plugin versions response from Modrinth: " + e.getMessage()); return Optional.empty(); } catch (DateTimeParseException e) { - plugin.getLogger().severe("Failed to parse version published_date from Modrinth!"); - plugin.getLogger().severe(e.toString()); + plugin.getLogger().severe("Failed to parse version published_date from Modrinth: " + e.getMessage()); return Optional.empty(); } catch (URISyntaxException e) { - plugin.getLogger().severe("Failed to create URL to check updates from Modrinth!"); - plugin.getLogger().severe(e.toString()); + plugin.getLogger().severe("Failed to create URL to check updates from Modrinth: " + e.getMessage()); return Optional.empty(); } From ea83aa61302eaeaa66b30de3303c520e121bdfc8 Mon Sep 17 00:00:00 2001 From: Lynx Date: Thu, 15 Jan 2026 15:25:35 -0800 Subject: [PATCH 6/6] remove changelog metadata with new API option --- .../org/modernbeta/admintoolbox/ModrinthUpdateChecker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java index 5741bb3..306e0ab 100644 --- a/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java +++ b/src/main/java/org/modernbeta/admintoolbox/ModrinthUpdateChecker.java @@ -77,7 +77,9 @@ public Optional getNewestCompatibleVersion(String projectId, St // so we must wrap them in javascript arrays String queryString = Map.of( "loaders", "[\"" + loader.toLowerCase() + "\"]", - "game_versions", "[\"" + gameVersion + "\"]" + "game_versions", "[\"" + gameVersion + "\"]", + // Added 2026-01-15 - decreases metadata to parsed + "include_changelog", "false" ) .entrySet().stream() .map(entry ->