diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java index 6eedecc10..5a2c12351 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/DownloadProviders.java @@ -17,19 +17,14 @@ */ package org.jackhuang.hmcl.setting; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.ObjectBinding; -import javafx.beans.value.ObservableObjectValue; +import org.jackhuang.hmcl.download.AdaptedDownloadProvider; import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.MojangDownloadProvider; -import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.ui.FXUtils; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ThreadPoolExecutor; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -40,6 +35,8 @@ import static org.jackhuang.hmcl.util.Pair.pair; public final class DownloadProviders { private DownloadProviders() {} + private static final AdaptedDownloadProvider DOWNLOAD_PROVIDER = new AdaptedDownloadProvider(); + public static final Map providersById = mapOf( pair("mojang", new MojangDownloadProvider()), pair("bmclapi", new BMCLAPIDownloadProvider("https://bmclapi2.bangbang93.com")), @@ -47,32 +44,44 @@ public final class DownloadProviders { public static final String DEFAULT_PROVIDER_ID = "mcbbs"; - private static ObjectBinding downloadProviderProperty; - static void init() { - downloadProviderProperty = Bindings.createObjectBinding( - () -> Optional.ofNullable(providersById.get(config().getDownloadType())) - .orElse(providersById.get(DEFAULT_PROVIDER_ID)), - config().downloadTypeProperty()); + FXUtils.onChangeAndOperate(config().downloadTypeProperty(), downloadType -> { + DownloadProvider primary = Optional.ofNullable(providersById.get(config().getDownloadType())) + .orElse(providersById.get(DEFAULT_PROVIDER_ID)); + DOWNLOAD_PROVIDER.setDownloadProviderCandidates( + Stream.concat( + Stream.of(primary), + providersById.values().stream().filter(x -> x != primary) + ).collect(Collectors.toList()) + ); + }); + } + + public static String getPrimaryDownloadProviderId() { + String downloadType = config().getDownloadType(); + if (providersById.containsKey(downloadType)) + return downloadType; + else + return DEFAULT_PROVIDER_ID; + } + + public static AdaptedDownloadProvider getDownloadProviderByPrimaryId(String primaryId) { + AdaptedDownloadProvider adaptedDownloadProvider = new AdaptedDownloadProvider(); + DownloadProvider primary = Optional.ofNullable(providersById.get(primaryId)) + .orElse(providersById.get(DEFAULT_PROVIDER_ID)); + adaptedDownloadProvider.setDownloadProviderCandidates( + Stream.concat( + Stream.of(primary), + providersById.values().stream().filter(x -> x != primary) + ).collect(Collectors.toList()) + ); + return adaptedDownloadProvider; } /** * Get current primary preferred download provider */ - public static DownloadProvider getDownloadProvider() { - return downloadProviderProperty.get(); - } - - /** - * Preferred download providers have the primary one first, the official one next. - * @return the preferred download providers - */ - public static List getPreferredDownloadProviders() { - DownloadProvider provider = getDownloadProvider(); - return Stream.concat(Stream.of(provider), providersById.values().stream().filter(x -> x != provider)).collect(Collectors.toList()); - } - - public static ObservableObjectValue downloadProviderProperty() { - return downloadProviderProperty; + public static AdaptedDownloadProvider getDownloadProvider() { + return DOWNLOAD_PROVIDER; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardDownloadProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardDownloadProvider.java new file mode 100644 index 000000000..22be7f19b --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardDownloadProvider.java @@ -0,0 +1,72 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2020 huangyuhui and 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 . + */ +package org.jackhuang.hmcl.ui.download; + +import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.VersionList; + +import java.net.URL; +import java.util.List; + +public class InstallerWizardDownloadProvider implements DownloadProvider { + + private DownloadProvider fallback; + + public InstallerWizardDownloadProvider(DownloadProvider fallback) { + this.fallback = fallback; + } + + public void setDownloadProvider(DownloadProvider downloadProvider) { + fallback = downloadProvider; + } + + @Override + public String getVersionListURL() { + return fallback.getVersionListURL(); + } + + @Override + public String getAssetBaseURL() { + return fallback.getAssetBaseURL(); + } + + @Override + public List getAssetObjectCandidates(String assetObjectLocation) { + return fallback.injectURLWithCandidates(assetObjectLocation); + } + + @Override + public String injectURL(String baseURL) { + return fallback.injectURL(baseURL); + } + + @Override + public List injectURLWithCandidates(String baseURL) { + return fallback.injectURLWithCandidates(baseURL); + } + + @Override + public VersionList getVersionListById(String id) { + return fallback.getVersionListById(id); + } + + @Override + public int getConcurrency() { + return fallback.getConcurrency(); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java index de5653280..62b4fedb6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java @@ -37,7 +37,6 @@ import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.game.GameRepository; import org.jackhuang.hmcl.setting.Theme; @@ -64,7 +63,7 @@ public class InstallersPage extends Control implements WizardPage { protected JFXTextField txtName = new JFXTextField(); protected BooleanProperty installable = new SimpleBooleanProperty(); - public InstallersPage(WizardController controller, GameRepository repository, String gameVersion, DownloadProvider downloadProvider) { + public InstallersPage(WizardController controller, GameRepository repository, String gameVersion, InstallerWizardDownloadProvider downloadProvider) { this.controller = controller; Validator hasVersion = new Validator(s -> !repository.hasVersion(s) && StringUtils.isNotBlank(s)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java index 1bde0b72e..d77c18466 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java @@ -18,12 +18,16 @@ package org.jackhuang.hmcl.ui.download; import javafx.scene.Node; -import org.jackhuang.hmcl.download.*; +import org.jackhuang.hmcl.download.ArtifactMalformedException; +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.RemoteVersion; +import org.jackhuang.hmcl.download.VersionMismatchException; import org.jackhuang.hmcl.download.fabric.FabricInstallTask; import org.jackhuang.hmcl.download.game.GameAssetIndexDownloadTask; import org.jackhuang.hmcl.download.game.LibraryDownloadException; import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask; import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.setting.DownloadProviders; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.DownloadException; import org.jackhuang.hmcl.task.Task; @@ -53,14 +57,16 @@ public final class UpdateInstallerWizardProvider implements WizardProvider { private final Version version; private final String libraryId; private final String oldLibraryVersion; + private final InstallerWizardDownloadProvider downloadProvider; public UpdateInstallerWizardProvider(@NotNull Profile profile, @NotNull String gameVersion, @NotNull Version version, @NotNull String libraryId, @Nullable String oldLibraryVersion) { this.profile = profile; - this.dependencyManager = profile.getDependency(); this.gameVersion = gameVersion; this.version = version; this.libraryId = libraryId; this.oldLibraryVersion = oldLibraryVersion; + this.downloadProvider = new InstallerWizardDownloadProvider(DownloadProviders.getDownloadProvider()); + this.dependencyManager = profile.getDependency(downloadProvider); } @Override @@ -95,15 +101,14 @@ public final class UpdateInstallerWizardProvider implements WizardProvider { @Override public Node createPage(WizardController controller, int step, Map settings) { - DownloadProvider provider = profile.getDependency().getPrimaryDownloadProvider(); switch (step) { case 0: - return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), gameVersion, provider, libraryId, () -> { + return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), gameVersion, downloadProvider, libraryId, () -> { if (oldLibraryVersion == null) { controller.onFinish(); } else if ("game".equals(libraryId)) { String newGameVersion = ((RemoteVersion) settings.get(libraryId)).getSelfVersion(); - controller.onNext(new AdditionalInstallersPage(newGameVersion, version, controller, profile.getRepository(), provider)); + controller.onNext(new AdditionalInstallersPage(newGameVersion, version, controller, profile.getRepository(), downloadProvider)); } else { Controllers.confirm(i18n("install.change_version.confirm", i18n("install.installer." + libraryId), oldLibraryVersion, ((RemoteVersion) settings.get(libraryId)).getSelfVersion()), i18n("install.change_version"), controller::onFinish, controller::onCancel); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java index 19ba95755..99bb88117 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java @@ -18,9 +18,10 @@ package org.jackhuang.hmcl.ui.download; import javafx.scene.Node; -import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.GameBuilder; import org.jackhuang.hmcl.download.RemoteVersion; +import org.jackhuang.hmcl.setting.DownloadProviders; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; @@ -33,9 +34,13 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class VanillaInstallWizardProvider implements WizardProvider { private final Profile profile; + private final DefaultDependencyManager dependencyManager; + private final InstallerWizardDownloadProvider downloadProvider; public VanillaInstallWizardProvider(Profile profile) { this.profile = profile; + this.downloadProvider = new InstallerWizardDownloadProvider(DownloadProviders.getDownloadProvider()); + this.dependencyManager = profile.getDependency(downloadProvider); } @Override @@ -44,7 +49,7 @@ public final class VanillaInstallWizardProvider implements WizardProvider { } private Task finishVersionDownloadingAsync(Map settings) { - GameBuilder builder = profile.getDependency().gameBuilder(); + GameBuilder builder = dependencyManager.gameBuilder(); String name = (String) settings.get("name"); builder.name(name); @@ -69,11 +74,10 @@ public final class VanillaInstallWizardProvider implements WizardProvider { @Override public Node createPage(WizardController controller, int step, Map settings) { - DownloadProvider provider = profile.getDependency().getPrimaryDownloadProvider(); switch (step) { case 0: - return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer.game")), "", provider, "game", - () -> controller.onNext(new InstallersPage(controller, profile.getRepository(), ((RemoteVersion) controller.getSettings().get("game")).getGameVersion(), provider))); + return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer.game")), "", downloadProvider, "game", + () -> controller.onNext(new InstallersPage(controller, profile.getRepository(), ((RemoteVersion) controller.getSettings().get("game")).getGameVersion(), downloadProvider))); default: throw new IllegalStateException("error step " + step + ", settings: " + settings + ", pages: " + controller.getPages()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java index 605ac6ed4..2ff3a5d74 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.ui.download; import com.jfoenix.controls.JFXCheckBox; +import com.jfoenix.controls.JFXComboBox; import com.jfoenix.controls.JFXListView; import com.jfoenix.controls.JFXSpinner; import javafx.application.Platform; @@ -31,7 +32,6 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.fabric.FabricRemoteVersion; @@ -39,6 +39,7 @@ import org.jackhuang.hmcl.download.forge.ForgeRemoteVersion; import org.jackhuang.hmcl.download.game.GameRemoteVersion; import org.jackhuang.hmcl.download.liteloader.LiteLoaderRemoteVersion; import org.jackhuang.hmcl.download.optifine.OptiFineRemoteVersion; +import org.jackhuang.hmcl.setting.DownloadProviders; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; @@ -54,6 +55,7 @@ import java.util.Map; import java.util.logging.Level; import java.util.stream.Collectors; +import static org.jackhuang.hmcl.ui.FXUtils.stringConverter; import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -83,23 +85,34 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres private HBox checkPane; @FXML private VBox centrePane; + @FXML + private JFXComboBox downloadSourceComboBox; - private final VersionList versionList; + private VersionList versionList; private TaskExecutor executor; - public VersionsPage(WizardController controller, String title, String gameVersion, DownloadProvider downloadProvider, String libraryId, Runnable callback) { + public VersionsPage(WizardController controller, String title, String gameVersion, InstallerWizardDownloadProvider downloadProvider, String libraryId, Runnable callback) { this.title = title; this.gameVersion = gameVersion; this.libraryId = libraryId; this.controller = controller; - this.versionList = downloadProvider.getVersionListById(libraryId); FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml"); - if (versionList.hasType()) { - centrePane.getChildren().setAll(checkPane, list); - } else - centrePane.getChildren().setAll(list); + downloadSourceComboBox.getItems().setAll(DownloadProviders.providersById.keySet()); + downloadSourceComboBox.setConverter(stringConverter(key -> i18n("download.provider." + key))); + downloadSourceComboBox.getSelectionModel().selectedItemProperty().addListener((a, b, newValue) -> { + controller.getSettings().put("downloadProvider", newValue); + downloadProvider.setDownloadProvider(DownloadProviders.getDownloadProviderByPrimaryId(newValue)); + versionList = downloadProvider.getVersionListById(libraryId); + if (versionList.hasType()) { + centrePane.getChildren().setAll(checkPane, list); + } else { + centrePane.getChildren().setAll(list); + } + refresh(); + }); + downloadSourceComboBox.getSelectionModel().select((String)controller.getSettings().getOrDefault("downloadProvider", DownloadProviders.getPrimaryDownloadProviderId())); InvalidationListener listener = o -> list.getItems().setAll(loadVersions()); chkRelease.selectedProperty().addListener(listener); @@ -184,13 +197,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres @Override public void refresh() { + VersionList currentVersionList = versionList; root.setContent(spinner, ContainerAnimations.FADE.getAnimationProducer()); - executor = versionList.refreshAsync(gameVersion).whenComplete(exception -> { + executor = currentVersionList.refreshAsync(gameVersion).whenComplete(exception -> { if (exception == null) { List items = loadVersions(); Platform.runLater(() -> { - if (versionList.getVersions(gameVersion).isEmpty()) { + if (versionList != currentVersionList) return; + if (currentVersionList.getVersions(gameVersion).isEmpty()) { root.setContent(emptyPane, ContainerAnimations.FADE.getAnimationProducer()); } else { if (items.isEmpty()) { @@ -206,6 +221,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres } else { LOG.log(Level.WARNING, "Failed to fetch versions list", exception); Platform.runLater(() -> { + if (versionList != currentVersionList) return; root.setContent(failedPane, ContainerAnimations.FADE.getAnimationProducer()); }); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index 7ac9b7173..23f99197a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -34,7 +34,6 @@ import org.jackhuang.hmcl.setting.*; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; -import org.jackhuang.hmcl.ui.construct.Navigator; import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.upgrade.RemoteVersion; @@ -63,7 +62,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.util.Lang.thread; import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.reservedSelectedPropertyFor; +import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.reversedSelectedPropertyFor; import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor; public final class SettingsPage extends SettingsView implements DecoratorPage { @@ -111,7 +110,7 @@ public final class SettingsPage extends SettingsView implements DecoratorPage { proxyPane.disableProperty().bind(chkDisableProxy.selectedProperty()); authPane.disableProperty().bind(chkProxyAuthentication.selectedProperty().not()); - reservedSelectedPropertyFor(chkDisableProxy).bindBidirectional(config().hasProxyProperty()); + reversedSelectedPropertyFor(chkDisableProxy).bindBidirectional(config().hasProxyProperty()); chkProxyAuthentication.selectedProperty().bindBidirectional(config().hasProxyAuthProperty()); ToggleGroup proxyConfigurationGroup = new ToggleGroup(); diff --git a/HMCL/src/main/resources/assets/fxml/download/versions.fxml b/HMCL/src/main/resources/assets/fxml/download/versions.fxml index 454142834..bee83477f 100644 --- a/HMCL/src/main/resources/assets/fxml/download/versions.fxml +++ b/HMCL/src/main/resources/assets/fxml/download/versions.fxml @@ -9,9 +9,20 @@ type="BorderPane" prefHeight="400.0" prefWidth="600.0"> - - + + + + + + + + + + + +
diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AbstractDependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AbstractDependencyManager.java index 75859b3c3..b70c5da39 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AbstractDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AbstractDependencyManager.java @@ -17,23 +17,19 @@ */ package org.jackhuang.hmcl.download; -import java.util.List; - /** * * @author huangyuhui */ public abstract class AbstractDependencyManager implements DependencyManager { - public abstract DownloadProvider getPrimaryDownloadProvider(); - - public abstract List getPreferredDownloadProviders(); + public abstract DownloadProvider getDownloadProvider(); @Override public abstract DefaultCacheRepository getCacheRepository(); @Override public VersionList getVersionList(String id) { - return getPrimaryDownloadProvider().getVersionListById(id); + return getDownloadProvider().getVersionListById(id); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AdaptedDownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AdaptedDownloadProvider.java new file mode 100644 index 000000000..e6d001294 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/AdaptedDownloadProvider.java @@ -0,0 +1,81 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2020 huangyuhui and 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 . + */ +package org.jackhuang.hmcl.download; + +import org.jackhuang.hmcl.util.io.NetworkUtils; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * The download provider that changes the real download source in need. + * + * @author huangyuhui + */ +public class AdaptedDownloadProvider implements DownloadProvider { + + private List downloadProviderCandidates; + + public void setDownloadProviderCandidates(List downloadProviderCandidates) { + this.downloadProviderCandidates = new ArrayList<>(downloadProviderCandidates); + } + + public DownloadProvider getPreferredDownloadProvider() { + List d = downloadProviderCandidates; + if (d == null || d.isEmpty()) { + throw new IllegalStateException("No download provider candidate"); + } + return d.get(0); + } + + @Override + public String getVersionListURL() { + return getPreferredDownloadProvider().getVersionListURL(); + } + + @Override + public String getAssetBaseURL() { + return getPreferredDownloadProvider().getAssetBaseURL(); + } + + @Override + public String injectURL(String baseURL) { + return getPreferredDownloadProvider().injectURL(baseURL); + } + + @Override + public List injectURLWithCandidates(String baseURL) { + List d = downloadProviderCandidates; + List results = new ArrayList<>(d.size()); + for (int i = 0; i < d.size(); i++) { + results.add(NetworkUtils.toURL(d.get(i).injectURL(baseURL))); + } + return results; + } + + @Override + public VersionList getVersionListById(String id) { + return getPreferredDownloadProvider().getVersionListById(id); + } + + @Override + public int getConcurrency() { + return getPreferredDownloadProvider().getConcurrency(); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java index 1c58e545e..7a54c11e6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java @@ -28,7 +28,6 @@ import org.jackhuang.hmcl.task.Task; import java.io.IOException; import java.nio.file.Path; -import java.util.List; /** * Note: This class has no state. @@ -39,13 +38,11 @@ public class DefaultDependencyManager extends AbstractDependencyManager { private final DefaultGameRepository repository; private final DownloadProvider downloadProvider; - private final List preferredDownloadProviders; private final DefaultCacheRepository cacheRepository; - public DefaultDependencyManager(DefaultGameRepository repository, DownloadProvider downloadProvider, List preferredDownloadProviders, DefaultCacheRepository cacheRepository) { + public DefaultDependencyManager(DefaultGameRepository repository, DownloadProvider downloadProvider, DefaultCacheRepository cacheRepository) { this.repository = repository; this.downloadProvider = downloadProvider; - this.preferredDownloadProviders = preferredDownloadProviders; this.cacheRepository = cacheRepository; } @@ -55,15 +52,10 @@ public class DefaultDependencyManager extends AbstractDependencyManager { } @Override - public DownloadProvider getPrimaryDownloadProvider() { + public DownloadProvider getDownloadProvider() { return downloadProvider; } - @Override - public List getPreferredDownloadProviders() { - return preferredDownloadProviders; - } - @Override public DefaultCacheRepository getCacheRepository() { return cacheRepository; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java index 32240ed6e..09c8bafed 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java @@ -32,21 +32,15 @@ import java.util.Map; public class DefaultGameBuilder extends GameBuilder { private final DefaultDependencyManager dependencyManager; - private final DownloadProvider downloadProvider; public DefaultGameBuilder(DefaultDependencyManager dependencyManager) { this.dependencyManager = dependencyManager; - this.downloadProvider = dependencyManager.getPrimaryDownloadProvider(); } public DefaultDependencyManager getDependencyManager() { return dependencyManager; } - public DownloadProvider getDownloadProvider() { - return downloadProvider; - } - @Override public Task buildAsync() { List stages = new ArrayList<>(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java index 4229a3334..7ef333044 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java @@ -17,6 +17,13 @@ */ package org.jackhuang.hmcl.download; +import org.jackhuang.hmcl.util.io.NetworkUtils; + +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + /** * The service provider that provides Minecraft online file downloads. * @@ -28,6 +35,10 @@ public interface DownloadProvider { String getAssetBaseURL(); + default List getAssetObjectCandidates(String assetObjectLocation) { + return Collections.singletonList(NetworkUtils.toURL(getAssetBaseURL() + assetObjectLocation)); + } + /** * Inject into original URL provided by Mojang and Forge. * @@ -40,9 +51,26 @@ public interface DownloadProvider { String injectURL(String baseURL); /** - * the specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine" + * Inject into original URL provided by Mojang and Forge. * - * @param id the id of specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine" + * Since there are many provided URLs that are written in JSONs and are unmodifiable, + * this method provides a way to change them. + * + * @param baseURL original URL provided by Mojang and Forge. + * @return the URL that is equivalent to [baseURL], but belongs to your own service provider. + */ + default List injectURLWithCandidates(String baseURL) { + return Collections.singletonList(NetworkUtils.toURL(baseURL)); + } + + default List injectURLsWithCandidates(List urls) { + return urls.stream().flatMap(url -> injectURLWithCandidates(url).stream()).collect(Collectors.toList()); + } + + /** + * the specific version list that this download provider provides. i.e. "fabric", "forge", "liteloader", "game", "optifine" + * + * @param id the id of specific version list that this download provider provides. i.e. "fabric", "forge", "liteloader", "game", "optifine" * @return the version list * @throws IllegalArgumentException if the version list does not exist */ diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/RemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/RemoteVersion.java index a7d2f7536..86ed4335a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/RemoteVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/RemoteVersion.java @@ -35,7 +35,7 @@ public class RemoteVersion implements Comparable { private final String libraryId; private final String gameVersion; private final String selfVersion; - private final String[] url; + private final List urls; private final Type type; /** @@ -43,10 +43,10 @@ public class RemoteVersion implements Comparable { * * @param gameVersion the Minecraft version that this remote version suits. * @param selfVersion the version string of the remote version. - * @param url the installer or universal jar URL. + * @param urls the installer or universal jar original URL. */ - public RemoteVersion(String libraryId, String gameVersion, String selfVersion, String... url) { - this(libraryId, gameVersion, selfVersion, Type.UNCATEGORIZED, url); + public RemoteVersion(String libraryId, String gameVersion, String selfVersion, List urls) { + this(libraryId, gameVersion, selfVersion, Type.UNCATEGORIZED, urls); } /** @@ -54,13 +54,13 @@ public class RemoteVersion implements Comparable { * * @param gameVersion the Minecraft version that this remote version suits. * @param selfVersion the version string of the remote version. - * @param url the installer or universal jar URL. + * @param urls the installer or universal jar URL. */ - public RemoteVersion(String libraryId, String gameVersion, String selfVersion, Type type, String... url) { + public RemoteVersion(String libraryId, String gameVersion, String selfVersion, Type type, List urls) { this.libraryId = Objects.requireNonNull(libraryId); this.gameVersion = Objects.requireNonNull(gameVersion); this.selfVersion = Objects.requireNonNull(selfVersion); - this.url = Objects.requireNonNull(url); + this.urls = Objects.requireNonNull(urls); this.type = Objects.requireNonNull(type); } @@ -76,8 +76,8 @@ public class RemoteVersion implements Comparable { return selfVersion; } - public String[] getUrl() { - return url; + public List getUrls() { + return urls; } public Type getVersionType() { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java index 275ce04c9..699ff0155 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java @@ -28,10 +28,8 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.gson.JsonUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; import java.util.*; -import java.util.stream.Collectors; /** * Note: Fabric should be installed first. @@ -51,9 +49,7 @@ public final class FabricInstallTask extends Task { this.version = version; this.remote = remoteVersion; - launchMetaTask = new GetTask(dependencyManager.getPreferredDownloadProviders().stream() - .map(downloadProvider -> downloadProvider.injectURL(getLaunchMetaUrl(remote.getGameVersion(), remote.getSelfVersion()))) - .map(NetworkUtils::toURL).collect(Collectors.toList())) + launchMetaTask = new GetTask(dependencyManager.getDownloadProvider().injectURLsWithCandidates(remoteVersion.getUrls())) .setCacheRepository(dependencyManager.getCacheRepository()); } @@ -90,10 +86,6 @@ public final class FabricInstallTask extends Task { dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true)); } - private static String getLaunchMetaUrl(String gameVersion, String loaderVersion) { - return String.format("https://meta.fabricmc.net/v2/versions/loader/%s/%s", gameVersion, loaderVersion); - } - private Version getPatch(FabricInfo fabricInfo, String gameVersion, String loaderVersion) { JsonObject launcherMeta = fabricInfo.launcherMeta; Arguments arguments = new Arguments(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricVersionList.java index b9a86cf21..cdac8f2bf 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricVersionList.java @@ -48,7 +48,7 @@ public final class FabricVersionList extends VersionList { public Task refreshAsync() { return new Task() { @Override - public void execute() throws IOException, XMLStreamException { + public void execute() throws IOException { List gameVersions = getGameVersions(GAME_META_URL); List loaderVersions = getGameVersions(LOADER_META_URL); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java index c66739879..3ce2ef998 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeInstallTask.java @@ -27,15 +27,15 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; -import org.jackhuang.hmcl.util.versioning.VersionNumber; import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; import static org.jackhuang.hmcl.util.StringUtils.removePrefix; import static org.jackhuang.hmcl.util.StringUtils.removeSuffix; @@ -69,9 +69,7 @@ public final class ForgeInstallTask extends Task { installer = Files.createTempFile("forge-installer", ".jar"); dependent = new FileDownloadTask( - dependencyManager.getPreferredDownloadProviders().stream() - .flatMap(downloadProvider -> Arrays.stream(remote.getUrl()).map(downloadProvider::injectURL)) - .map(NetworkUtils::toURL).collect(Collectors.toList()), + dependencyManager.getDownloadProvider().injectURLsWithCandidates(remote.getUrls()), installer.toFile(), null) .setCacheRepository(dependencyManager.getCacheRepository()) .setCaching(true); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeRemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeRemoteVersion.java index 561438fd2..e0a70b7e7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeRemoteVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeRemoteVersion.java @@ -23,15 +23,17 @@ import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.Task; +import java.util.List; + public class ForgeRemoteVersion extends RemoteVersion { /** * Constructor. * * @param gameVersion the Minecraft version that this remote version suits. * @param selfVersion the version string of the remote version. - * @param url the installer or universal jar URL. + * @param url the installer or universal jar original URL. */ - public ForgeRemoteVersion(String gameVersion, String selfVersion, String... url) { + public ForgeRemoteVersion(String gameVersion, String selfVersion, List url) { super(LibraryAnalyzer.LibraryType.FORGE.getPatchId(), gameVersion, selfVersion, url); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java index 6f698be2e..f6b32d62f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetDownloadTask.java @@ -18,7 +18,6 @@ package org.jackhuang.hmcl.download.game; import com.google.gson.JsonParseException; -import com.google.gson.JsonSyntaxException; import org.jackhuang.hmcl.download.AbstractDependencyManager; import org.jackhuang.hmcl.game.AssetIndex; import org.jackhuang.hmcl.game.AssetIndexInfo; @@ -30,7 +29,6 @@ import org.jackhuang.hmcl.util.CacheRepository; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; import java.io.IOException; @@ -39,7 +37,6 @@ import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; -import java.util.stream.Collectors; /** * @@ -112,10 +109,7 @@ public final class GameAssetDownloadTask extends Task { Logging.LOG.log(Level.WARNING, "Unable to calc hash value of file " + file.toPath(), e); } if (download) { - List urls = dependencyManager.getPreferredDownloadProviders().stream() - .map(downloadProvider -> downloadProvider.getAssetBaseURL() + assetObject.getLocation()) - .map(NetworkUtils::toURL) - .collect(Collectors.toList()); + List urls = dependencyManager.getDownloadProvider().getAssetObjectCandidates(assetObject.getLocation()); FileDownloadTask task = new FileDownloadTask(urls, file, new FileDownloadTask.IntegrityCheck("SHA-1", assetObject.getHash())); task.setName(assetObject.getHash()); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java index 717bad4f3..3f56f2b5c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameAssetIndexDownloadTask.java @@ -22,7 +22,6 @@ import org.jackhuang.hmcl.game.AssetIndexInfo; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; import java.io.IOException; @@ -65,7 +64,7 @@ public final class GameAssetIndexDownloadTask extends Task { // We should not check the hash code of asset index file since this file is not consistent // And Mojang will modify this file anytime. So assetIndex.hash might be outdated. dependencies.add(new FileDownloadTask( - NetworkUtils.toURL(dependencyManager.getPrimaryDownloadProvider().injectURL(assetIndexInfo.getUrl())), + dependencyManager.getDownloadProvider().injectURLWithCandidates(assetIndexInfo.getUrl()), assetIndexFile ).setCacheRepository(dependencyManager.getCacheRepository())); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java index f279700c6..0b906dc54 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameDownloadTask.java @@ -23,13 +23,11 @@ import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.CacheRepository; -import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; import java.util.Collection; import java.util.LinkedList; import java.util.List; -import java.util.stream.Collectors; /** * Task to download Minecraft jar @@ -59,9 +57,7 @@ public final class GameDownloadTask extends Task { File jar = dependencyManager.getGameRepository().getVersionJar(version); FileDownloadTask task = new FileDownloadTask( - dependencyManager.getPreferredDownloadProviders().stream() - .map(downloadProvider -> downloadProvider.injectURL(version.getDownloadInfo().getUrl())) - .map(NetworkUtils::toURL).collect(Collectors.toList()), + dependencyManager.getDownloadProvider().injectURLWithCandidates(version.getDownloadInfo().getUrl()), jar, IntegrityCheck.of(CacheRepository.SHA1, version.getDownloadInfo().getSha1())) .setCaching(true) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java index 6d33a01d4..1c14d1300 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java @@ -33,7 +33,7 @@ import org.tukaani.xz.XZInputStream; import java.io.*; import java.net.URL; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -42,7 +42,6 @@ import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; import java.util.jar.Pack200; import java.util.logging.Level; -import java.util.stream.Collectors; import static org.jackhuang.hmcl.util.DigestUtils.digest; import static org.jackhuang.hmcl.util.Hex.encodeHex; @@ -130,21 +129,15 @@ public class LibraryDownloadTask extends Task { } try { - URL packXz = NetworkUtils.toURL(dependencyManager.getPrimaryDownloadProvider().injectURL(url) + ".pack.xz"); + URL packXz = NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(url) + ".pack.xz"); if (NetworkUtils.urlExists(packXz)) { - List urls = dependencyManager.getPreferredDownloadProviders().stream() - .map(downloadProvider -> downloadProvider.injectURL(url) + ".pack.xz") - .map(NetworkUtils::toURL) - .collect(Collectors.toList()); + List urls = dependencyManager.getDownloadProvider().injectURLWithCandidates(url + ".pack.xz"); task = new FileDownloadTask(urls, xzFile, null) .setCacheRepository(cacheRepository) .setCaching(true); xz = true; } else { - List urls = dependencyManager.getPreferredDownloadProviders().stream() - .map(downloadProvider -> downloadProvider.injectURL(url)) - .map(NetworkUtils::toURL) - .collect(Collectors.toList()); + List urls = dependencyManager.getDownloadProvider().injectURLWithCandidates(url); task = new FileDownloadTask(urls, jar, library.getDownload().getSha1() != null ? new IntegrityCheck("SHA-1", library.getDownload().getSha1()) : null) .setCacheRepository(cacheRepository) @@ -192,7 +185,7 @@ public class LibraryDownloadTask extends Task { while (entry != null) { byte[] eData = IOUtils.readFullyWithoutClosing(jar); if (entry.getName().equals("checksums.sha1")) { - hashes = new String(eData, Charset.forName("UTF-8")).split("\n"); + hashes = new String(eData, StandardCharsets.UTF_8).split("\n"); } if (!entry.isDirectory()) { files.put(entry.getName(), encodeHex(digest("SHA-1", eData))); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java index af4eaad18..8eb1ebddd 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/VersionJsonDownloadTask.java @@ -22,14 +22,11 @@ import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.IOException; -import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; -import java.util.stream.Collectors; /** * @@ -46,9 +43,8 @@ public final class VersionJsonDownloadTask extends Task { this.gameVersion = gameVersion; this.dependencyManager = dependencyManager; this.gameVersionList = dependencyManager.getVersionList("game"); - - if (!gameVersionList.isLoaded()) - dependents.add(gameVersionList.refreshAsync()); + + dependents.add(gameVersionList.loadAsync()); setSignificance(TaskSignificance.MODERATE); } @@ -67,10 +63,6 @@ public final class VersionJsonDownloadTask extends Task { public void execute() throws IOException { RemoteVersion remoteVersion = gameVersionList.getVersion(gameVersion, gameVersion) .orElseThrow(() -> new IOException("Cannot find specific version " + gameVersion + " in remote repository")); - dependencies.add(new GetTask( - dependencyManager.getPreferredDownloadProviders().stream() - .flatMap(downloadProvider -> Arrays.stream(remoteVersion.getUrl()).map(downloadProvider::injectURL)) - .map(NetworkUtils::toURL).collect(Collectors.toList()) - ).storeTo(this::setResult)); + dependencies.add(new GetTask(dependencyManager.getDownloadProvider().injectURLsWithCandidates(remoteVersion.getUrls())).storeTo(this::setResult)); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java index cc5767122..430b057a5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.platform.JavaVersion; import org.jackhuang.hmcl.util.platform.SystemUtils; import org.jenkinsci.constant_pool_scanner.ConstantPool; @@ -96,9 +95,7 @@ public final class OptiFineInstallTask extends Task { if (installer == null) { dependents.add(new FileDownloadTask( - dependencyManager.getPreferredDownloadProviders().stream() - .flatMap(downloadProvider -> Arrays.stream(remote.getUrl()).map(downloadProvider::injectURL)) - .map(NetworkUtils::toURL).collect(Collectors.toList()), + dependencyManager.getDownloadProvider().injectURLsWithCandidates(remote.getUrls()), dest.toFile(), null) .setCacheRepository(dependencyManager.getCacheRepository()) .setCaching(true)); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java index ff2bc4114..fbe4e5c0c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java @@ -119,6 +119,15 @@ public class FileDownloadTask extends Task { this(Collections.singletonList(url), file, integrityCheck, retry); } + /** + * Constructor. + * @param urls urls of remote file, will be attempted in order. + * @param file the location that download to. + */ + public FileDownloadTask(List urls, File file) { + this(urls, file, null); + } + /** * Constructor. * @param urls urls of remote file, will be attempted in order. diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/ExtendedProperties.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/ExtendedProperties.java index 7ae2371b8..a0541eab9 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/ExtendedProperties.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/javafx/ExtendedProperties.java @@ -17,7 +17,12 @@ */ package org.jackhuang.hmcl.util.javafx; -import static org.jackhuang.hmcl.util.Pair.pair; +import javafx.beans.InvalidationListener; +import javafx.beans.WeakInvalidationListener; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.Property; +import javafx.collections.ObservableList; +import javafx.scene.control.*; import java.util.Objects; import java.util.Optional; @@ -25,16 +30,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; -import javafx.beans.InvalidationListener; -import javafx.beans.WeakInvalidationListener; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.Property; -import javafx.collections.ObservableList; -import javafx.scene.control.CheckBox; -import javafx.scene.control.ComboBox; -import javafx.scene.control.SelectionModel; -import javafx.scene.control.Toggle; -import javafx.scene.control.ToggleGroup; +import static org.jackhuang.hmcl.util.Pair.pair; /** * @author yushijinhun @@ -126,7 +122,7 @@ public final class ExtendedProperties { // ==== CheckBox ==== @SuppressWarnings("unchecked") - public static ObjectProperty reservedSelectedPropertyFor(CheckBox checkbox) { + public static ObjectProperty reversedSelectedPropertyFor(CheckBox checkbox) { return (ObjectProperty) checkbox.getProperties().computeIfAbsent( PROP_PREFIX + ".checkbox.reservedSelected", any -> new MappedProperty(checkbox, "ext.reservedSelected",