Remove AutoTypingMap

This commit is contained in:
huanghongxun 2019-02-23 22:44:52 +08:00
parent fff7abc2ac
commit a388450f94
29 changed files with 233 additions and 330 deletions

View File

@ -122,14 +122,14 @@ public final class LauncherHelper {
Optional<String> gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version)); Optional<String> gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version));
TaskExecutor executor = Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.DEPENDENCIES)) TaskExecutor executor = Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.DEPENDENCIES))
.then(variables -> { .then(() -> {
if (setting.isNotCheckGame()) if (setting.isNotCheckGame())
return null; return null;
else else
return dependencyManager.checkGameCompletionAsync(version); return dependencyManager.checkGameCompletionAsync(version);
}) })
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.MODS))) .then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.MODS)))
.then(var -> { .then(() -> {
try { try {
ModpackConfiguration<?> configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion)); ModpackConfiguration<?> configuration = ModpackHelper.readModpackConfiguration(repository.getModpackConfiguration(selectedVersion));
if ("Curse".equals(configuration.getType())) if ("Curse".equals(configuration.getType()))
@ -141,44 +141,42 @@ public final class LauncherHelper {
} }
}) })
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN))) .then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN)))
.then(Task.of(i18n("account.methods"), variables -> { .thenTaskResult(() -> Task.ofResult(i18n("account.methods"), () -> {
try { try {
variables.set("account", account.logIn()); return account.logIn();
} catch (CredentialExpiredException e) { } catch (CredentialExpiredException e) {
LOG.info("Credential has expired: " + e); LOG.info("Credential has expired: " + e);
variables.set("account", DialogController.logIn(account)); return DialogController.logIn(account);
} catch (AuthenticationException e) { } catch (AuthenticationException e) {
LOG.warning("Authentication failed, try playing offline: " + e); LOG.warning("Authentication failed, try playing offline: " + e);
variables.set("account", return account.playOffline().orElseThrow(() -> e);
account.playOffline().orElseThrow(() -> e));
} }
})) }))
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LAUNCHING))) .thenResult(Schedulers.javafx(), authInfo -> {
.then(Task.of(variables -> { emitStatus(LoadingState.LAUNCHING);
variables.set("launcher", new HMCLGameLauncher( return authInfo;
repository, })
selectedVersion, .thenResult(authInfo -> new HMCLGameLauncher(
variables.get("account"), repository,
setting.toLaunchOptions(profile.getGameDir()), selectedVersion,
launcherVisibility == LauncherVisibility.CLOSE authInfo,
? null // Unnecessary to start listening to game process output when close launcher immediately after game launched. setting.toLaunchOptions(profile.getGameDir()),
: new HMCLProcessListener(variables.get("account"), setting, gameVersion.isPresent()) launcherVisibility == LauncherVisibility.CLOSE
)); ? null // Unnecessary to start listening to game process output when close launcher immediately after game launched.
})) : new HMCLProcessListener(authInfo, setting, gameVersion.isPresent())
.then(variables -> { ))
DefaultLauncher launcher = variables.get("launcher"); .thenTaskResult(launcher -> { // launcher is prev task's result
if (scriptFile == null) { if (scriptFile == null) {
return new LaunchTask<>(launcher::launch).setName(i18n("version.launch")); return new LaunchTask<>(launcher::launch).setName(i18n("version.launch"));
} else { } else {
return new LaunchTask<>(() -> { return new LaunchTask<ManagedProcess>(() -> {
launcher.makeLaunchScript(scriptFile); launcher.makeLaunchScript(scriptFile);
return null; return null;
}).setName(i18n("version.launch_script")); }).setName(i18n("version.launch_script"));
} }
}) })
.then(Task.of(variables -> { .thenVoid(process -> { // process is LaunchTask's result
if (scriptFile == null) { if (scriptFile == null) {
ManagedProcess process = variables.get(LaunchTask.LAUNCH_ID);
PROCESSES.add(process); PROCESSES.add(process);
if (launcherVisibility == LauncherVisibility.CLOSE) if (launcherVisibility == LauncherVisibility.CLOSE)
Launcher.stopApplication(); Launcher.stopApplication();
@ -187,13 +185,13 @@ public final class LauncherHelper {
process.stop(); process.stop();
it.fireEvent(new DialogCloseEvent()); it.fireEvent(new DialogCloseEvent());
}); });
} else } else {
Platform.runLater(() -> { Platform.runLater(() -> {
launchingStepsPane.fireEvent(new DialogCloseEvent()); launchingStepsPane.fireEvent(new DialogCloseEvent());
Controllers.dialog(i18n("version.launch_script.success", scriptFile.getAbsolutePath())); Controllers.dialog(i18n("version.launch_script.success", scriptFile.getAbsolutePath()));
}); });
}
})) })
.executor(); .executor();
launchingStepsPane.setExecutor(executor, false); launchingStepsPane.setExecutor(executor, false);
@ -429,13 +427,6 @@ public final class LauncherHelper {
public void execute() throws Exception { public void execute() throws Exception {
setResult(supplier.get()); setResult(supplier.get());
} }
@Override
public String getId() {
return LAUNCH_ID;
}
static final String LAUNCH_ID = "launch";
} }
/** /**

View File

@ -121,13 +121,12 @@ public final class LeftPaneController extends AdvancedListBox {
if (modpackFile.exists()) { if (modpackFile.exists()) {
Task.ofResult(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath())) Task.ofResult(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath()))
.thenResult(encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding)) .thenResult(encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding))
.thenResult(modpack -> { .thenVoid(modpack -> {
AtomicReference<Region> region = new AtomicReference<>(); AtomicReference<Region> region = new AtomicReference<>();
TaskExecutor executor = ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack) TaskExecutor executor = ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack)
.with(Task.of(Schedulers.javafx(), this::checkAccount)).executor(); .with(Task.of(Schedulers.javafx(), this::checkAccount)).executor();
region.set(Controllers.taskDialog(executor, i18n("modpack.installing"))); region.set(Controllers.taskDialog(executor, i18n("modpack.installing")));
executor.start(); executor.start();
return null;
}).start(); }).start();
} }
} }

View File

@ -27,6 +27,7 @@ import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.DownloadException; import org.jackhuang.hmcl.task.DownloadException;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.task.TaskResult;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.construct.MessageBox;
import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardController;
@ -89,16 +90,16 @@ public final class InstallerWizardProvider implements WizardProvider {
settings.put("success_message", i18n("install.success")); settings.put("success_message", i18n("install.success"));
settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> alertFailureMessage(exception, next)); settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> alertFailureMessage(exception, next));
Task ret = Task.ofResult("version", () -> version); TaskResult<Version> ret = Task.ofResult(() -> version);
if (settings.containsKey("forge")) if (settings.containsKey("forge"))
ret = ret.then(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("forge"))); ret = ret.thenTaskResult(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("forge")));
if (settings.containsKey("liteloader")) if (settings.containsKey("liteloader"))
ret = ret.then(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("liteloader"))); ret = ret.thenTaskResult(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("liteloader")));
if (settings.containsKey("optifine")) if (settings.containsKey("optifine"))
ret = ret.then(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("optifine"))); ret = ret.thenTaskResult(profile.getDependency().installLibraryAsync((RemoteVersion) settings.get("optifine")));
return ret.then(profile.getRepository().refreshVersionsAsync()); return ret.then(profile.getRepository().refreshVersionsAsync());
} }

View File

@ -54,7 +54,7 @@ public class InstallerListPage extends ListPage<InstallerItem> {
LinkedList<Library> newList = new LinkedList<>(version.getLibraries()); LinkedList<Library> newList = new LinkedList<>(version.getLibraries());
newList.remove(library); newList.remove(library);
new MaintainTask(version.setLibraries(newList)) new MaintainTask(version.setLibraries(newList))
.then(variables -> new VersionJsonSaveTask(profile.getRepository(), variables.get(MaintainTask.ID))) .then(maintainedVersion -> new VersionJsonSaveTask(profile.getRepository(), maintainedVersion))
.with(profile.getRepository().refreshVersionsAsync()) .with(profile.getRepository().refreshVersionsAsync())
.with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId))) .with(Task.of(Schedulers.javafx(), () -> loadVersion(this.profile, this.versionId)))
.start(); .start();

View File

@ -36,7 +36,6 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.ListPage;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
@ -86,7 +85,7 @@ public final class ModListPage extends Control {
public void loadMods(ModManager modManager) { public void loadMods(ModManager modManager) {
this.modManager = modManager; this.modManager = modManager;
Task.ofResult("list", variables -> { Task.ofResult(() -> {
synchronized (ModListPage.this) { synchronized (ModListPage.this) {
JFXUtilities.runInFX(() -> loadingProperty().set(true)); JFXUtilities.runInFX(() -> loadingProperty().set(true));
modManager.refreshMods(); modManager.refreshMods();
@ -112,7 +111,7 @@ public final class ModListPage extends Control {
List<String> succeeded = new LinkedList<>(); List<String> succeeded = new LinkedList<>();
List<String> failed = new LinkedList<>(); List<String> failed = new LinkedList<>();
if (res == null) return; if (res == null) return;
Task.of(variables -> { Task.of(() -> {
for (File file : res) { for (File file : res) {
try { try {
modManager.addMod(file); modManager.addMod(file);
@ -124,7 +123,7 @@ public final class ModListPage extends Control {
// Actually addMod will not throw exceptions because FileChooser has already filtered files. // Actually addMod will not throw exceptions because FileChooser has already filtered files.
} }
} }
}).with(Task.of(Schedulers.javafx(), variables -> { }).with(Task.of(Schedulers.javafx(), () -> {
List<String> prompt = new LinkedList<>(); List<String> prompt = new LinkedList<>();
if (!succeeded.isEmpty()) if (!succeeded.isEmpty())
prompt.add(i18n("mods.add.success", String.join(", ", succeeded))); prompt.add(i18n("mods.add.success", String.join(", ", succeeded)));

View File

@ -57,7 +57,7 @@ import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.Optional;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -113,14 +113,13 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
FXUtils.smoothScrolling(scroll); FXUtils.smoothScrolling(scroll);
Task.ofResult(JavaVersion::getJavas).thenResult(Schedulers.javafx(), list -> { Task.ofResult(JavaVersion::getJavas).thenVoid(Schedulers.javafx(), list -> {
javaItem.loadChildren(list.stream() javaItem.loadChildren(list.stream()
.map(javaVersion -> javaItem.createChildren(javaVersion.getVersion() + i18n("settings.game.java_directory.bit", .map(javaVersion -> javaItem.createChildren(javaVersion.getVersion() + i18n("settings.game.java_directory.bit",
javaVersion.getPlatform().getBit()), javaVersion.getBinary().toString(), javaVersion)) javaVersion.getPlatform().getBit()), javaVersion.getBinary().toString(), javaVersion))
.collect(Collectors.toList())); .collect(Collectors.toList()));
javaItemsLoaded = true; javaItemsLoaded = true;
initializeSelectedJava(); initializeSelectedJava();
return null;
}).start(); }).start();
javaItem.setSelectedData(null); javaItem.setSelectedData(null);
@ -268,10 +267,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
} }
private void initJavaSubtitle(VersionSetting versionSetting) { private void initJavaSubtitle(VersionSetting versionSetting) {
Task.of(variables -> variables.set("java", versionSetting.getJavaVersion())) Task.ofResult(versionSetting::getJavaVersion)
.subscribe(Task.of(Schedulers.javafx(), .thenVoid(Schedulers.javafx(), javaVersion -> javaItem.setSubtitle(Optional.ofNullable(javaVersion)
variables -> javaItem.setSubtitle(variables.<JavaVersion>getOptional("java") .map(JavaVersion::getBinary).map(Path::toString).orElse("Invalid Java Directory")))
.map(JavaVersion::getBinary).map(Path::toString).orElse("Invalid Java Directory")))); .start();
} }
@FXML @FXML

View File

@ -28,7 +28,7 @@ import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.ParallelTask; import org.jackhuang.hmcl.task.ParallelTask;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.AutoTypingMap; import org.jackhuang.hmcl.task.TaskResult;
import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.function.ExceptionalFunction;
/** /**
@ -71,7 +71,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
@Override @Override
public Task checkGameCompletionAsync(Version version) { public Task checkGameCompletionAsync(Version version) {
return new ParallelTask( return new ParallelTask(
Task.ofThen(var -> { Task.ofThen(() -> {
if (!repository.getVersionJar(version).exists()) if (!repository.getVersionJar(version).exists())
return new GameDownloadTask(this, null, version); return new GameDownloadTask(this, null, version);
else else
@ -88,36 +88,32 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
} }
@Override @Override
public Task installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) { public TaskResult<Version> installLibraryAsync(String gameVersion, Version version, String libraryId, String libraryVersion) {
VersionList<?> versionList = getVersionList(libraryId); VersionList<?> versionList = getVersionList(libraryId);
return versionList.loadAsync(gameVersion, getDownloadProvider()) return versionList.loadAsync(gameVersion, getDownloadProvider())
.then(variables -> installLibraryAsync(version, versionList.getVersion(gameVersion, libraryVersion) .thenTaskResult(() -> installLibraryAsync(version, versionList.getVersion(gameVersion, libraryVersion)
.orElseThrow(() -> new IllegalStateException("Remote library " + libraryId + " has no version " + libraryVersion)))); .orElseThrow(() -> new IllegalStateException("Remote library " + libraryId + " has no version " + libraryVersion))));
} }
@Override @Override
public Task installLibraryAsync(Version version, RemoteVersion libraryVersion) { public TaskResult<Version> installLibraryAsync(Version oldVersion, RemoteVersion libraryVersion) {
TaskResult<Version> task;
if (libraryVersion instanceof ForgeRemoteVersion) if (libraryVersion instanceof ForgeRemoteVersion)
return new ForgeInstallTask(this, version, (ForgeRemoteVersion) libraryVersion) task = new ForgeInstallTask(this, oldVersion, (ForgeRemoteVersion) libraryVersion);
.then(variables -> new LibrariesUniqueTask(variables.get("version")))
.then(variables -> new MaintainTask(variables.get("version")))
.then(variables -> new VersionJsonSaveTask(repository, variables.get("version")));
else if (libraryVersion instanceof LiteLoaderRemoteVersion) else if (libraryVersion instanceof LiteLoaderRemoteVersion)
return new LiteLoaderInstallTask(this, version, (LiteLoaderRemoteVersion) libraryVersion) task = new LiteLoaderInstallTask(this, oldVersion, (LiteLoaderRemoteVersion) libraryVersion);
.then(variables -> new LibrariesUniqueTask(variables.get("version")))
.then(variables -> new MaintainTask(variables.get("version")))
.then(variables -> new VersionJsonSaveTask(repository, variables.get("version")));
else if (libraryVersion instanceof OptiFineRemoteVersion) else if (libraryVersion instanceof OptiFineRemoteVersion)
return new OptiFineInstallTask(this, version, (OptiFineRemoteVersion) libraryVersion) task = new OptiFineInstallTask(this, oldVersion, (OptiFineRemoteVersion) libraryVersion);
.then(variables -> new LibrariesUniqueTask(variables.get("version")))
.then(variables -> new MaintainTask(variables.get("version")))
.then(variables -> new VersionJsonSaveTask(repository, variables.get("version")));
else else
throw new IllegalArgumentException("Remote library " + libraryVersion + " is unrecognized."); throw new IllegalArgumentException("Remote library " + libraryVersion + " is unrecognized.");
return task
.thenTaskResult(LibrariesUniqueTask::new)
.thenTaskResult(MaintainTask::new)
.thenTaskResult(newVersion -> new VersionJsonSaveTask(repository, newVersion));
} }
public ExceptionalFunction<AutoTypingMap<String>, Task, ?> installLibraryAsync(RemoteVersion libraryVersion) { public ExceptionalFunction<Version, TaskResult<Version>, ?> installLibraryAsync(RemoteVersion libraryVersion) {
return var -> installLibraryAsync(var.get("version"), libraryVersion); return version -> installLibraryAsync(version, libraryVersion);
} }
} }

View File

@ -21,6 +21,7 @@ import org.jackhuang.hmcl.download.game.*;
import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.ParallelTask; import org.jackhuang.hmcl.task.ParallelTask;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.task.TaskResult;
import org.jackhuang.hmcl.util.AutoTypingMap; import org.jackhuang.hmcl.util.AutoTypingMap;
import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
@ -49,34 +50,35 @@ public class DefaultGameBuilder extends GameBuilder {
@Override @Override
public Task buildAsync() { public Task buildAsync() {
return new VersionJsonDownloadTask(gameVersion, dependencyManager).then(variables -> { return new VersionJsonDownloadTask(gameVersion, dependencyManager).thenTaskResult(rawJson -> {
Version version = JsonUtils.GSON.fromJson(variables.<String>get(VersionJsonDownloadTask.ID), Version.class); Version original = JsonUtils.GSON.fromJson(rawJson, Version.class);
version = version.setId(name).setJar(null); Version version = original.setId(name).setJar(null);
variables.set("version", version); Task vanillaTask = downloadGameAsync(gameVersion, version).then(new ParallelTask(
Task result = downloadGameAsync(gameVersion, version).then(new ParallelTask(
new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY), new GameAssetDownloadTask(dependencyManager, version, GameAssetDownloadTask.DOWNLOAD_INDEX_FORCIBLY),
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries. new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version))); // using [with] because download failure here are tolerant. ).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version))); // using [with] because download failure here are tolerant.
TaskResult<Version> libraryTask = vanillaTask.thenResult(() -> version);
if (toolVersions.containsKey("forge")) if (toolVersions.containsKey("forge"))
result = result.then(libraryTaskHelper(gameVersion, "forge")); libraryTask = libraryTask.thenTaskResult(libraryTaskHelper(gameVersion, "forge"));
if (toolVersions.containsKey("liteloader")) if (toolVersions.containsKey("liteloader"))
result = result.then(libraryTaskHelper(gameVersion, "liteloader")); libraryTask = libraryTask.thenTaskResult(libraryTaskHelper(gameVersion, "liteloader"));
if (toolVersions.containsKey("optifine")) if (toolVersions.containsKey("optifine"))
result = result.then(libraryTaskHelper(gameVersion, "optifine")); libraryTask = libraryTask.thenTaskResult(libraryTaskHelper(gameVersion, "optifine"));
for (RemoteVersion remoteVersion : remoteVersions) for (RemoteVersion remoteVersion : remoteVersions)
result = result.then(dependencyManager.installLibraryAsync(remoteVersion)); libraryTask = libraryTask.thenTaskResult(dependencyManager.installLibraryAsync(remoteVersion));
return result; return libraryTask;
}).finalized((isDependentsSucceeded, exception) -> { }).finalized((isDependentsSucceeded, exception) -> {
if (!isDependentsSucceeded) if (!isDependentsSucceeded)
dependencyManager.getGameRepository().getVersionRoot(name).delete(); dependencyManager.getGameRepository().getVersionRoot(name).delete();
}); });
} }
private ExceptionalFunction<AutoTypingMap<String>, Task, ?> libraryTaskHelper(String gameVersion, String libraryId) { private ExceptionalFunction<Version, TaskResult<Version>, ?> libraryTaskHelper(String gameVersion, String libraryId) {
return variables -> dependencyManager.installLibraryAsync(gameVersion, variables.get("version"), libraryId, toolVersions.get(libraryId)); return version -> dependencyManager.installLibraryAsync(gameVersion, version, libraryId, toolVersions.get(libraryId));
} }
protected Task downloadGameAsync(String gameVersion, Version version) { protected Task downloadGameAsync(String gameVersion, Version version) {

View File

@ -23,15 +23,9 @@ import org.jackhuang.hmcl.task.TaskResult;
public class MaintainTask extends TaskResult<Version> { public class MaintainTask extends TaskResult<Version> {
private final Version version; private final Version version;
private final String id;
public MaintainTask(Version version) { public MaintainTask(Version version) {
this(version, ID);
}
public MaintainTask(Version version, String id) {
this.version = version; this.version = version;
this.id = id;
} }
@Override @Override
@ -76,11 +70,4 @@ public class MaintainTask extends TaskResult<Version> {
return builder.build(); return builder.build();
} }
@Override
public String getId() {
return id;
}
public static final String ID = "version";
} }

View File

@ -74,7 +74,7 @@ public abstract class VersionList<T extends RemoteVersion> {
} }
public Task loadAsync(DownloadProvider downloadProvider) { public Task loadAsync(DownloadProvider downloadProvider) {
return Task.ofThen(variables -> { return Task.ofThen(() -> {
lock.readLock().lock(); lock.readLock().lock();
boolean loaded; boolean loaded;
@ -88,7 +88,7 @@ public abstract class VersionList<T extends RemoteVersion> {
} }
public Task loadAsync(String gameVersion, DownloadProvider downloadProvider) { public Task loadAsync(String gameVersion, DownloadProvider downloadProvider) {
return Task.ofThen(variables -> { return Task.ofThen(() -> {
lock.readLock().lock(); lock.readLock().lock();
boolean loaded; boolean loaded;

View File

@ -82,11 +82,6 @@ public final class ForgeInstallTask extends TaskResult<Version> {
return Collections.singleton(dependency); return Collections.singleton(dependency);
} }
@Override
public String getId() {
return "version";
}
@Override @Override
public boolean isRelyingOnDependencies() { public boolean isRelyingOnDependencies() {
return false; return false;

View File

@ -89,11 +89,6 @@ public class ForgeNewInstallTask extends TaskResult<Version> {
return dependencies; return dependencies;
} }
@Override
public String getId() {
return "version";
}
@Override @Override
public boolean doPreExecute() { public boolean doPreExecute() {
return true; return true;

View File

@ -49,11 +49,6 @@ public class ForgeOldInstallTask extends TaskResult<Version> {
return dependencies; return dependencies;
} }
@Override
public String getId() {
return "version";
}
@Override @Override
public boolean doPreExecute() { public boolean doPreExecute() {
return true; return true;

View File

@ -33,15 +33,9 @@ import java.util.stream.Collectors;
public class LibrariesUniqueTask extends TaskResult<Version> { public class LibrariesUniqueTask extends TaskResult<Version> {
private final Version version; private final Version version;
private final String id;
public LibrariesUniqueTask(Version version) { public LibrariesUniqueTask(Version version) {
this(version, "version");
}
public LibrariesUniqueTask(Version version, String id) {
this.version = version; this.version = version;
this.id = id;
} }
@Override @Override
@ -99,9 +93,4 @@ public class LibrariesUniqueTask extends TaskResult<Version> {
setResult(version.setLibraries(multimap.values().stream().sorted().collect(Collectors.toList()))); setResult(version.setLibraries(multimap.values().stream().sorted().collect(Collectors.toList())));
} }
@Override
public String getId() {
return id;
}
} }

View File

@ -22,6 +22,7 @@ import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.download.VersionList;
import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.GetTask;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.task.TaskResult;
import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.util.Collection; import java.util.Collection;
@ -32,7 +33,7 @@ import java.util.List;
* *
* @author huangyuhui * @author huangyuhui
*/ */
public final class VersionJsonDownloadTask extends Task { public final class VersionJsonDownloadTask extends TaskResult<String> {
private final String gameVersion; private final String gameVersion;
private final DefaultDependencyManager dependencyManager; private final DefaultDependencyManager dependencyManager;
private final List<Task> dependents = new LinkedList<>(); private final List<Task> dependents = new LinkedList<>();
@ -65,8 +66,6 @@ public final class VersionJsonDownloadTask extends Task {
RemoteVersion remoteVersion = gameVersionList.getVersions(gameVersion).stream().findFirst() RemoteVersion remoteVersion = gameVersionList.getVersions(gameVersion).stream().findFirst()
.orElseThrow(() -> new IllegalStateException("Cannot find specific version " + gameVersion + " in remote repository")); .orElseThrow(() -> new IllegalStateException("Cannot find specific version " + gameVersion + " in remote repository"));
String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl()); String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl());
dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL), ID)); dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL)).storeTo(this::setResult));
} }
public static final String ID = "raw_version_json";
} }

View File

@ -19,7 +19,7 @@ package org.jackhuang.hmcl.download.game;
import org.jackhuang.hmcl.game.DefaultGameRepository; import org.jackhuang.hmcl.game.DefaultGameRepository;
import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskResult;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
@ -31,7 +31,7 @@ import java.io.IOException;
* *
* @author huangyuhui * @author huangyuhui
*/ */
public final class VersionJsonSaveTask extends Task { public final class VersionJsonSaveTask extends TaskResult<Version> {
private final DefaultGameRepository repository; private final DefaultGameRepository repository;
private final Version version; private final Version version;
@ -47,6 +47,7 @@ public final class VersionJsonSaveTask extends Task {
this.version = version; this.version = version;
setSignificance(TaskSignificance.MODERATE); setSignificance(TaskSignificance.MODERATE);
setResult(version);
} }
@Override @Override

View File

@ -18,7 +18,6 @@
package org.jackhuang.hmcl.download.liteloader; package org.jackhuang.hmcl.download.liteloader;
import org.jackhuang.hmcl.download.DefaultDependencyManager; import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.game.GameLibrariesTask;
import org.jackhuang.hmcl.game.LibrariesDownloadInfo; import org.jackhuang.hmcl.game.LibrariesDownloadInfo;
import org.jackhuang.hmcl.game.Library; import org.jackhuang.hmcl.game.Library;
import org.jackhuang.hmcl.game.LibraryDownloadInfo; import org.jackhuang.hmcl.game.LibraryDownloadInfo;
@ -61,11 +60,6 @@ public final class LiteLoaderInstallTask extends TaskResult<Version> {
return dependencies; return dependencies;
} }
@Override
public String getId() {
return "version";
}
@Override @Override
public void execute() { public void execute() {
Library library = new Library( Library library = new Library(

View File

@ -59,11 +59,6 @@ public final class OptiFineInstallTask extends TaskResult<Version> {
return dependencies; return dependencies;
} }
@Override
public String getId() {
return "version";
}
@Override @Override
public boolean isRelyingOnDependencies() { public boolean isRelyingOnDependencies() {
return false; return false;

View File

@ -156,7 +156,7 @@ public final class MultiMCModpackInstallTask extends Task {
} }
} }
dependencies.add(new MaintainTask(version).then(var -> new VersionJsonSaveTask(repository, var.get(MaintainTask.ID)))); dependencies.add(new MaintainTask(version).thenTaskResult(maintainedVersion -> new VersionJsonSaveTask(repository, maintainedVersion)));
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)));
} }

View File

@ -18,57 +18,53 @@
package org.jackhuang.hmcl.task; package org.jackhuang.hmcl.task;
import org.jackhuang.hmcl.util.AutoTypingMap; import org.jackhuang.hmcl.util.AutoTypingMap;
import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/** /**
* A task that combines two tasks and make sure [pred] runs before succ. * A task that combines two tasks and make sure [pred] runs before succ.
* *
* @author huangyuhui * @author huangyuhui
*/ */
final class CoupleTask<P extends Task> extends Task { final class CoupleTask extends Task {
private final boolean relyingOnDependents; private final boolean relyingOnDependents;
private final Collection<Task> dependents; private final Task pred;
private final List<Task> dependencies = new LinkedList<>(); private Task succ;
private final ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ; private final ExceptionalSupplier<Task, ?> supplier;
/** /**
* A task that combines two tasks and make sure pred runs before succ. * A task that combines two tasks and make sure pred runs before succ.
* *
* @param pred the task that runs before succ. * @param pred the task that runs before supplier.
* @param succ a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. * @param supplier a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
* @param relyingOnDependents true if this task chain will be broken when task pred fails. * @param relyingOnDependents true if this task chain will be broken when task pred fails.
*/ */
public CoupleTask(P pred, ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ, boolean relyingOnDependents) { CoupleTask(Task pred, ExceptionalSupplier<Task, ?> supplier, boolean relyingOnDependents) {
this.dependents = pred == null ? Collections.emptySet() : Collections.singleton(pred); this.pred = pred;
this.succ = succ; this.supplier = supplier;
this.relyingOnDependents = relyingOnDependents; this.relyingOnDependents = relyingOnDependents;
setSignificance(TaskSignificance.MODERATE); setSignificance(TaskSignificance.MODERATE);
setName(succ.toString()); setName(supplier.toString());
} }
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
setName(succ.toString()); setName(supplier.toString());
Task task = succ.apply(getVariables()); succ = supplier.get();
if (task != null)
dependencies.add(task);
} }
@Override @Override
public Collection<Task> getDependents() { public Collection<Task> getDependents() {
return dependents; return pred == null ? Collections.emptySet() : Collections.singleton(pred);
} }
@Override @Override
public Collection<Task> getDependencies() { public Collection<Task> getDependencies() {
return dependencies; return succ == null ? Collections.emptySet() : Collections.singleton(succ);
} }
@Override @Override

View File

@ -37,13 +37,12 @@ final class FinalizedTask extends Task {
* @param pred the task that runs before succ. * @param pred the task that runs before succ.
* @param callback a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred. * @param callback a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
*/ */
public FinalizedTask(Task pred, Scheduler scheduler, FinalizedCallback callback, String name) { public FinalizedTask(Task pred, Scheduler scheduler, FinalizedCallback callback) {
this.pred = pred; this.pred = pred;
this.scheduler = scheduler; this.scheduler = scheduler;
this.callback = callback; this.callback = callback;
setSignificance(TaskSignificance.MODERATE); setSignificance(TaskSignificance.MODERATE);
setName(name);
} }
@Override @Override

View File

@ -72,11 +72,6 @@ public final class GetTask extends TaskResult<String> {
return Schedulers.io(); return Schedulers.io();
} }
@Override
public String getId() {
return id;
}
public GetTask setCacheRepository(CacheRepository repository) { public GetTask setCacheRepository(CacheRepository repository) {
this.repository = repository; this.repository = repository;
return this; return this;

View File

@ -17,8 +17,7 @@
*/ */
package org.jackhuang.hmcl.task; package org.jackhuang.hmcl.task;
import org.jackhuang.hmcl.util.AutoTypingMap; import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
/** /**
* *
@ -26,16 +25,16 @@ import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
*/ */
class SimpleTask extends Task { class SimpleTask extends Task {
private final ExceptionalConsumer<AutoTypingMap<String>, ?> consumer; private final ExceptionalRunnable<?> closure;
private final Scheduler scheduler; private final Scheduler scheduler;
public SimpleTask(String name, ExceptionalConsumer<AutoTypingMap<String>, ?> consumer, Scheduler scheduler) { public SimpleTask(String name, ExceptionalRunnable<?> closure, Scheduler scheduler) {
this.consumer = consumer; this.closure = closure;
this.scheduler = scheduler; this.scheduler = scheduler;
if (name == null) { if (name == null) {
setSignificance(TaskSignificance.MINOR); setSignificance(TaskSignificance.MINOR);
setName(consumer.toString()); setName(closure.toString());
} else { } else {
setName(name); setName(name);
} }
@ -48,6 +47,6 @@ class SimpleTask extends Task {
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
consumer.accept(getVariables()); closure.run();
} }
} }

View File

@ -17,24 +17,30 @@
*/ */
package org.jackhuang.hmcl.task; package org.jackhuang.hmcl.task;
import org.jackhuang.hmcl.util.AutoTypingMap;
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import org.jackhuang.hmcl.util.function.ExceptionalSupplier; import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
public final class SimpleTaskResult<V> extends TaskResult<V> { import java.util.concurrent.Callable;
private final String id;
private final ExceptionalSupplier<V, ?> supplier;
public SimpleTaskResult(String id, ExceptionalSupplier<V, ?> supplier) { /**
this.id = id; *
this.supplier = supplier; * @author huangyuhui
*/
class SimpleTaskResult<V> extends TaskResult<V> {
private final Callable<V> callable;
public SimpleTaskResult(Callable<V> callable) {
this.callable = callable;
}
public SimpleTaskResult(ExceptionalSupplier<V, ?> supplier) {
this.callable = supplier.toCallable();
} }
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
setResult(supplier.get()); setResult(callable.call());
}
@Override
public String getId() {
return id;
} }
} }

View File

@ -23,13 +23,12 @@ import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper; import javafx.beans.property.ReadOnlyStringWrapper;
import org.jackhuang.hmcl.event.EventManager; import org.jackhuang.hmcl.event.EventManager;
import org.jackhuang.hmcl.util.AutoTypingMap;
import org.jackhuang.hmcl.util.InvocationDispatcher; import org.jackhuang.hmcl.util.InvocationDispatcher;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.ReflectionHelper; import org.jackhuang.hmcl.util.ReflectionHelper;
import org.jackhuang.hmcl.util.function.ExceptionalConsumer; import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import org.jackhuang.hmcl.util.function.ExceptionalRunnable; import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -134,16 +133,6 @@ public abstract class Task {
return this; return this;
} }
private AutoTypingMap<String> variables = null;
public AutoTypingMap<String> getVariables() {
return variables;
}
void setVariables(AutoTypingMap<String> variables) {
this.variables = variables;
}
public boolean doPreExecute() { public boolean doPreExecute() {
return false; return false;
} }
@ -280,16 +269,8 @@ public abstract class Task {
new TaskExecutor(then(subscriber)).start(); new TaskExecutor(then(subscriber)).start();
} }
public final void subscribe(Scheduler scheduler, ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
subscribe(of(scheduler, closure));
}
public final void subscribe(Scheduler scheduler, ExceptionalRunnable<?> closure) { public final void subscribe(Scheduler scheduler, ExceptionalRunnable<?> closure) {
subscribe(of(scheduler, ExceptionalConsumer.fromRunnable(closure))); subscribe(of(scheduler, closure));
}
public final void subscribe(ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
subscribe(of(closure));
} }
public final void subscribe(ExceptionalRunnable<?> closure) { public final void subscribe(ExceptionalRunnable<?> closure) {
@ -300,16 +281,36 @@ public abstract class Task {
return then(convert(b)); return then(convert(b));
} }
public final Task then(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) { public final Task then(ExceptionalSupplier<Task, ?> b) {
return new CoupleTask<>(this, b, true); return new CoupleTask(this, b, true);
}
public final <R> TaskResult<R> thenResult(Callable<R> supplier) {
return thenTaskResult(() -> Task.ofResult(supplier));
}
public final <R> TaskResult<R> thenTaskResult(ExceptionalSupplier<TaskResult<R>, ?> taskSupplier) {
return new TaskResult<R>() {
TaskResult<R> then;
@Override
public void execute() throws Exception {
then = taskSupplier.get().storeTo(this::setResult);
}
@Override
public Collection<? extends Task> getDependencies() {
return then == null ? Collections.emptyList() : Collections.singleton(then);
}
};
} }
public final Task with(Task b) { public final Task with(Task b) {
return with(convert(b)); return with(convert(b));
} }
public final <E extends Exception> Task with(ExceptionalFunction<AutoTypingMap<String>, Task, E> b) { public final <E extends Exception> Task with(ExceptionalSupplier<Task, E> b) {
return new CoupleTask<>(this, b, false); return new CoupleTask(this, b, false);
} }
public final Task finalized(FinalizedCallback b) { public final Task finalized(FinalizedCallback b) {
@ -317,7 +318,7 @@ public abstract class Task {
} }
public final Task finalized(Scheduler scheduler, FinalizedCallback b) { public final Task finalized(Scheduler scheduler, FinalizedCallback b) {
return new FinalizedTask(this, scheduler, b, ReflectionHelper.getCaller().toString()); return new FinalizedTask(this, scheduler, b).setName(getCaller());
} }
// T, K here is necessary, or javac cannot infer type of failure // T, K here is necessary, or javac cannot infer type of failure
@ -339,58 +340,38 @@ public abstract class Task {
}); });
} }
public static Task of(String name, ExceptionalRunnable<?> runnable) { public static Task of(ExceptionalRunnable<?> closure) {
return of(name, ExceptionalConsumer.fromRunnable(runnable));
}
public static Task of(ExceptionalRunnable<?> runnable) {
return of(ExceptionalConsumer.fromRunnable(runnable));
}
public static Task of(String name, ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
return of(name, Schedulers.defaultScheduler(), closure);
}
public static Task of(ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
return of(Schedulers.defaultScheduler(), closure); return of(Schedulers.defaultScheduler(), closure);
} }
public static Task of(String name, Scheduler scheduler, ExceptionalConsumer<AutoTypingMap<String>, ?> closure) { public static Task of(String name, ExceptionalRunnable<?> closure) {
return new SimpleTask(name, closure, scheduler); return of(name, Schedulers.defaultScheduler(), closure);
}
public static Task of(Scheduler scheduler, ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
return of(ReflectionHelper.getCaller().toString(), scheduler, closure);
}
public static Task of(String name, Scheduler scheduler, ExceptionalRunnable<?> closure) {
return new SimpleTask(name, ExceptionalConsumer.fromRunnable(closure), scheduler);
} }
public static Task of(Scheduler scheduler, ExceptionalRunnable<?> closure) { public static Task of(Scheduler scheduler, ExceptionalRunnable<?> closure) {
return of(ReflectionHelper.getCaller().toString(), scheduler, closure); return of(getCaller(), scheduler, closure);
} }
public static Task ofThen(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) { public static Task of(String name, Scheduler scheduler, ExceptionalRunnable<?> closure) {
return new CoupleTask<>(null, b, true); return new SimpleTask(name, closure, scheduler);
}
public static Task ofThen(ExceptionalSupplier<Task, ?> b) {
return new CoupleTask(null, b, true);
} }
public static <V> TaskResult<V> ofResult(Callable<V> callable) { public static <V> TaskResult<V> ofResult(Callable<V> callable) {
return ofResult("", callable); return ofResult(getCaller(), callable);
} }
public static <V> TaskResult<V> ofResult(String id, Callable<V> callable) { public static <V> TaskResult<V> ofResult(String name, Callable<V> callable) {
return new TaskCallable<>(id, callable); return new SimpleTaskResult<>(callable).setName(name);
} }
public static <V> TaskResult<V> ofResult(String id, ExceptionalFunction<AutoTypingMap<String>, V, ?> closure) { private static ExceptionalSupplier<Task, ?> convert(Task t) {
return new TaskCallable<>(id, closure); return new ExceptionalSupplier<Task, Exception>() {
}
private static ExceptionalFunction<AutoTypingMap<String>, Task, ?> convert(Task t) {
return new ExceptionalFunction<AutoTypingMap<String>, Task, Exception>() {
@Override @Override
public Task apply(AutoTypingMap<String> autoTypingMap) { public Task get() {
return t; return t;
} }
@ -426,4 +407,8 @@ public abstract class Task {
public interface FinalizedCallback { public interface FinalizedCallback {
void execute(boolean isDependentsSucceeded, Exception exception) throws Exception; void execute(boolean isDependentsSucceeded, Exception exception) throws Exception;
} }
static String getCaller() {
return ReflectionHelper.getCaller(packageName -> !"org.jackhuang.hmcl.task".equals(packageName)).toString();
}
} }

View File

@ -1,52 +0,0 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2019 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.task;
import org.jackhuang.hmcl.util.AutoTypingMap;
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import java.util.concurrent.Callable;
/**
*
* @author huangyuhui
*/
class TaskCallable<V> extends TaskResult<V> {
private final String id;
private final ExceptionalFunction<AutoTypingMap<String>, V, ?> callable;
public TaskCallable(String id, Callable<V> callable) {
this(id, variables -> callable.call());
}
public TaskCallable(String id, ExceptionalFunction<AutoTypingMap<String>, V, ?> callable) {
this.id = id;
this.callable = callable;
}
@Override
public String getId() {
return id;
}
@Override
public void execute() throws Exception {
setResult(callable.apply(getVariables()));
}
}

View File

@ -38,7 +38,6 @@ public final class TaskExecutor {
private Exception lastException; private Exception lastException;
private final AtomicInteger totTask = new AtomicInteger(0); private final AtomicInteger totTask = new AtomicInteger(0);
private final ConcurrentLinkedQueue<Future<?>> workerQueue = new ConcurrentLinkedQueue<>(); private final ConcurrentLinkedQueue<Future<?>> workerQueue = new ConcurrentLinkedQueue<>();
private final AutoTypingMap<String> variables = new AutoTypingMap<>(new HashMap<>());
private Scheduler scheduler = Schedulers.newThread(); private Scheduler scheduler = Schedulers.newThread();
public TaskExecutor(Task task) { public TaskExecutor(Task task) {
@ -147,8 +146,6 @@ public final class TaskExecutor {
boolean flag = false; boolean flag = false;
try { try {
task.setVariables(variables);
if (task.doPreExecute()) { if (task.doPreExecute()) {
try { try {
task.getScheduler().schedule(task::preExecute).get(); task.getScheduler().schedule(task::preExecute).get();
@ -186,11 +183,6 @@ public final class TaskExecutor {
task.setState(Task.TaskState.EXECUTED); task.setState(Task.TaskState.EXECUTED);
} }
if (task instanceof TaskResult<?>) {
TaskResult<?> taskResult = (TaskResult<?>) task;
variables.set(taskResult.getId(), taskResult.getResult());
}
Collection<? extends Task> dependencies = task.getDependencies(); Collection<? extends Task> dependencies = task.getDependencies();
boolean doDependenciesSucceeded = executeTasks(dependencies); boolean doDependenciesSucceeded = executeTasks(dependencies);
Exception dependenciesException = dependencies.stream().map(Task::getLastException).filter(Objects::nonNull).findAny().orElse(null); Exception dependenciesException = dependencies.stream().map(Task::getLastException).filter(Objects::nonNull).findAny().orElse(null);
@ -238,8 +230,6 @@ public final class TaskExecutor {
} }
task.onDone().fireEvent(new TaskEvent(this, task, true)); task.onDone().fireEvent(new TaskEvent(this, task, true));
taskListeners.forEach(it -> it.onFailed(task, e)); taskListeners.forEach(it -> it.onFailed(task, e));
} finally {
task.setVariables(null);
} }
task.setState(flag ? Task.TaskState.SUCCEEDED : Task.TaskState.FAILED); task.setState(flag ? Task.TaskState.SUCCEEDED : Task.TaskState.FAILED);
return flag; return flag;
@ -249,10 +239,6 @@ public final class TaskExecutor {
return totTask.get(); return totTask.get();
} }
public AutoTypingMap<String> getVariables() {
return variables;
}
private class Invoker implements ExceptionalRunnable<Exception> { private class Invoker implements ExceptionalRunnable<Exception> {
private final Task task; private final Task task;

View File

@ -17,12 +17,12 @@
*/ */
package org.jackhuang.hmcl.task; package org.jackhuang.hmcl.task;
import org.jackhuang.hmcl.util.ReflectionHelper;
import org.jackhuang.hmcl.util.function.ExceptionalConsumer; import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
import org.jackhuang.hmcl.util.function.ExceptionalFunction; import org.jackhuang.hmcl.util.function.ExceptionalFunction;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.function.Consumer;
/** /**
* A task that has a result. * A task that has a result.
@ -32,6 +32,13 @@ import java.util.Collections;
public abstract class TaskResult<V> extends Task { public abstract class TaskResult<V> extends Task {
private V result; private V result;
private Consumer<V> resultConsumer;
@Override
public TaskResult<V> setName(String name) {
super.setName(name);
return this;
}
public V getResult() { public V getResult() {
return result; return result;
@ -39,20 +46,59 @@ public abstract class TaskResult<V> extends Task {
public void setResult(V result) { public void setResult(V result) {
this.result = result; this.result = result;
if (resultConsumer != null)
resultConsumer.accept(result);
} }
public abstract String getId(); public TaskResult<V> storeTo(Consumer<V> resultConsumer) {
this.resultConsumer = resultConsumer;
return this;
}
public <R, E extends Exception> TaskResult<R> thenTaskResult(ExceptionalFunction<V, TaskResult<R>, E> taskSupplier) {
return new TaskResult<R>() {
TaskResult<R> then;
@Override
public Collection<? extends Task> getDependents() {
return Collections.singleton(TaskResult.this);
}
@Override
public void execute() throws Exception {
then = taskSupplier.apply(TaskResult.this.getResult()).storeTo(this::setResult);
}
@Override
public Collection<? extends Task> getDependencies() {
return then == null ? Collections.emptyList() : Collections.singleton(then);
}
};
}
public <R, E extends Exception> Task then(ExceptionalFunction<V, Task, E> taskSupplier) {
return new CoupleTask(this, () -> taskSupplier.apply(getResult()), true);
}
public <R, E extends Exception> TaskResult<R> thenResult(ExceptionalFunction<V, R, E> task) { public <R, E extends Exception> TaskResult<R> thenResult(ExceptionalFunction<V, R, E> task) {
return thenResult(Schedulers.defaultScheduler(), task); return thenResult(Schedulers.defaultScheduler(), task);
} }
public <R, E extends Exception> TaskResult<R> thenResult(Scheduler scheduler, ExceptionalFunction<V, R, E> task) { public <R, E extends Exception> TaskResult<R> thenResult(Scheduler scheduler, ExceptionalFunction<V, R, E> task) {
return thenResult(ReflectionHelper.getCaller().toString(), scheduler, task); return thenResult(getCaller(), scheduler, task);
} }
public <R, E extends Exception> TaskResult<R> thenResult(String id, Scheduler scheduler, ExceptionalFunction<V, R, E> task) { public <R, E extends Exception> TaskResult<R> thenResult(String name, Scheduler scheduler, ExceptionalFunction<V, R, E> task) {
return new Subtask<>(id, scheduler, task); return new Subtask<>(name, scheduler, task);
}
// stupid javac stop us from renaming thenVoid to thenResult
public <E extends Exception> Task thenVoid(ExceptionalConsumer<V, E> task) {
return thenVoid(Schedulers.defaultScheduler(), task);
}
public <E extends Exception> Task thenVoid(Scheduler scheduler, ExceptionalConsumer<V, E> task) {
return new CoupleTask(this, () -> Task.of(scheduler, () -> task.accept(getResult())), true);
} }
public <T extends Exception, K extends Exception> Task finalized(Scheduler scheduler, ExceptionalConsumer<V, T> success, ExceptionalConsumer<Exception, K> failure) { public <T extends Exception, K extends Exception> Task finalized(Scheduler scheduler, ExceptionalConsumer<V, T> success, ExceptionalConsumer<Exception, K> failure) {
@ -64,14 +110,14 @@ public abstract class TaskResult<V> extends Task {
} }
private class Subtask<R> extends TaskResult<R> { private class Subtask<R> extends TaskResult<R> {
private final String id;
private final Scheduler scheduler; private final Scheduler scheduler;
private final ExceptionalFunction<V, R, ?> callable; private final ExceptionalFunction<V, R, ?> callable;
public Subtask(String id, Scheduler scheduler, ExceptionalFunction<V, R, ?> callable) { public Subtask(String name, Scheduler scheduler, ExceptionalFunction<V, R, ?> callable) {
this.id = id;
this.scheduler = scheduler; this.scheduler = scheduler;
this.callable = callable; this.callable = callable;
setName(name);
} }
@Override @Override
@ -79,11 +125,6 @@ public abstract class TaskResult<V> extends Task {
return Collections.singleton(TaskResult.this); return Collections.singleton(TaskResult.this);
} }
@Override
public String getId() {
return id;
}
@Override @Override
public Scheduler getScheduler() { public Scheduler getScheduler() {
return scheduler; return scheduler;

View File

@ -17,17 +17,28 @@
*/ */
package org.jackhuang.hmcl.util; package org.jackhuang.hmcl.util;
import java.util.function.Predicate;
/** /**
* *
* @author huangyuhui * @author huangyuhui
*/ */
public final class ReflectionHelper { public final class ReflectionHelper {
public static StackTraceElement getCaller() { /**
* Get caller, this method is caller sensitive.
* @param packageFilter returns false if we consider the given package is internal calls, not the caller
* @return the caller, method name, source file, line number
*/
public static StackTraceElement getCaller(Predicate<String> packageFilter) {
StackTraceElement[] elements = Thread.currentThread().getStackTrace(); StackTraceElement[] elements = Thread.currentThread().getStackTrace();
// element[0] is Thread.currentThread().getStackTrace()
// element[1] is ReflectionHelper.getCaller(packageFilter)
// so element[2] is caller of this method.
StackTraceElement caller = elements[2]; StackTraceElement caller = elements[2];
for (int i = 3; i < elements.length; ++i) { for (int i = 3; i < elements.length; ++i) {
if (!caller.getClassName().equals(elements[i].getClassName())) if (packageFilter.test(StringUtils.substringBeforeLast(elements[i].getClassName(), '.')) &&
!caller.getClassName().equals(elements[i].getClassName()))
return elements[i]; return elements[i];
} }
return caller; return caller;