make launch script
This commit is contained in:
@@ -23,6 +23,7 @@ import org.jackhuang.hmcl.task.ParallelTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.ExceptionalFunction;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -63,7 +64,7 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
private Function<AutoTypingMap<String>, Task> libraryTaskHelper(String gameVersion, String libraryId) {
|
||||
private ExceptionalFunction<AutoTypingMap<String>, Task, ?> libraryTaskHelper(String gameVersion, String libraryId) {
|
||||
return variables -> dependencyManager.installLibraryAsync(gameVersion, variables.get("version"), libraryId, toolVersions.get(libraryId));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public final class GameAssetIndexDownloadTask extends Task {
|
||||
public GameAssetIndexDownloadTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,6 +39,8 @@ public final class GameDownloadTask extends Task {
|
||||
public GameDownloadTask(DefaultDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -49,6 +49,7 @@ public final class GameLibrariesTask extends Task {
|
||||
public GameLibrariesTask(AbstractDependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -50,6 +50,7 @@ public final class GameLoggingDownloadTask extends Task {
|
||||
public GameLoggingDownloadTask(DependencyManager dependencyManager, Version version) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
this.version = version;
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,6 +47,8 @@ public final class VersionJsonDownloadTask extends Task {
|
||||
|
||||
if (!gameVersionList.isLoaded())
|
||||
dependents.add(gameVersionList.refreshAsync(dependencyManager.getDownloadProvider()));
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,6 +45,8 @@ public final class VersionJsonSaveTask extends Task {
|
||||
public VersionJsonSaveTask(DefaultGameRepository repository, Version version) {
|
||||
this.repository = repository;
|
||||
this.version = version;
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.util.ExceptionalFunction;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -35,7 +36,7 @@ final class CoupleTask<P extends Task> extends Task {
|
||||
private final boolean relyingOnDependents;
|
||||
private final Collection<Task> dependents;
|
||||
private final List<Task> dependencies = new LinkedList<>();
|
||||
private final Function<AutoTypingMap<String>, Task> succ;
|
||||
private final ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ;
|
||||
|
||||
/**
|
||||
* A task that combines two tasks and make sure pred runs before succ.
|
||||
@@ -44,24 +45,21 @@ final class CoupleTask<P extends Task> extends Task {
|
||||
* @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 relyingOnDependents true if this task chain will be broken when task pred fails.
|
||||
*/
|
||||
public CoupleTask(P pred, Function<AutoTypingMap<String>, Task> succ, boolean relyingOnDependents) {
|
||||
public CoupleTask(P pred, ExceptionalFunction<AutoTypingMap<String>, Task, ?> succ, boolean relyingOnDependents) {
|
||||
this.dependents = Collections.singleton(pred);
|
||||
this.succ = succ;
|
||||
this.relyingOnDependents = relyingOnDependents;
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
public void execute() throws Exception {
|
||||
Task task = succ.apply(getVariables());
|
||||
if (task != null)
|
||||
dependencies.add(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
|
||||
@@ -88,6 +88,8 @@ public class FileDownloadTask extends Task {
|
||||
this.hash = hash;
|
||||
this.retry = retry;
|
||||
this.proxy = proxy;
|
||||
|
||||
setName(file.getName());
|
||||
}
|
||||
|
||||
private void closeFiles() {
|
||||
@@ -101,6 +103,10 @@ public class FileDownloadTask extends Task {
|
||||
return onFailed;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
URL currentURL = url;
|
||||
|
||||
@@ -65,6 +65,8 @@ public final class GetTask extends TaskResult<String> {
|
||||
this.retry = retry;
|
||||
this.proxy = proxy;
|
||||
this.id = id;
|
||||
|
||||
setName(url.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,17 +37,13 @@ public final class ParallelTask extends Task {
|
||||
*/
|
||||
public ParallelTask(Task... tasks) {
|
||||
this.tasks = tasks;
|
||||
setSignificance(TaskSignificance.MINOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return Arrays.asList(tasks);
|
||||
|
||||
@@ -22,10 +22,7 @@ import javafx.beans.property.ReadOnlyDoubleWrapper;
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||
import org.jackhuang.hmcl.event.EventManager;
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.util.ExceptionalConsumer;
|
||||
import org.jackhuang.hmcl.util.ExceptionalRunnable;
|
||||
import org.jackhuang.hmcl.util.Properties;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -42,11 +39,17 @@ public abstract class Task {
|
||||
|
||||
private final EventManager<TaskEvent> onDone = new EventManager<>();
|
||||
|
||||
private TaskSignificance significance = TaskSignificance.MAJOR;
|
||||
|
||||
/**
|
||||
* True if not logging when executing this task.
|
||||
*/
|
||||
public boolean isHidden() {
|
||||
return false;
|
||||
public final TaskSignificance getSignificance() {
|
||||
return significance;
|
||||
}
|
||||
|
||||
public void setSignificance(TaskSignificance significance) {
|
||||
this.significance = significance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,10 +142,10 @@ public abstract class Task {
|
||||
}
|
||||
|
||||
protected void updateProgress(double progress) {
|
||||
if (progress > 1.0)
|
||||
if (progress < 0 || progress > 1.0)
|
||||
throw new IllegalArgumentException("Progress is must between 0 and 1.");
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastTime >= getProgressInterval()) {
|
||||
if (lastTime == Long.MIN_VALUE || now - lastTime >= getProgressInterval()) {
|
||||
updateProgressImmediately(progress);
|
||||
lastTime = now;
|
||||
}
|
||||
@@ -186,7 +189,7 @@ public abstract class Task {
|
||||
|
||||
public final TaskExecutor executor(Function<TaskExecutor, TaskListener> taskListener) {
|
||||
TaskExecutor executor = new TaskExecutor(this);
|
||||
executor.setTaskListener(taskListener.apply(executor));
|
||||
executor.addTaskListener(taskListener.apply(executor));
|
||||
return executor;
|
||||
}
|
||||
|
||||
@@ -224,7 +227,7 @@ public abstract class Task {
|
||||
return then(s -> b);
|
||||
}
|
||||
|
||||
public final Task then(Function<AutoTypingMap<String>, Task> b) {
|
||||
public final Task then(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
|
||||
return new CoupleTask<>(this, b, true);
|
||||
}
|
||||
|
||||
@@ -232,7 +235,7 @@ public abstract class Task {
|
||||
return with(s -> b);
|
||||
}
|
||||
|
||||
public final Task with(Function<AutoTypingMap<String>, Task> b) {
|
||||
public final Task with(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
|
||||
return new CoupleTask<>(this, b, false);
|
||||
}
|
||||
|
||||
@@ -264,4 +267,18 @@ public abstract class Task {
|
||||
public static <V> TaskResult<V> ofResult(String id, Function<AutoTypingMap<String>, V> closure) {
|
||||
return new TaskCallable2<>(id, closure);
|
||||
}
|
||||
|
||||
public enum TaskSignificance {
|
||||
MAJOR,
|
||||
MODERATE,
|
||||
MINOR;
|
||||
|
||||
public boolean shouldLog() {
|
||||
return this != MINOR;
|
||||
}
|
||||
|
||||
public boolean shouldShow() {
|
||||
return this == MAJOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,11 @@ import org.jackhuang.hmcl.util.ExceptionalRunnable;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
@@ -40,7 +38,7 @@ import java.util.logging.Level;
|
||||
public final class TaskExecutor {
|
||||
|
||||
private final Task firstTask;
|
||||
private TaskListener taskListener = TaskListener.DefaultTaskListener.INSTANCE;
|
||||
private List<TaskListener> taskListeners = new LinkedList<>();
|
||||
private boolean canceled = false;
|
||||
private Exception lastException;
|
||||
private final AtomicInteger totTask = new AtomicInteger(0);
|
||||
@@ -52,15 +50,8 @@ public final class TaskExecutor {
|
||||
this.firstTask = task;
|
||||
}
|
||||
|
||||
public TaskListener getTaskListener() {
|
||||
return taskListener;
|
||||
}
|
||||
|
||||
public void setTaskListener(TaskListener taskListener) {
|
||||
if (taskListener == null)
|
||||
this.taskListener = TaskListener.DefaultTaskListener.INSTANCE;
|
||||
else
|
||||
this.taskListener = taskListener;
|
||||
public void addTaskListener(TaskListener taskListener) {
|
||||
taskListeners.add(taskListener);
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
@@ -78,7 +69,10 @@ public final class TaskExecutor {
|
||||
public void start() {
|
||||
workerQueue.add(scheduler.schedule(() -> {
|
||||
if (!executeTasks(Collections.singleton(firstTask)))
|
||||
taskListener.onTerminate();
|
||||
taskListeners.forEach(it -> {
|
||||
it.onTerminate();
|
||||
it.onTerminate(variables);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -86,7 +80,10 @@ public final class TaskExecutor {
|
||||
AtomicBoolean flag = new AtomicBoolean(true);
|
||||
Future<?> future = scheduler.schedule(() -> {
|
||||
if (!executeTasks(Collections.singleton(firstTask))) {
|
||||
taskListener.onTerminate();
|
||||
taskListeners.forEach(it -> {
|
||||
it.onTerminate();
|
||||
it.onTerminate(variables);
|
||||
});
|
||||
flag.set(false);
|
||||
}
|
||||
});
|
||||
@@ -108,7 +105,7 @@ public final class TaskExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean executeTasks(Collection<Task> tasks) {
|
||||
private boolean executeTasks(Collection<Task> tasks) throws InterruptedException {
|
||||
if (tasks.isEmpty())
|
||||
return true;
|
||||
|
||||
@@ -119,38 +116,35 @@ public final class TaskExecutor {
|
||||
if (canceled)
|
||||
return false;
|
||||
Invoker invoker = new Invoker(task, latch, success);
|
||||
Future<?> future = task.getScheduler().schedule(invoker);
|
||||
if (future != null)
|
||||
workerQueue.add(future);
|
||||
try {
|
||||
Future<?> future = task.getScheduler().schedule(invoker);
|
||||
if (future != null)
|
||||
workerQueue.add(future);
|
||||
} catch (RejectedExecutionException e) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
}
|
||||
|
||||
if (canceled)
|
||||
return false;
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
return success.get() && !canceled;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
// Once interrupted, we are aborting the subscription.
|
||||
// and operations fail.
|
||||
return false;
|
||||
}
|
||||
latch.await();
|
||||
return success.get() && !canceled;
|
||||
}
|
||||
|
||||
private boolean executeTask(Task task) {
|
||||
if (canceled)
|
||||
return false;
|
||||
|
||||
if (!task.isHidden())
|
||||
if (task.getSignificance().shouldLog())
|
||||
Logging.LOG.log(Level.FINE, "Executing task: {0}", task.getName());
|
||||
|
||||
taskListener.onReady(task);
|
||||
taskListeners.forEach(it -> it.onReady(task));
|
||||
|
||||
boolean doDependentsSucceeded = executeTasks(task.getDependents());
|
||||
boolean flag = false;
|
||||
|
||||
try {
|
||||
boolean doDependentsSucceeded = executeTasks(task.getDependents());
|
||||
if (!doDependentsSucceeded && task.isRelyingOnDependents() || canceled)
|
||||
throw new SilentException();
|
||||
|
||||
@@ -166,27 +160,29 @@ public final class TaskExecutor {
|
||||
throw new IllegalStateException("Subtasks failed for " + task.getName());
|
||||
|
||||
flag = true;
|
||||
if (!task.isHidden()) {
|
||||
if (task.getSignificance().shouldLog()) {
|
||||
Logging.LOG.log(Level.FINER, "Task finished: {0}", task.getName());
|
||||
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
||||
taskListener.onFinished(task);
|
||||
taskListeners.forEach(it -> it.onFinished(task));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
if (!task.isHidden()) {
|
||||
if (task.getSignificance().shouldLog()) {
|
||||
lastException = e;
|
||||
Logging.LOG.log(Level.FINE, "Task aborted: " + task.getName(), e);
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, true));
|
||||
taskListener.onFailed(task, e);
|
||||
taskListeners.forEach(it -> it.onFailed(task, e));
|
||||
}
|
||||
} catch (SilentException e) {
|
||||
// do nothing
|
||||
} catch (RejectedExecutionException e) {
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
if (!task.isHidden()) {
|
||||
if (task.getSignificance().shouldLog()) {
|
||||
lastException = e;
|
||||
Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e);
|
||||
task.onDone().fireEvent(new TaskEvent(this, task, true));
|
||||
taskListener.onFailed(task, e);
|
||||
taskListeners.forEach(it -> it.onFailed(task, e));
|
||||
}
|
||||
} finally {
|
||||
task.setVariables(null);
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
/**
|
||||
@@ -37,6 +39,9 @@ public abstract class TaskListener implements EventListener {
|
||||
public void onTerminate() {
|
||||
}
|
||||
|
||||
public void onTerminate(AutoTypingMap<String> variables) {
|
||||
}
|
||||
|
||||
public static class DefaultTaskListener extends TaskListener {
|
||||
|
||||
public static final DefaultTaskListener INSTANCE = new DefaultTaskListener();
|
||||
|
||||
Reference in New Issue
Block a user