diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java index 4732637ef..867ff195e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java @@ -35,6 +35,8 @@ import java.io.File; import java.io.IOException; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public final class HMCLModpackInstallTask extends Task { private final File zipFile; @@ -102,7 +104,15 @@ public final class HMCLModpackInstallTask extends Task { } dependencies.add(libraryTask.thenComposeAsync(repository::save)); - dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/minecraft", modpack, MODPACK_TYPE, repository.getModpackConfiguration(name))); + dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/minecraft", modpack, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); + } + + @Override + public List getStages() { + return Stream.concat( + dependents.stream().flatMap(task -> task.getStages().stream()), + Stream.of("hmcl.modpack") + ).collect(Collectors.toList()); } public static final String MODPACK_TYPE = "HMCL"; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 2ecb2522e..a8a7e976d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -49,7 +49,6 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.gson.UUIDTypeAdapter; -import org.jackhuang.hmcl.util.i18n.LocalizedTaskStages; import org.jackhuang.hmcl.util.io.ResponseCodeException; import org.jackhuang.hmcl.util.platform.CommandBuilder; import org.jackhuang.hmcl.util.platform.JavaVersion; @@ -128,28 +127,26 @@ public final class LauncherHelper { Version version = MaintainTask.maintain(repository, repository.getResolvedVersion(selectedVersion)); Optional gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version)); - TaskExecutor executor = Task.runAsync(() -> { - }) - .thenComposeAsync(() -> Task.allOf( - Task.composeAsync(null, () -> { - if (setting.isNotCheckGame()) - return null; - else - return dependencyManager.checkGameCompletionAsync(version, repository.unmarkVersionLaunchedAbnormally(selectedVersion)); - }), Task.composeAsync(null, () -> { - try { - ModpackConfiguration configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion)); - if ("Curse".equals(configuration.getType())) - return new CurseCompletionTask(dependencyManager, selectedVersion); - else if ("Server".equals(configuration.getType())) - return new ServerModpackCompletionTask(dependencyManager, selectedVersion); - else - return null; - } catch (IOException e) { - return null; - } - })).withStage("launch.state.dependencies")) - .thenComposeAsync(() -> Task.supplyAsync((String) null, () -> { + TaskExecutor executor = Task.allOf( + Task.composeAsync(null, () -> { + if (setting.isNotCheckGame()) + return null; + else + return dependencyManager.checkGameCompletionAsync(version, repository.unmarkVersionLaunchedAbnormally(selectedVersion)); + }), Task.composeAsync(null, () -> { + try { + ModpackConfiguration configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion)); + if ("Curse".equals(configuration.getType())) + return new CurseCompletionTask(dependencyManager, selectedVersion); + else if ("Server".equals(configuration.getType())) + return new ServerModpackCompletionTask(dependencyManager, selectedVersion); + else + return null; + } catch (IOException e) { + return null; + } + })).withStage("launch.state.dependencies") + .thenComposeAsync(Task.supplyAsync((String) null, () -> { try { return account.logIn(); } catch (CredentialExpiredException e) { @@ -199,11 +196,11 @@ public final class LauncherHelper { launchingLatch = new CountDownLatch(1); launchingLatch.await(); }).withStage("launch.state.waiting_launching")) + .withStagesHint(Lang.immutableListOf( + "launch.state.dependencies", + "launch.state.logging_in", + "launch.state.waiting_launching")) .cancellableExecutor(); - executor.setStages(new LocalizedTaskStages(Lang.immutableListOf( - "launch.state.dependencies", - "launch.state.logging_in", - "launch.state.waiting_launching"))); launchingStepsPane.setExecutor(executor, false); executor.addTaskListener(new TaskListener() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java index 4e6ba665b..b3b3f1f0c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java @@ -46,9 +46,10 @@ import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.task.TaskListener; -import org.jackhuang.hmcl.task.TaskStages; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; +import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.StringUtils; import java.util.ArrayList; import java.util.HashMap; @@ -72,7 +73,7 @@ public final class TaskListPane extends StackPane { } public void setExecutor(TaskExecutor executor) { - TaskStages stages = executor.getStages(); + List stages = Lang.removingDuplicates(executor.getStages()); this.executor = executor; executor.addTaskListener(new TaskListener() { @Override @@ -80,10 +81,10 @@ public final class TaskListPane extends StackPane { Platform.runLater(() -> { stageNodes.clear(); listBox.clear(); - stageNodes.addAll(stages.getStages().stream().map(StageNode::new).collect(Collectors.toList())); + stageNodes.addAll(stages.stream().map(StageNode::new).collect(Collectors.toList())); stageNodes.forEach(listBox::add); - if (stages.getStages().isEmpty()) progressNodePadding.setValue(new Insets(0, 0, 8, 0)); + if (stages.isEmpty()) progressNodePadding.setValue(new Insets(0, 0, 8, 0)); else progressNodePadding.setValue(new Insets(0, 0, 8, 26)); }); } @@ -182,7 +183,25 @@ public final class TaskListPane extends StackPane { public StageNode(String stage) { this.stage = stage; - title.setText(executor.getStages().localize(stage)); + String stageKey = StringUtils.substringBefore(stage, ':'); + String stageValue = StringUtils.substringAfter(stage, ':'); + String message; + + // @formatter:off + switch (stageKey) { + case "hmcl.modpack": message = i18n("install.modpack"); break; + case "hmcl.modpack.download": message = i18n("launch.state.modpack"); break; + case "hmcl.install.assets": message = i18n("assets.download"); break; + case "hmcl.install.game": message = i18n("install.installer.install", i18n("install.installer.game") + " " + stageValue); break; + case "hmcl.install.forge": message = i18n("install.installer.install", i18n("install.installer.forge") + " " + stageValue); break; + case "hmcl.install.liteloader": message = i18n("install.installer.install", i18n("install.installer.liteloader") + " " + stageValue); break; + case "hmcl.install.optifine": message = i18n("install.installer.install", i18n("install.installer.optifine") + " " + stageValue); break; + case "hmcl.install.fabric": message = i18n("install.installer.install", i18n("install.installer.fabric") + " " + stageValue); break; + default: message = i18n(stageKey); break; + } + // @formatter:on + + title.setText(message); BorderPane.setAlignment(title, Pos.CENTER_LEFT); BorderPane.setMargin(title, new Insets(0, 0, 0, 8)); setPadding(new Insets(0, 0, 8, 4)); @@ -210,7 +229,7 @@ public final class TaskListPane extends StackPane { private final Label title = new Label(); private final Label state = new Label(); private final DoubleBinding binding = Bindings.createDoubleBinding(() -> - getWidth() - getPadding().getLeft() - getPadding().getRight() - 100, + getWidth() - getPadding().getLeft() - getPadding().getRight(), paddingProperty(), widthProperty()); public ProgressListNode(Task task) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java index 5aab98603..f3e0375dc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallerWizardProvider.java @@ -30,7 +30,6 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.DownloadException; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskStages; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.wizard.WizardController; @@ -41,6 +40,8 @@ import org.jackhuang.hmcl.util.io.ResponseCodeException; import java.net.SocketTimeoutException; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -77,35 +78,18 @@ public final class InstallerWizardProvider implements WizardProvider { settings.put("title", i18n("install.installer.install_online")); settings.put("success_message", i18n("install.success")); settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> alertFailureMessage(exception, next)); - settings.put("stages", new TaskStages() { - { - if (settings.containsKey("forge")) { - RemoteVersion forge = (RemoteVersion) settings.get("forge"); - addStage("hmcl.install.forge", i18n("install.installer.install", i18n("install.installer.forge") + " " + forge.getSelfVersion())); - } - if (settings.containsKey("liteloader")) { - RemoteVersion liteloader = (RemoteVersion) settings.get("liteloader"); - addStage("hmcl.install.liteloader", i18n("install.installer.install", i18n("install.installer.liteloader") + " " + liteloader.getSelfVersion())); - } - if (settings.containsKey("optifine")) { - RemoteVersion optifine = (RemoteVersion) settings.get("optifine"); - addStage("hmcl.install.optifine", i18n("install.installer.install", i18n("install.installer.optifine") + " " + optifine.getSelfVersion())); - } - if (settings.containsKey("fabric")) { - RemoteVersion fabric = (RemoteVersion) settings.get("fabric"); - addStage("hmcl.install.fabric", i18n("install.installer.install", i18n("install.installer.fabric") + " " + fabric.getSelfVersion())); - } - } - }); Task ret = Task.supplyAsync(() -> version); - + List stages = new ArrayList<>(); for (Object value : settings.values()) { - if (value instanceof RemoteVersion) - ret = ret.thenComposeAsync(version -> profile.getDependency().installLibraryAsync(version, (RemoteVersion) value)); + if (value instanceof RemoteVersion) { + RemoteVersion remoteVersion = (RemoteVersion) value; + ret = ret.thenComposeAsync(version -> profile.getDependency().installLibraryAsync(version, remoteVersion)); + stages.add(String.format("hmcl.install.%s:%s", remoteVersion.getLibraryId(), remoteVersion.getSelfVersion())); + } } - return ret.thenComposeAsync(profile.getRepository().refreshVersionsAsync()); + return ret.thenComposeAsync(profile.getRepository().refreshVersionsAsync()).withStagesHint(stages); } @Override 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 5cd0d4428..20aa3ec76 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 @@ -22,7 +22,6 @@ import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.setting.Profile; -import org.jackhuang.hmcl.task.TaskStages; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; @@ -57,26 +56,6 @@ public final class UpdateInstallerWizardProvider implements WizardProvider { settings.put("title", i18n("install.change_version")); settings.put("success_message", i18n("install.success")); settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> alertFailureMessage(exception, next)); - settings.put("stages", new TaskStages() { - { - if (settings.containsKey("forge")) { - RemoteVersion forge = (RemoteVersion) settings.get("forge"); - addStage("hmcl.install.forge", i18n("install.installer.install", i18n("install.installer.forge") + " " + forge.getSelfVersion())); - } - if (settings.containsKey("liteloader")) { - RemoteVersion liteloader = (RemoteVersion) settings.get("liteloader"); - addStage("hmcl.install.liteloader", i18n("install.installer.install", i18n("install.installer.liteloader") + " " + liteloader.getSelfVersion())); - } - if (settings.containsKey("optifine")) { - RemoteVersion optifine = (RemoteVersion) settings.get("optifine"); - addStage("hmcl.install.optifine", i18n("install.installer.install", i18n("install.installer.optifine") + " " + optifine.getSelfVersion())); - } - if (settings.containsKey("fabric")) { - RemoteVersion fabric = (RemoteVersion) settings.get("fabric"); - addStage("hmcl.install.fabric", i18n("install.installer.install", i18n("install.installer.fabric") + " " + fabric.getSelfVersion())); - } - } - }); // We remove library but not save it, // so if installation failed will not break down current version. 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 98ade9d75..076eb2c94 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 @@ -24,7 +24,6 @@ import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.task.TaskStages; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; @@ -64,31 +63,6 @@ public final class VanillaInstallWizardProvider implements WizardProvider { settings.put("title", i18n("install.new_game")); settings.put("success_message", i18n("install.success")); settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> InstallerWizardProvider.alertFailureMessage(exception, next)); - settings.put("stages", new TaskStages() { - { - if (settings.containsKey("game")) { - RemoteVersion game = (RemoteVersion) settings.get("game"); - addStage("hmcl.install.game", i18n("install.installer.install", i18n("install.installer.game") + " " + game.getSelfVersion())); - addStage("hmcl.install.assets", i18n("assets.download")); - } - if (settings.containsKey("forge")) { - RemoteVersion forge = (RemoteVersion) settings.get("forge"); - addStage("hmcl.install.forge", i18n("install.installer.install", i18n("install.installer.forge") + " " + forge.getSelfVersion())); - } - if (settings.containsKey("liteloader")) { - RemoteVersion liteloader = (RemoteVersion) settings.get("liteloader"); - addStage("hmcl.install.liteloader", i18n("install.installer.install", i18n("install.installer.liteloader") + " " + liteloader.getSelfVersion())); - } - if (settings.containsKey("optifine")) { - RemoteVersion optifine = (RemoteVersion) settings.get("optifine"); - addStage("hmcl.install.optifine", i18n("install.installer.install", i18n("install.installer.optifine") + " " + optifine.getSelfVersion())); - } - if (settings.containsKey("fabric")) { - RemoteVersion fabric = (RemoteVersion) settings.get("fabric"); - addStage("hmcl.install.fabric", i18n("install.installer.install", i18n("install.installer.fabric") + " " + fabric.getSelfVersion())); - } - } - }); return finishVersionDownloadingAsync(settings); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java index 554897b07..9203ecfeb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java @@ -21,7 +21,6 @@ import javafx.beans.property.StringProperty; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.task.TaskListener; -import org.jackhuang.hmcl.task.TaskStages; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; @@ -76,8 +75,6 @@ public interface TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplay }); } }); - if (settings.containsKey("stages")) - executor.setStages((TaskStages) settings.get("stages")); pane.setExecutor(executor); Controllers.dialog(pane); executor.start(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/LocalizedTaskStages.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/LocalizedTaskStages.java deleted file mode 100644 index cb0cc5c2b..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/LocalizedTaskStages.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.util.i18n; - -import org.jackhuang.hmcl.task.TaskStages; - -import java.util.List; - -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; - -public class LocalizedTaskStages extends TaskStages { - public LocalizedTaskStages(List stages) { - for (String stage : stages) { - addStage(stage, i18n(stage)); - } - } -} 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 d5fe5012d..30b04b38d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultDependencyManager.java @@ -102,7 +102,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager { return versionList.loadAsync(gameVersion) .thenComposeAsync(() -> installLibraryAsync(baseVersion, versionList.getVersion(gameVersion, libraryVersion) .orElseThrow(() -> new IOException("Remote library " + libraryId + " has no version " + libraryVersion)))) - .withStage("hmcl.install." + libraryId); + .withStage(String.format("hmcl.install.%s:%s", libraryId, libraryVersion)); } @Override @@ -112,7 +112,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager { return removeLibraryAsync(baseVersion.resolvePreservingPatches(repository), libraryVersion.getLibraryId()) .thenComposeAsync(version -> libraryVersion.getInstallTask(this, version)) .thenApplyAsync(baseVersion::addPatch) - .thenComposeAsync(repository::save).withStage("hmcl.install." + libraryVersion.getLibraryId()); + .thenComposeAsync(repository::save).withStage(String.format("hmcl.install.%s:%s", libraryVersion.getLibraryId(), libraryVersion.getSelfVersion())); } public Task installLibraryAsync(Version oldVersion, Path installer) { 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 40cd175c9..94e8c08d1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DefaultGameBuilder.java @@ -21,6 +21,8 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.function.ExceptionalFunction; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -47,19 +49,27 @@ public class DefaultGameBuilder extends GameBuilder { @Override public Task buildAsync() { + List stages = new ArrayList<>(); + Task libraryTask = Task.supplyAsync(() -> new Version(name)); libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, "game", gameVersion)); + stages.add("hmcl.install.game:" + gameVersion); + stages.add("hmcl.install.assets"); - for (Map.Entry entry : toolVersions.entrySet()) + for (Map.Entry entry : toolVersions.entrySet()) { libraryTask = libraryTask.thenComposeAsync(libraryTaskHelper(gameVersion, entry.getKey(), entry.getValue())); + stages.add(String.format("hmcl.install.%s:%s", entry.getKey(), entry.getValue())); + } - for (RemoteVersion remoteVersion : remoteVersions) + for (RemoteVersion remoteVersion : remoteVersions) { libraryTask = libraryTask.thenComposeAsync(version -> dependencyManager.installLibraryAsync(version, remoteVersion)); + stages.add(String.format("hmcl.install.%s:%s", remoteVersion.getLibraryId(), remoteVersion.getSelfVersion())); + } return libraryTask.whenComplete(exception -> { if (exception != null) dependencyManager.getGameRepository().removeVersionFromDisk(name); - }); + }).withStagesHint(stages); } private ExceptionalFunction, ?> libraryTaskHelper(String gameVersion, String libraryId, String libraryVersion) { 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 d56ad0b13..047e23800 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 @@ -31,7 +31,7 @@ import java.util.LinkedList; import java.util.List; /** - * + * Task to download Minecraft jar * @author huangyuhui */ public final class GameDownloadTask extends Task { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java index 703303e4a..1556e4321 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameInstallTask.java @@ -69,11 +69,13 @@ public class GameInstallTask extends Task { setResult(patch); Version version = new Version(this.version.getId()).addPatch(patch); - dependencies.add(new GameDownloadTask(dependencyManager, remote.getGameVersion(), version) - .thenComposeAsync(Task.allOf( + dependencies.add(Task.allOf( + new GameDownloadTask(dependencyManager, remote.getGameVersion(), version), + Task.allOf( new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY, true), new GameLibrariesTask(dependencyManager, version, true) - ).withStage("hmcl.install.assets").withComposeAsync(gameRepository.save(version)))); + ).withStage("hmcl.install.assets") + ).withComposeAsync(gameRepository.save(version))); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java index 08192cfba..14a31ee35 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseInstallTask.java @@ -32,11 +32,12 @@ import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Install a downloaded CurseForge modpack. @@ -105,7 +106,8 @@ public final class CurseInstallTask extends Task { } catch (JsonParseException | IOException ignore) { } this.config = config; - dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), manifest.getOverrides(), any -> true, config)); + dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), manifest.getOverrides(), any -> true, config).withStage("hmcl.modpack")); + dependents.add(new CurseCompletionTask(dependencyManager, name, manifest).withStage("hmcl.modpack.download")); } @Override @@ -133,8 +135,15 @@ public final class CurseInstallTask extends Task { File root = repository.getVersionRoot(name); FileUtils.writeText(new File(root, "manifest.json"), JsonUtils.GSON.toJson(manifest)); - dependencies.add(new CurseCompletionTask(dependencyManager, name, manifest).withStage("hmcl.modpack.download")); - dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), manifest.getOverrides(), manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack.unzip")); + dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), manifest.getOverrides(), manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); + } + + @Override + public List getStages() { + return Stream.concat( + dependents.stream().flatMap(task -> task.getStages().stream()), + Stream.of("hmcl.modpack", "hmcl.modpack.download") + ).collect(Collectors.toList()); } public static final String MODPACK_TYPE = "Curse"; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java index 5084d5b67..4e39b23b6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java @@ -43,6 +43,8 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @@ -127,9 +129,9 @@ public final class MultiMCModpackInstallTask extends Task { try (FileSystem fs = CompressingUtils.readonly(zipFile.toPath()).setEncoding(modpack.getEncoding()).build()) { if (Files.exists(fs.getPath("/" + manifest.getName() + "/.minecraft"))) - dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/.minecraft", any -> true, config)); + dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/.minecraft", any -> true, config).withStage("hmcl.modpack")); else if (Files.exists(fs.getPath("/" + manifest.getName() + "/minecraft"))) - dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", any -> true, config)); + dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", any -> true, config).withStage("hmcl.modpack")); } } @@ -173,7 +175,15 @@ public final class MultiMCModpackInstallTask extends Task { } dependencies.add(repository.save(version)); - dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name))); + dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); + } + + @Override + public List getStages() { + return Stream.concat( + dependents.stream().flatMap(task -> task.getStages().stream()), + Stream.of("hmcl.modpack") + ).collect(Collectors.toList()); } public static final String MODPACK_TYPE = "MultiMC"; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java index 90c44d41d..6b233de67 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackLocalInstallTask.java @@ -34,6 +34,8 @@ import java.io.File; import java.io.IOException; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ServerModpackLocalInstallTask extends Task { @@ -79,7 +81,7 @@ public class ServerModpackLocalInstallTask extends Task { } } catch (JsonParseException | IOException ignore) { } - dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/overrides", any -> true, config)); + dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/overrides", any -> true, config).withStage("hmcl.modpack")); } @Override @@ -94,7 +96,15 @@ public class ServerModpackLocalInstallTask extends Task { @Override public void execute() throws Exception { - dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/overrides", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name))); + dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/overrides", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); + } + + @Override + public List getStages() { + return Stream.concat( + dependents.stream().flatMap(task -> task.getStages().stream()), + Stream.of("hmcl.modpack") + ).collect(Collectors.toList()); } public static final String MODPACK_TYPE = "Server"; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java index 1188ab8a3..0c02c9e27 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java @@ -24,6 +24,7 @@ import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.ReadOnlyStringWrapper; import org.jackhuang.hmcl.event.EventManager; import org.jackhuang.hmcl.util.InvocationDispatcher; +import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.ReflectionHelper; import org.jackhuang.hmcl.util.function.ExceptionalConsumer; @@ -34,12 +35,15 @@ import org.jackhuang.hmcl.util.function.ExceptionalSupplier; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Disposable task. @@ -91,13 +95,17 @@ public abstract class Task { } /** - * You must initialize stage in preExecute. + * You must initialize stage in constructor. * @param stage the stage */ final void setStage(String stage) { this.stage = stage; } + public List getStages() { + return getStage() == null ? Collections.emptyList() : Collections.singletonList(getStage()); + } + // state private TaskState state = TaskState.READY; @@ -688,6 +696,11 @@ public abstract class Task { public boolean isRelyingOnDependents() { return false; } + + @Override + public List getStages() { + return Lang.merge(Task.this.getStages(), super.getStages()); + } }.setExecutor(executor).setName(getCaller()); } @@ -763,11 +776,31 @@ public abstract class Task { } public Task withStage(String stage) { - StageTask task = new StageTask<>(this); + StageTask task = new StageTask(); task.setStage(stage); return task; } + public Task withStagesHint(List stages) { + return new Task() { + + @Override + public Collection> getDependents() { + return Collections.singleton(Task.this); + } + + @Override + public void execute() throws Exception { + setResult(Task.this.getResult()); + } + + @Override + public List getStages() { + return stages; + } + }; + } + public static Task runAsync(ExceptionalRunnable closure) { return runAsync(Schedulers.defaultScheduler(), closure); } @@ -803,6 +836,11 @@ public abstract class Task { public Collection> getDependencies() { return then == null ? Collections.emptySet() : Collections.singleton(then); } + + @Override + public List getStages() { + return Lang.merge(super.getStages(), then == null ? null : then.getStages()); + } }.setName(name); } @@ -862,6 +900,11 @@ public abstract class Task { public Collection> getDependents() { return tasks; } + + @Override + public List getStages() { + return tasks.stream().flatMap(task -> task.getStages().stream()).collect(Collectors.toList()); + } }; } @@ -929,6 +972,11 @@ public abstract class Task { public void execute() throws Exception { setResult(callable.apply(Task.this.getResult())); } + + @Override + public List getStages() { + return Lang.merge(Task.this.getStages(), super.getStages()); + } } /** @@ -988,22 +1036,30 @@ public abstract class Task { public boolean isRelyingOnDependents() { return relyingOnDependents; } + + @Override + public List getStages() { + return Stream.of(Task.this.getStages(), super.getStages(), succ == null ? Collections.emptyList() : succ.getStages()) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } } - public static class StageTask extends Task { - private final Task task; - StageTask(Task task) { - this.task = task; - } + public class StageTask extends Task { @Override public Collection> getDependents() { - return Collections.singleton(task); + return Collections.singleton(Task.this); } @Override public void execute() throws Exception { - setResult(task.getResult()); + setResult(Task.this.getResult()); + } + + @Override + public List getStages() { + return Lang.merge(Task.this.getStages(), super.getStages()); } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java index 3fe6888b1..3bcb88f3f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskExecutor.java @@ -30,10 +30,11 @@ public abstract class TaskExecutor { protected final AtomicInteger totTask = new AtomicInteger(0); protected final AtomicBoolean cancelled = new AtomicBoolean(false); protected Exception exception; - private TaskStages stages = TaskStages.EMPTY; + private final List stages; public TaskExecutor(Task task) { this.firstTask = task; + this.stages = task.getStages(); } public void addTaskListener(TaskListener taskListener) { @@ -66,11 +67,7 @@ public abstract class TaskExecutor { return totTask.get(); } - public TaskStages getStages() { + public List getStages() { return stages; } - - public void setStages(TaskStages stages) { - this.stages = stages; - } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskStages.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskStages.java deleted file mode 100644 index 0f4463636..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/TaskStages.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.task; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class TaskStages { - public static final TaskStages EMPTY = new TaskStages(); - - private final List stages = new ArrayList<>(); - private final Map localization = new HashMap<>(); - - protected void addStage(String stage, String localizedMessage) { - stages.add(stage); - localization.put(stage, localizedMessage); - } - - public List getStages() { - return stages; - } - - public String localize(String stage) { - return localization.get(stage); - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java index 983bc3210..9e2df62a1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java @@ -112,6 +112,12 @@ public final class Lang { return operator.apply(a, b); } + public static List removingDuplicates(List list) { + LinkedHashSet set = new LinkedHashSet<>(list.size()); + set.addAll(list); + return new ArrayList<>(set); + } + /** * Join two collections into one list. *