From 86d65e96ec63bdebba51a0baaa7862e18e21bab9 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sat, 3 Jan 2026 20:41:16 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20#4774:=20=E5=AE=89=E8=A3=85=20Modrinth=20?= =?UTF-8?q?=E6=95=B4=E5=90=88=E5=8C=85=E6=97=B6=E4=B8=8B=E8=BD=BD=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=20(#5119)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/game/HMCLModpackProvider.java | 2 +- .../jackhuang/hmcl/game/ModpackHelper.java | 8 ++--- .../hmcl/ui/download/DownloadPage.java | 10 +++---- .../hmcl/ui/download/LocalModpackPage.java | 1 + .../ModpackInstallWizardProvider.java | 11 ++++++- .../org/jackhuang/hmcl/ui/main/RootPage.java | 2 +- .../hmcl/ui/versions/DownloadPage.java | 26 ++++++++-------- .../hmcl/ui/versions/ModListPageSkin.java | 2 +- .../jackhuang/hmcl/ui/versions/Versions.java | 15 ++++++---- .../java/org/jackhuang/hmcl/mod/Modpack.java | 2 +- .../hmcl/mod/curse/CurseModpackProvider.java | 2 +- .../hmcl/mod/mcbbs/McbbsModpackManifest.java | 2 +- .../mod/modrinth/ModrinthInstallTask.java | 30 ++++++++++++++++++- .../mod/modrinth/ModrinthModpackProvider.java | 6 ++-- .../mod/multimc/MultiMCModpackProvider.java | 2 +- .../mod/server/ServerModpackManifest.java | 2 +- 16 files changed, 82 insertions(+), 41 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackProvider.java index cec33afcc..b96bd92c1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackProvider.java @@ -79,7 +79,7 @@ public final class HMCLModpackProvider implements ModpackProvider { private final static class HMCLModpack extends Modpack { @Override - public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name) { + public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl) { return new HMCLModpackInstallTask(((HMCLGameRepository) dependencyManager.getGameRepository()).getProfile(), zipFile, this, name); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java index 019d8bc4f..de71d44e7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java @@ -188,7 +188,7 @@ public final class ModpackHelper { }); } - public static Task getInstallTask(Profile profile, Path zipFile, String name, Modpack modpack) { + public static Task getInstallTask(Profile profile, Path zipFile, String name, Modpack modpack, String iconUrl) { profile.getRepository().markVersionAsModpack(name); ExceptionalRunnable success = () -> { @@ -208,17 +208,17 @@ public final class ModpackHelper { }; if (modpack.getManifest() instanceof MultiMCInstanceConfiguration) - return modpack.getInstallTask(profile.getDependency(), zipFile, name) + return modpack.getInstallTask(profile.getDependency(), zipFile, name, iconUrl) .whenComplete(Schedulers.defaultScheduler(), success, failure) .thenComposeAsync(createMultiMCPostInstallTask(profile, (MultiMCInstanceConfiguration) modpack.getManifest(), name)) .withStagesHint(List.of("hmcl.modpack", "hmcl.modpack.download")); else if (modpack.getManifest() instanceof McbbsModpackManifest) - return modpack.getInstallTask(profile.getDependency(), zipFile, name) + return modpack.getInstallTask(profile.getDependency(), zipFile, name, iconUrl) .whenComplete(Schedulers.defaultScheduler(), success, failure) .thenComposeAsync(createMcbbsPostInstallTask(profile, (McbbsModpackManifest) modpack.getManifest(), name)) .withStagesHint(List.of("hmcl.modpack", "hmcl.modpack.download")); else - return modpack.getInstallTask(profile.getDependency(), zipFile, name) + return modpack.getInstallTask(profile.getDependency(), zipFile, name, iconUrl) .whenComplete(Schedulers.javafx(), success, failure) .withStagesHint(List.of("hmcl.modpack", "hmcl.modpack.download")); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index b607b5584..aa17a4504 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -84,8 +84,8 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage newGameTab.setNodeSupplier(loadVersionFor(() -> new VersionsPage(versionPageNavigator, i18n("install.installer.choose", i18n("install.installer.game")), "", DownloadProviders.getDownloadProvider(), "game", versionPageNavigator::onGameSelected))); modpackTab.setNodeSupplier(loadVersionFor(() -> { - DownloadListPage page = HMCLLocalizedDownloadListPage.ofModPack((profile, __, file) -> { - Versions.downloadModpackImpl(profile, uploadVersion, file); + DownloadListPage page = HMCLLocalizedDownloadListPage.ofModPack((profile, __, mod, file) -> { + Versions.downloadModpackImpl(profile, uploadVersion, mod, file); }, false); JFXButton installLocalModpackButton = FXUtils.newRaisedButton(i18n("install.modpack")); @@ -94,9 +94,9 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage page.getActions().add(installLocalModpackButton); return page; })); - modTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofMod((profile, version, file) -> download(profile, version, file, "mods"), true))); - resourcePackTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofResourcePack((profile, version, file) -> download(profile, version, file, "resourcepacks"), true))); - shaderTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofShaderPack((profile, version, file) -> download(profile, version, file, "shaderpacks"), true))); + modTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofMod((profile, version, mod, file) -> download(profile, version, file, "mods"), true))); + resourcePackTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofResourcePack((profile, version, mod, file) -> download(profile, version, file, "resourcepacks"), true))); + shaderTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofShaderPack((profile, version, mod, file) -> download(profile, version, file, "shaderpacks"), true))); worldTab.setNodeSupplier(loadVersionFor(() -> new DownloadListPage(CurseForgeRemoteModRepository.WORLDS))); tab = new TabHeader(transitionPane, newGameTab, modpackTab, modTab, resourcePackTab, shaderTab, worldTab); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java index ad99b108e..41f302b9f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java @@ -180,4 +180,5 @@ public final class LocalModpackPage extends ModpackPage { public static final SettingsMap.Key MODPACK_MANIFEST = new SettingsMap.Key<>("MODPACK_MANIFEST"); public static final SettingsMap.Key MODPACK_CHARSET = new SettingsMap.Key<>("MODPACK_CHARSET"); public static final SettingsMap.Key MODPACK_MANUALLY_CREATED = new SettingsMap.Key<>("MODPACK_MANUALLY_CREATED"); + public static final SettingsMap.Key MODPACK_ICON_URL = new SettingsMap.Key<>("MODPACK_ICON_URL"); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java index c9790bc7a..bd6a40012 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java @@ -33,6 +33,7 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; import org.jackhuang.hmcl.util.SettingsMap; +import org.jackhuang.hmcl.util.StringUtils; import java.io.FileNotFoundException; import java.io.IOException; @@ -45,6 +46,7 @@ public final class ModpackInstallWizardProvider implements WizardProvider { private final Profile profile; private final Path file; private final String updateVersion; + private String iconUrl; public ModpackInstallWizardProvider(Profile profile) { this(profile, null, null); @@ -64,12 +66,18 @@ public final class ModpackInstallWizardProvider implements WizardProvider { this.updateVersion = updateVersion; } + public void setIconUrl(String iconUrl) { + this.iconUrl = iconUrl; + } + @Override public void start(SettingsMap settings) { if (file != null) settings.put(LocalModpackPage.MODPACK_FILE, file); if (updateVersion != null) settings.put(LocalModpackPage.MODPACK_NAME, updateVersion); + if (StringUtils.isNotBlank(iconUrl)) + settings.put(LocalModpackPage.MODPACK_ICON_URL, iconUrl); settings.put(ModpackPage.PROFILE, profile); } @@ -78,6 +86,7 @@ public final class ModpackInstallWizardProvider implements WizardProvider { ServerModpackManifest serverModpackManifest = settings.get(RemoteModpackPage.MODPACK_SERVER_MANIFEST); Modpack modpack = settings.get(LocalModpackPage.MODPACK_MANIFEST); String name = settings.get(LocalModpackPage.MODPACK_NAME); + String iconUrl = settings.get(LocalModpackPage.MODPACK_ICON_URL); Charset charset = settings.get(LocalModpackPage.MODPACK_CHARSET); boolean isManuallyCreated = settings.getOrDefault(LocalModpackPage.MODPACK_MANUALLY_CREATED, false); @@ -111,7 +120,7 @@ public final class ModpackInstallWizardProvider implements WizardProvider { return ModpackHelper.getInstallTask(profile, serverModpackManifest, name, modpack) .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); } else { - return ModpackHelper.getInstallTask(profile, selected, name, modpack) + return ModpackHelper.getInstallTask(profile, selected, name, modpack, iconUrl) .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java index cdaef77e5..445f67bcc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/RootPage.java @@ -299,7 +299,7 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage { .thenApplyAsync( encoding -> ModpackHelper.readModpackManifest(modpackFile, encoding)) .thenApplyAsync(modpack -> ModpackHelper - .getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack) + .getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack, null) .executor()) .thenAcceptAsync(Schedulers.javafx(), executor -> { Controllers.taskDialog(executor, i18n("modpack.installing"), TaskCancellationAction.NO_CANCEL); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java index 0afe1bafe..ed424c9ce 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java @@ -157,15 +157,15 @@ public class DownloadPage extends Control implements DecoratorPage { this.failed.set(failed); } - public void download(RemoteMod.Version file) { + public void download(RemoteMod mod, RemoteMod.Version file) { if (this.callback == null) { - saveAs(file); + saveAs(mod, file); } else { - this.callback.download(version.getProfile(), version.getVersion(), file); + this.callback.download(version.getProfile(), version.getVersion(), mod, file); } } - public void saveAs(RemoteMod.Version file) { + public void saveAs(RemoteMod mod, RemoteMod.Version file) { String extension = StringUtils.substringAfterLast(file.getFile().getFilename(), '.'); FileChooser fileChooser = new FileChooser(); @@ -287,7 +287,7 @@ public class DownloadPage extends Control implements DecoratorPage { if (targetLoaders.contains(loader)) { list.getContent().addAll( ComponentList.createComponentListTitle(i18n("mods.download.recommend", gameVersion)), - new ModItem(modVersion, control) + new ModItem(control.addon, modVersion, control) ); break resolve; } @@ -308,7 +308,7 @@ public class DownloadPage extends Control implements DecoratorPage { ComponentList sublist = new ComponentList(() -> { ArrayList items = new ArrayList<>(versions.size()); for (RemoteMod.Version v : versions) { - items.add(new ModItem(v, control)); + items.add(new ModItem(control.addon, v, control)); } return items; }); @@ -373,7 +373,7 @@ public class DownloadPage extends Control implements DecoratorPage { private static final class ModItem extends StackPane { - ModItem(RemoteMod.Version dataItem, DownloadPage selfPage) { + ModItem(RemoteMod mod, RemoteMod.Version dataItem, DownloadPage selfPage) { VBox pane = new VBox(8); pane.setPadding(new Insets(8, 0, 8, 0)); @@ -435,7 +435,7 @@ public class DownloadPage extends Control implements DecoratorPage { } RipplerContainer container = new RipplerContainer(pane); - FXUtils.onClicked(container, () -> Controllers.dialog(new ModVersion(dataItem, selfPage))); + FXUtils.onClicked(container, () -> Controllers.dialog(new ModVersion(mod, dataItem, selfPage))); getChildren().setAll(container); // Workaround for https://github.com/HMCL-dev/HMCL/issues/2129 @@ -444,7 +444,7 @@ public class DownloadPage extends Control implements DecoratorPage { } private static final class ModVersion extends JFXDialogLayout { - public ModVersion(RemoteMod.Version version, DownloadPage selfPage) { + public ModVersion(RemoteMod mod, RemoteMod.Version version, DownloadPage selfPage) { RemoteModRepository.Type type = selfPage.repository.getType(); String title = switch (type) { @@ -458,7 +458,7 @@ public class DownloadPage extends Control implements DecoratorPage { VBox box = new VBox(8); box.setPadding(new Insets(8)); - ModItem modItem = new ModItem(version, selfPage); + ModItem modItem = new ModItem(mod, version, selfPage); modItem.setMouseTransparent(true); // Item is displayed for info, clicking shouldn't open the dialog again box.getChildren().setAll(modItem); SpinnerPane spinnerPane = new SpinnerPane(); @@ -484,7 +484,7 @@ public class DownloadPage extends Control implements DecoratorPage { if (type == RemoteModRepository.Type.MODPACK || !spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) { fireEvent(new DialogCloseEvent()); } - selfPage.download(version); + selfPage.download(mod, version); }); } @@ -494,7 +494,7 @@ public class DownloadPage extends Control implements DecoratorPage { if (!spinnerPane.isLoading() && spinnerPane.getFailedReason() == null) { fireEvent(new DialogCloseEvent()); } - selfPage.saveAs(version); + selfPage.saveAs(mod, version); }); JFXButton cancelButton = new JFXButton(i18n("button.cancel")); @@ -548,6 +548,6 @@ public class DownloadPage extends Control implements DecoratorPage { } public interface DownloadCallback { - void download(Profile profile, @Nullable String version, RemoteMod.Version file); + void download(Profile profile, @Nullable String version, RemoteMod mod, RemoteMod.Version file); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index dd60f0130..6ab3f114e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -493,7 +493,7 @@ final class ModListPageSkin extends SkinBase { repository instanceof CurseForgeRemoteModRepository ? HMCLLocalizedDownloadListPage.ofCurseForgeMod(null, false) : HMCLLocalizedDownloadListPage.ofModrinthMod(null, false), remoteMod, new Profile.ProfileVersion(ModListPageSkin.this.getSkinnable().getProfile(), ModListPageSkin.this.getSkinnable().getInstanceId()), - (profile, version, file) -> org.jackhuang.hmcl.ui.download.DownloadPage.download(profile, version, file, "mods") + (profile, version, mod, file) -> org.jackhuang.hmcl.ui.download.DownloadPage.download(profile, version, file, "mods") )); }); button.setDisable(false); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index a2c9b18f4..e52b444d1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -72,7 +72,7 @@ public final class Versions { } } - public static void downloadModpackImpl(Profile profile, String version, RemoteMod.Version file) { + public static void downloadModpackImpl(Profile profile, String version, RemoteMod mod, RemoteMod.Version file) { Path modpack; URI downloadURL; try { @@ -88,11 +88,14 @@ public final class Versions { new FileDownloadTask(downloadURL, modpack) .whenComplete(Schedulers.javafx(), e -> { if (e == null) { - if (version != null) { - Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack, version)); - } else { - Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack)); - } + ModpackInstallWizardProvider installWizardProvider; + if (version != null) + installWizardProvider = new ModpackInstallWizardProvider(profile, modpack, version); + else + installWizardProvider = new ModpackInstallWizardProvider(profile, modpack); + if (StringUtils.isNotBlank(mod.getIconUrl())) + installWizardProvider.setIconUrl(mod.getIconUrl()); + Controllers.getDecorator().startWizard(installWizardProvider); } else if (e instanceof CancellationException) { Controllers.showToast(i18n("message.cancelled")); } else { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Modpack.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Modpack.java index a82c83e9b..dd05bea8e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Modpack.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/Modpack.java @@ -114,7 +114,7 @@ public abstract class Modpack { return this; } - public abstract Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name); + public abstract Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl); public static boolean acceptFile(String path, List blackList, List whiteList) { if (path.isEmpty()) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseModpackProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseModpackProvider.java index 20a1435b1..033775472 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseModpackProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseModpackProvider.java @@ -68,7 +68,7 @@ public final class CurseModpackProvider implements ModpackProvider { return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), manifest.getMinecraft().getGameVersion(), description, encoding, manifest) { @Override - public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name) { + public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl) { return new CurseInstallTask(dependencyManager, zipFile, this, manifest, name); } }; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java index 8a3687766..403a30ff7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java @@ -424,7 +424,7 @@ public class McbbsModpackManifest implements ModpackManifest, Validation { .orElseThrow(() -> new IOException("Cannot find game version")).getVersion(); return new Modpack(name, author, version, gameVersion, description, encoding, this) { @Override - public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name) { + public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl) { return new McbbsModpackLocalInstallTask(dependencyManager, zipFile, this, McbbsModpackManifest.this, name); } }; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java index b01868006..4cab142ee 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthInstallTask.java @@ -22,15 +22,23 @@ import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.mod.*; +import org.jackhuang.hmcl.task.CacheFileTask; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.JsonUtils; +import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + public class ModrinthInstallTask extends Task { + private static final Set SUPPORTED_ICON_EXTS = Set.of("png", "jpg", "jpeg", "bmp", "gif", "webp", "apng"); private final DefaultDependencyManager dependencyManager; private final DefaultGameRepository repository; @@ -38,17 +46,21 @@ public class ModrinthInstallTask extends Task { private final Modpack modpack; private final ModrinthManifest manifest; private final String name; + private final String iconUrl; private final Path run; private final ModpackConfiguration config; + private String iconExt; + private Task downloadIconTask; private final List> dependents = new ArrayList<>(4); private final List> dependencies = new ArrayList<>(1); - public ModrinthInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, Modpack modpack, ModrinthManifest manifest, String name) { + public ModrinthInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, Modpack modpack, ModrinthManifest manifest, String name, String iconUrl) { this.dependencyManager = dependencyManager; this.zipFile = zipFile; this.modpack = modpack; this.manifest = manifest; this.name = name; + this.iconUrl = iconUrl; this.repository = dependencyManager.getGameRepository(); this.run = repository.getRunDirectory(name); @@ -104,6 +116,14 @@ public class ModrinthInstallTask extends Task { dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), subDirectories, any -> true, config).withStage("hmcl.modpack")); dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), subDirectories, manifest, ModrinthModpackProvider.INSTANCE, manifest.getName(), manifest.getVersionId(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); + URI iconUri = NetworkUtils.toURIOrNull(iconUrl); + if (iconUri != null) { + String ext = FileUtils.getExtension(StringUtils.substringAfter(iconUri.getPath(), '/')).toLowerCase(Locale.ROOT); + if (SUPPORTED_ICON_EXTS.contains(ext)) { + iconExt = ext; + dependents.add(downloadIconTask = new CacheFileTask(iconUrl)); + } + } dependencies.add(new ModrinthCompletionTask(dependencyManager, name, manifest)); } @@ -133,5 +153,13 @@ public class ModrinthInstallTask extends Task { Path root = repository.getVersionRoot(name); Files.createDirectories(root); JsonUtils.writeToJsonFile(root.resolve("modrinth.index.json"), manifest); + + if (iconExt != null) { + try { + Files.copy(downloadIconTask.getResult(), root.resolve("icon." + iconExt)); + } catch (Exception e) { + LOG.warning("Failed to copy modpack icon", e); + } + } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackProvider.java index 77e154bdd..c8adc3da6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/modrinth/ModrinthModpackProvider.java @@ -50,7 +50,7 @@ public final class ModrinthModpackProvider implements ModpackProvider { if (!(modpack.getManifest() instanceof ModrinthManifest modrinthManifest)) throw new MismatchedModpackTypeException(getName(), modpack.getManifest().getProvider().getName()); - return new ModpackUpdateTask(dependencyManager.getGameRepository(), name, new ModrinthInstallTask(dependencyManager, zipFile, modpack, modrinthManifest, name)); + return new ModpackUpdateTask(dependencyManager.getGameRepository(), name, new ModrinthInstallTask(dependencyManager, zipFile, modpack, modrinthManifest, name, null)); } @Override @@ -58,8 +58,8 @@ public final class ModrinthModpackProvider implements ModpackProvider { ModrinthManifest manifest = JsonUtils.fromNonNullJson(CompressingUtils.readTextZipEntry(zip, "modrinth.index.json"), ModrinthManifest.class); return new Modpack(manifest.getName(), "", manifest.getVersionId(), manifest.getGameVersion(), manifest.getSummary(), encoding, manifest) { @Override - public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name) { - return new ModrinthInstallTask(dependencyManager, zipFile, this, manifest, name); + public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl) { + return new ModrinthInstallTask(dependencyManager, zipFile, this, manifest, name, iconUrl); } }; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackProvider.java index aff3d11c0..1bb7c8e93 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackProvider.java @@ -85,7 +85,7 @@ public final class MultiMCModpackProvider implements ModpackProvider { MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, instanceStream, manifest); return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), encoding, cfg) { @Override - public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name) { + public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl) { return new MultiMCModpackInstallTask(dependencyManager, zipFile, this, cfg, name); } }; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java index bf3c30545..b8075c09f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackManifest.java @@ -126,7 +126,7 @@ public class ServerModpackManifest implements ModpackManifest, Validation { .orElseThrow(() -> new IOException("Cannot find game version")).getVersion(); return new Modpack(name, author, version, gameVersion, description, encoding, this) { @Override - public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name) { + public Task getInstallTask(DefaultDependencyManager dependencyManager, Path zipFile, String name, String iconUrl) { return new ServerModpackLocalInstallTask(dependencyManager, zipFile, this, ServerModpackManifest.this, name); } };