make launch script

This commit is contained in:
huangyuhui
2018-01-24 19:42:04 +08:00
parent 6db41431ed
commit 056c0901f2
34 changed files with 610 additions and 258 deletions

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -47,6 +47,8 @@ public final class VersionJsonDownloadTask extends Task {
if (!gameVersionList.isLoaded())
dependents.add(gameVersionList.refreshAsync(dependencyManager.getDownloadProvider()));
setSignificance(TaskSignificance.MODERATE);
}
@Override

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -65,6 +65,8 @@ public final class GetTask extends TaskResult<String> {
this.retry = retry;
this.proxy = proxy;
this.id = id;
setName(url.toString());
}
@Override

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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();