From a3c203ad3f1275d98596e39185e9c21d33791e85 Mon Sep 17 00:00:00 2001 From: LostLuma Date: Sat, 13 Apr 2024 06:49:05 +0200 Subject: [PATCH 1/6] Allow choosing an update channel to receive notifications for --- .../modmenu/api/UpdateChannel.java | 7 +++++++ .../terraformersmc/modmenu/api/UpdateInfo.java | 5 ++++- .../modmenu/config/ModMenuConfig.java | 2 ++ .../modmenu/util/UpdateCheckerUtil.java | 13 ++++++++++++- .../com/terraformersmc/modmenu/util/mod/Mod.java | 3 ++- .../modmenu/util/mod/ModrinthUpdateInfo.java | 16 +++++++++++----- .../resources/assets/modmenu/lang/en_us.json | 6 +++++- 7 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java new file mode 100644 index 000000000..ffe800ec2 --- /dev/null +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java @@ -0,0 +1,7 @@ +package com.terraformersmc.modmenu.api; + +public enum UpdateChannel { + ALPHA, + BETA, + RELEASE, +} diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateInfo.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateInfo.java index fee9c07b7..b5f40a4f0 100644 --- a/src/main/java/com/terraformersmc/modmenu/api/UpdateInfo.java +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateInfo.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.Nullable; public interface UpdateInfo { - /** * @return If an update for the mod is available. */ @@ -23,4 +22,8 @@ default Text getUpdateMessage() { */ String getDownloadLink(); + /** + * @return The update channel this update is available for. + */ + UpdateChannel getUpdateChannel(); } diff --git a/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java b/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java index bdeba118b..9ad11d111 100644 --- a/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java +++ b/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java @@ -1,6 +1,7 @@ package com.terraformersmc.modmenu.config; import com.google.gson.annotations.SerializedName; +import com.terraformersmc.modmenu.api.UpdateChannel; import com.terraformersmc.modmenu.config.option.BooleanConfigOption; import com.terraformersmc.modmenu.config.option.EnumConfigOption; import com.terraformersmc.modmenu.config.option.OptionConvertable; @@ -44,6 +45,7 @@ public class ModMenuConfig { public static final BooleanConfigOption UPDATE_CHECKER = new BooleanConfigOption("update_checker", true); public static final BooleanConfigOption BUTTON_UPDATE_BADGE = new BooleanConfigOption("button_update_badge", true); public static final BooleanConfigOption QUICK_CONFIGURE = new BooleanConfigOption("quick_configure", true); + public static final EnumConfigOption UPDATE_CHANNEL = new EnumConfigOption<>("update_channel", UpdateChannel.RELEASE); public static SimpleOption[] asOptions() { ArrayList> options = new ArrayList<>(); diff --git a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java index 509c20600..fc39d28a7 100644 --- a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java +++ b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java @@ -4,6 +4,7 @@ import com.google.gson.JsonParser; import com.google.gson.annotations.SerializedName; import com.terraformersmc.modmenu.ModMenu; +import com.terraformersmc.modmenu.api.UpdateChannel; import com.terraformersmc.modmenu.api.UpdateChecker; import com.terraformersmc.modmenu.config.ModMenuConfig; import com.terraformersmc.modmenu.util.mod.Mod; @@ -109,6 +110,7 @@ public static void checkForModrinthUpdates() { responseObject.asMap().forEach((lookupHash, versionJson) -> { var versionObj = versionJson.getAsJsonObject(); var projectId = versionObj.get("project_id").getAsString(); + var versionType = versionObj.get("version_type").getAsString(); var versionNumber = versionObj.get("version_number").getAsString(); var versionId = versionObj.get("id").getAsString(); var primaryFile = versionObj.get("files").getAsJsonArray().asList().stream() @@ -118,13 +120,14 @@ public static void checkForModrinthUpdates() { return; } + var updateChannel = UpdateCheckerUtil.getUpdateChannel(versionType); var versionHash = primaryFile.get().getAsJsonObject().get("hashes").getAsJsonObject().get("sha512").getAsString(); if (!Objects.equals(versionHash, lookupHash)) { // hashes different, there's an update. modHashes.get(lookupHash).forEach(mod -> { LOGGER.info("Update available for '{}@{}', (-> {})", mod.getId(), mod.getVersion(), versionNumber); - mod.setUpdateInfo(new ModrinthUpdateInfo(projectId, versionId, versionNumber)); + mod.setUpdateInfo(new ModrinthUpdateInfo(projectId, versionId, versionNumber, updateChannel)); }); } }); @@ -134,6 +137,14 @@ public static void checkForModrinthUpdates() { } } + private static UpdateChannel getUpdateChannel(String versionType) { + try { + return UpdateChannel.valueOf(versionType.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException | NullPointerException e) { + return UpdateChannel.RELEASE; + } + } + public static void triggerV2DeprecatedToast() { if (modrinthApiV2Deprecated && ModMenuConfig.UPDATE_CHECKER.getValue()) { MinecraftClient.getInstance().getToastManager().add(new SystemToast( diff --git a/src/main/java/com/terraformersmc/modmenu/util/mod/Mod.java b/src/main/java/com/terraformersmc/modmenu/util/mod/Mod.java index 22c95d6a3..58e2ec4d2 100644 --- a/src/main/java/com/terraformersmc/modmenu/util/mod/Mod.java +++ b/src/main/java/com/terraformersmc/modmenu/util/mod/Mod.java @@ -114,7 +114,8 @@ default boolean hasUpdate() { if (updateInfo == null) { return false; } - return updateInfo.isUpdateAvailable(); + + return updateInfo.isUpdateAvailable() && updateInfo.getUpdateChannel().compareTo(ModMenuConfig.UPDATE_CHANNEL.getValue()) >= 0; } default @Nullable String getSha512Hash() throws IOException { diff --git a/src/main/java/com/terraformersmc/modmenu/util/mod/ModrinthUpdateInfo.java b/src/main/java/com/terraformersmc/modmenu/util/mod/ModrinthUpdateInfo.java index 9a17b5a46..f982211b0 100644 --- a/src/main/java/com/terraformersmc/modmenu/util/mod/ModrinthUpdateInfo.java +++ b/src/main/java/com/terraformersmc/modmenu/util/mod/ModrinthUpdateInfo.java @@ -1,17 +1,19 @@ package com.terraformersmc.modmenu.util.mod; +import com.terraformersmc.modmenu.api.UpdateChannel; import com.terraformersmc.modmenu.api.UpdateInfo; public class ModrinthUpdateInfo implements UpdateInfo { + protected final String projectId; + protected final String versionId; + protected final String versionNumber; + protected final UpdateChannel updateChannel; - protected String projectId; - protected String versionId; - protected String versionNumber; - - public ModrinthUpdateInfo(String projectId, String versionId, String versionNumber) { + public ModrinthUpdateInfo(String projectId, String versionId, String versionNumber, UpdateChannel updateChannel) { this.projectId = projectId; this.versionId = versionId; this.versionNumber = versionNumber; + this.updateChannel = updateChannel; } @Override @@ -36,4 +38,8 @@ public String getVersionNumber() { return versionNumber; } + @Override + public UpdateChannel getUpdateChannel() { + return this.updateChannel; + } } diff --git a/src/main/resources/assets/modmenu/lang/en_us.json b/src/main/resources/assets/modmenu/lang/en_us.json index 1c42d9fb8..0d6f80b03 100644 --- a/src/main/resources/assets/modmenu/lang/en_us.json +++ b/src/main/resources/assets/modmenu/lang/en_us.json @@ -164,5 +164,9 @@ "option.modmenu.button_update_badge.false": "Hidden", "option.modmenu.quick_configure": "Quick Configure", "option.modmenu.quick_configure.true": "Enabled", - "option.modmenu.quick_configure.false": "Disabled" + "option.modmenu.quick_configure.false": "Disabled", + "option.modmenu.update_channel": "Update Channel", + "option.modmenu.update_channel.alpha": "All", + "option.modmenu.update_channel.beta": "Release & Beta", + "option.modmenu.update_channel.release": "Release" } From 2cb269a256d2448a2a9b6f04a452b1f002712bf5 Mon Sep 17 00:00:00 2001 From: LostLuma Date: Tue, 16 Apr 2024 20:34:30 +0200 Subject: [PATCH 2/6] Pass user preferred update channel to UpdateChecker --- .../java/com/terraformersmc/modmenu/api/UpdateChannel.java | 3 +++ .../java/com/terraformersmc/modmenu/api/UpdateChecker.java | 7 ++++--- .../com/terraformersmc/modmenu/util/UpdateCheckerUtil.java | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java index ffe800ec2..533ce5dc6 100644 --- a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java @@ -1,5 +1,8 @@ package com.terraformersmc.modmenu.api; +/** + * Supported update channels, in ascending order by stability. + */ public enum UpdateChannel { ALPHA, BETA, diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java index 1c2aa231e..f9e8956fd 100644 --- a/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java @@ -1,13 +1,14 @@ package com.terraformersmc.modmenu.api; public interface UpdateChecker { - /** * Gets called when ModMenu is checking for updates. * This is done in a separate thread, so this call can/should be blocking. * + * Your update checker should aim to return an update on the same or a more stable channel than requested. + * + * @param updateChannel The end user's preferred update channel. * @return The update info */ - UpdateInfo checkForUpdates(); - + UpdateInfo checkForUpdates(UpdateChannel updateChannel); } diff --git a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java index fc39d28a7..7a7dc93ba 100644 --- a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java +++ b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java @@ -46,12 +46,14 @@ public static void checkForUpdates() { } public static void checkForCustomUpdates() { + UpdateChannel preferredChannel = ModMenuConfig.UPDATE_CHANNEL.getValue(); + ModMenu.MODS.values().stream().filter(UpdateCheckerUtil::allowsUpdateChecks).forEach(mod -> { UpdateChecker updateChecker = mod.getUpdateChecker(); if (updateChecker == null) { return; } - UpdateCheckerThread.run(mod, () -> mod.setUpdateInfo(updateChecker.checkForUpdates())); + UpdateCheckerThread.run(mod, () -> mod.setUpdateInfo(updateChecker.checkForUpdates(preferredChannel))); }); } From b6b699bcc27b0f357498770694f9b9e54121fe5d Mon Sep 17 00:00:00 2001 From: LostLuma Date: Tue, 16 Apr 2024 21:19:52 +0200 Subject: [PATCH 3/6] Change method of getting the preferred update channel --- .../com/terraformersmc/modmenu/api/UpdateChannel.java | 11 ++++++++++- .../com/terraformersmc/modmenu/api/UpdateChecker.java | 5 ++--- .../modmenu/util/UpdateCheckerUtil.java | 4 +--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java index 533ce5dc6..fe4082504 100644 --- a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java @@ -1,10 +1,19 @@ package com.terraformersmc.modmenu.api; +import com.terraformersmc.modmenu.config.ModMenuConfig; + /** * Supported update channels, in ascending order by stability. */ public enum UpdateChannel { ALPHA, BETA, - RELEASE, + RELEASE; + + /** + * @return the user's preferred update channel. + */ + public UpdateChannel getUserPreference() { + return ModMenuConfig.UPDATE_CHANNEL.getValue(); + } } diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java index f9e8956fd..de80fd93b 100644 --- a/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateChecker.java @@ -5,10 +5,9 @@ public interface UpdateChecker { * Gets called when ModMenu is checking for updates. * This is done in a separate thread, so this call can/should be blocking. * - * Your update checker should aim to return an update on the same or a more stable channel than requested. + *

Your update checker should aim to return an update on the same or a more stable channel than the user's preference which you can get via {@link UpdateChannel#getUserPreference()}.

* - * @param updateChannel The end user's preferred update channel. * @return The update info */ - UpdateInfo checkForUpdates(UpdateChannel updateChannel); + UpdateInfo checkForUpdates(); } diff --git a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java index 7a7dc93ba..fc39d28a7 100644 --- a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java +++ b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java @@ -46,14 +46,12 @@ public static void checkForUpdates() { } public static void checkForCustomUpdates() { - UpdateChannel preferredChannel = ModMenuConfig.UPDATE_CHANNEL.getValue(); - ModMenu.MODS.values().stream().filter(UpdateCheckerUtil::allowsUpdateChecks).forEach(mod -> { UpdateChecker updateChecker = mod.getUpdateChecker(); if (updateChecker == null) { return; } - UpdateCheckerThread.run(mod, () -> mod.setUpdateInfo(updateChecker.checkForUpdates(preferredChannel))); + UpdateCheckerThread.run(mod, () -> mod.setUpdateInfo(updateChecker.checkForUpdates())); }); } From 867e384e02ccb307ad8a28fa74c8ef53d8d084ed Mon Sep 17 00:00:00 2001 From: LostLuma Date: Tue, 16 Apr 2024 22:11:16 +0200 Subject: [PATCH 4/6] Request preferred version types from Modrinth only --- .../modmenu/api/UpdateChannel.java | 2 +- .../modmenu/util/UpdateCheckerUtil.java | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java index fe4082504..4c51835c9 100644 --- a/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java +++ b/src/main/java/com/terraformersmc/modmenu/api/UpdateChannel.java @@ -13,7 +13,7 @@ public enum UpdateChannel { /** * @return the user's preferred update channel. */ - public UpdateChannel getUserPreference() { + public static UpdateChannel getUserPreference() { return ModMenuConfig.UPDATE_CHANNEL.getValue(); } } diff --git a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java index fc39d28a7..ce4ef7ceb 100644 --- a/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java +++ b/src/main/java/com/terraformersmc/modmenu/util/UpdateCheckerUtil.java @@ -86,7 +86,20 @@ public static void checkForModrinthUpdates() { .get().getMetadata().getVersion().getFriendlyString().split("\\+", 1); // Strip build metadata for privacy final var modMenuVersion = splitVersion.length > 1 ? splitVersion[1] : splitVersion[0]; final var userAgent = "%s/%s (%s/%s%s)".formatted(ModMenu.GITHUB_REF, modMenuVersion, mcVer, primaryLoader, environment); - String body = ModMenu.GSON_MINIFIED.toJson(new LatestVersionsFromHashesBody(modHashes.keySet(), loaders, mcVer)); + + List updateChannels; + UpdateChannel preferredChannel = UpdateChannel.getUserPreference(); + + if (preferredChannel == UpdateChannel.RELEASE) { + updateChannels = List.of(UpdateChannel.RELEASE); + } else if (preferredChannel == UpdateChannel.BETA) { + updateChannels = List.of(UpdateChannel.BETA, UpdateChannel.RELEASE); + } else { + updateChannels = List.of(UpdateChannel.ALPHA, UpdateChannel.BETA, UpdateChannel.RELEASE); + } + + String body = ModMenu.GSON_MINIFIED.toJson(new LatestVersionsFromHashesBody(modHashes.keySet(), loaders, mcVer, updateChannels)); + LOGGER.debug("User agent: " + userAgent); LOGGER.debug("Body: " + body); var latestVersionsRequest = HttpRequest.newBuilder() @@ -161,11 +174,14 @@ public static class LatestVersionsFromHashesBody { public Collection loaders; @SerializedName("game_versions") public Collection gameVersions; + @SerializedName("version_types") + public Collection versionTypes; - public LatestVersionsFromHashesBody(Collection hashes, Collection loaders, String mcVersion) { + public LatestVersionsFromHashesBody(Collection hashes, Collection loaders, String mcVersion, Collection updateChannels) { this.hashes = hashes; this.loaders = loaders; this.gameVersions = Set.of(mcVersion); + this.versionTypes = updateChannels.stream().map(value -> value.toString().toLowerCase()).toList(); } } } From 2c0c23655ed14142721d64ff446976aa96fd085a Mon Sep 17 00:00:00 2001 From: LostLuma Date: Thu, 18 Apr 2024 18:10:06 +0200 Subject: [PATCH 5/6] Switch update channel and quick configure button order --- .../java/com/terraformersmc/modmenu/config/ModMenuConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java b/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java index 9ad11d111..038c419ea 100644 --- a/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java +++ b/src/main/java/com/terraformersmc/modmenu/config/ModMenuConfig.java @@ -44,8 +44,8 @@ public class ModMenuConfig { public static final StringSetConfigOption DISABLE_UPDATE_CHECKER = new StringSetConfigOption("disable_update_checker", new HashSet<>()); public static final BooleanConfigOption UPDATE_CHECKER = new BooleanConfigOption("update_checker", true); public static final BooleanConfigOption BUTTON_UPDATE_BADGE = new BooleanConfigOption("button_update_badge", true); - public static final BooleanConfigOption QUICK_CONFIGURE = new BooleanConfigOption("quick_configure", true); public static final EnumConfigOption UPDATE_CHANNEL = new EnumConfigOption<>("update_channel", UpdateChannel.RELEASE); + public static final BooleanConfigOption QUICK_CONFIGURE = new BooleanConfigOption("quick_configure", true); public static SimpleOption[] asOptions() { ArrayList> options = new ArrayList<>(); From 4619a5db78bdf02e6de3135a05ba9eb020fc165f Mon Sep 17 00:00:00 2001 From: LostLuma Date: Thu, 18 Apr 2024 18:35:08 +0200 Subject: [PATCH 6/6] Rerun update checks when clicking done in the modmenu options screen --- src/main/java/com/terraformersmc/modmenu/ModMenu.java | 6 +++++- .../terraformersmc/modmenu/gui/ModMenuOptionsScreen.java | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/terraformersmc/modmenu/ModMenu.java b/src/main/java/com/terraformersmc/modmenu/ModMenu.java index 07ddcd3ab..770b7ab0e 100644 --- a/src/main/java/com/terraformersmc/modmenu/ModMenu.java +++ b/src/main/java/com/terraformersmc/modmenu/ModMenu.java @@ -99,7 +99,7 @@ public void onInitializeClient() { MODS.put(mod.getId(), mod); } - UpdateCheckerUtil.checkForUpdates(); + checkForUpdates(); Map dummyParents = new HashMap<>(); @@ -127,6 +127,10 @@ public static void clearModCountCache() { cachedDisplayedModCount = -1; } + public static void checkForUpdates() { + UpdateCheckerUtil.checkForUpdates(); + } + public static boolean areModUpdatesAvailable() { if (!ModMenuConfig.UPDATE_CHECKER.getValue()) { return false; diff --git a/src/main/java/com/terraformersmc/modmenu/gui/ModMenuOptionsScreen.java b/src/main/java/com/terraformersmc/modmenu/gui/ModMenuOptionsScreen.java index 3e9c4a753..b0efeb3ba 100644 --- a/src/main/java/com/terraformersmc/modmenu/gui/ModMenuOptionsScreen.java +++ b/src/main/java/com/terraformersmc/modmenu/gui/ModMenuOptionsScreen.java @@ -1,5 +1,6 @@ package com.terraformersmc.modmenu.gui; +import com.terraformersmc.modmenu.ModMenu; import com.terraformersmc.modmenu.config.ModMenuConfig; import com.terraformersmc.modmenu.config.ModMenuConfigManager; import net.minecraft.client.MinecraftClient; @@ -29,6 +30,7 @@ protected void init() { this.addSelectableChild(this.list); this.addDrawableChild( ButtonWidget.builder(ScreenTexts.DONE, (button) -> { + ModMenu.checkForUpdates(); ModMenuConfigManager.save(); this.client.setScreen(this.previous); }).position(this.width / 2 - 100, this.height - 27)