GC after game launched

This commit is contained in:
huanghongxun 2018-02-18 13:54:13 +08:00
parent 4ad172dda4
commit 20a7039f59
15 changed files with 106 additions and 63 deletions

View File

@ -32,6 +32,7 @@ import org.jackhuang.hmcl.util.*;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
public final class Main extends Application { public final class Main extends Application {
@ -89,6 +90,10 @@ public final class Main extends Application {
Logging.LOG.info("Shutting down executor services."); Logging.LOG.info("Shutting down executor services.");
Schedulers.shutdown(); Schedulers.shutdown();
Controllers.shutdown();
Lang.executeDelayed(OperatingSystem::forceGC, TimeUnit.SECONDS, 5, true);
}); });
} }

View File

@ -143,13 +143,15 @@ public final class LauncherHelper {
@Override @Override
public void onFinished(Task task) { public void onFinished(Task task) {
finished.incrementAndGet(); finished.incrementAndGet();
Platform.runLater(() -> { int runningTasks = executor.getRunningTasks();
launchingStepsPane.setProgress(1.0 * finished.get() / executor.getRunningTasks()); Platform.runLater(() -> launchingStepsPane.setProgress(1.0 * finished.get() / runningTasks));
});
} }
@Override @Override
public void onTerminate() { public void onStop(boolean success, TaskExecutor executor) {
if (success) {
Controllers.closeDialog();
} else {
Platform.runLater(() -> { Platform.runLater(() -> {
if (executor.getLastException() != null) if (executor.getLastException() != null)
Controllers.dialog(I18nException.getStackTrace(executor.getLastException()), Controllers.dialog(I18nException.getStackTrace(executor.getLastException()),
@ -159,6 +161,9 @@ public final class LauncherHelper {
Controllers.closeDialog(); Controllers.closeDialog();
}); });
} }
LauncherHelper.this.executor = null;
}
}); });
executor.start(); executor.start();
@ -217,8 +222,6 @@ public final class LauncherHelper {
} }
public void emitStatus(LoadingState state) { public void emitStatus(LoadingState state) {
if (state == LoadingState.DONE)
Controllers.closeDialog();
launchingStepsPane.setTitle(state.getLocalizedMessage()); launchingStepsPane.setTitle(state.getLocalizedMessage());
launchingStepsPane.setSubtitle((state.ordinal() + 1) + " / " + LoadingState.values().length); launchingStepsPane.setSubtitle((state.ordinal() + 1) + " / " + LoadingState.values().length);

View File

@ -39,7 +39,7 @@ public final class Controllers {
private static Scene scene; private static Scene scene;
private static Stage stage; private static Stage stage;
private static MainPage mainPage = new MainPage(); private static MainPage mainPage = null;
private static SettingsPage settingsPage = null; private static SettingsPage settingsPage = null;
private static VersionPage versionPage = null; private static VersionPage versionPage = null;
private static AuthlibInjectorServersPage serversPage = null; private static AuthlibInjectorServersPage serversPage = null;
@ -75,11 +75,14 @@ public final class Controllers {
return serversPage; return serversPage;
} }
// FXThread
public static Decorator getDecorator() { public static Decorator getDecorator() {
return decorator; return decorator;
} }
public static MainPage getMainPage() { public static MainPage getMainPage() {
if (mainPage == null)
mainPage = new MainPage();
return mainPage; return mainPage;
} }
@ -90,7 +93,7 @@ public final class Controllers {
public static void initialize(Stage stage) { public static void initialize(Stage stage) {
Controllers.stage = stage; Controllers.stage = stage;
decorator = new Decorator(stage, mainPage, Main.TITLE, false, true); decorator = new Decorator(stage, getMainPage(), Main.TITLE, false, true);
decorator.showPage(null); decorator.showPage(null);
leftPaneController = new LeftPaneController(decorator.getLeftPane()); leftPaneController = new LeftPaneController(decorator.getLeftPane());
@ -167,4 +170,14 @@ public final class Controllers {
public static void showUpdate() { public static void showUpdate() {
getDecorator().showUpdate(); getDecorator().showUpdate();
} }
public static void shutdown() {
mainPage = null;
settingsPage = null;
versionPage = null;
serversPage = null;
decorator = null;
stage = null;
scene = null;
}
} }

View File

@ -32,6 +32,7 @@ import javafx.scene.Node;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Toggle; import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup; import javafx.scene.control.ToggleGroup;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
@ -50,6 +51,7 @@ public class MultiFileItem extends ComponentList {
private final StringProperty customTitle = new SimpleStringProperty(this, "customTitle", Main.i18n("selector.custom")); private final StringProperty customTitle = new SimpleStringProperty(this, "customTitle", Main.i18n("selector.custom"));
private final StringProperty chooserTitle = new SimpleStringProperty(this, "chooserTitle", Main.i18n("selector.choose_file")); private final StringProperty chooserTitle = new SimpleStringProperty(this, "chooserTitle", Main.i18n("selector.choose_file"));
private final BooleanProperty directory = new SimpleBooleanProperty(this, "directory", false); private final BooleanProperty directory = new SimpleBooleanProperty(this, "directory", false);
private final SimpleStringProperty tooltip = new SimpleStringProperty(this, "tooltip");
private ObservableList<FileChooser.ExtensionFilter> extensionFilters = FXCollections.observableArrayList(); private ObservableList<FileChooser.ExtensionFilter> extensionFilters = FXCollections.observableArrayList();
private final ToggleGroup group = new ToggleGroup(); private final ToggleGroup group = new ToggleGroup();
@ -109,6 +111,10 @@ public class MultiFileItem extends ComponentList {
if (toggleSelectedListener != null) if (toggleSelectedListener != null)
toggleSelectedListener.accept(newValue); toggleSelectedListener.accept(newValue);
}); });
Tooltip tip = new Tooltip();
tip.textProperty().bind(tooltipProperty());
Tooltip.install(this, tip);
} }
public Node createChildren(String title) { public Node createChildren(String title) {
@ -223,4 +229,16 @@ public class MultiFileItem extends ComponentList {
public ObservableList<FileChooser.ExtensionFilter> getExtensionFilters() { public ObservableList<FileChooser.ExtensionFilter> getExtensionFilters() {
return extensionFilters; return extensionFilters;
} }
public String getTooltip() {
return tooltip.get();
}
public StringProperty tooltipProperty() {
return tooltip;
}
public void setTooltip(String tooltip) {
this.tooltip.set(tooltip);
}
} }

View File

@ -49,7 +49,7 @@ public class NumberValidator extends ValidatorBase {
TextInputControl textField = ((TextInputControl) srcControl.get()); TextInputControl textField = ((TextInputControl) srcControl.get());
if (StringUtils.isBlank(textField.getText())) if (StringUtils.isBlank(textField.getText()))
hasErrors.set(nullable); hasErrors.set(!nullable);
else else
try { try {
Integer.parseInt(textField.getText()); Integer.parseInt(textField.getText());

View File

@ -57,25 +57,24 @@ public interface TaskExecutorDialogWizardDisplayer extends AbstractWizardDisplay
} }
JFXUtilities.runInFX(() -> { JFXUtilities.runInFX(() -> {
TaskExecutor executor = task.executor(e -> new TaskListener() { TaskExecutor executor = task.executor(new TaskListener() {
@Override @Override
public void onSucceed() { public void onStop(boolean success, TaskExecutor executor) {
if (success) {
if (settings.containsKey("success_message") && settings.get("success_message") instanceof String) if (settings.containsKey("success_message") && settings.get("success_message") instanceof String)
JFXUtilities.runInFX(() -> Controllers.dialog((String) settings.get("success_message"), null, MessageBox.FINE_MESSAGE, () -> Controllers.navigate(null))); JFXUtilities.runInFX(() -> Controllers.dialog((String) settings.get("success_message"), null, MessageBox.FINE_MESSAGE, () -> Controllers.navigate(null)));
else if (!settings.containsKey("forbid_success_message")) else if (!settings.containsKey("forbid_success_message"))
JFXUtilities.runInFX(() -> Controllers.dialog(Main.i18n("message.success"), null, MessageBox.FINE_MESSAGE, () -> Controllers.navigate(null))); JFXUtilities.runInFX(() -> Controllers.dialog(Main.i18n("message.success"), null, MessageBox.FINE_MESSAGE, () -> Controllers.navigate(null)));
} } else {
if (executor.getLastException() == null)
@Override
public void onTerminate() {
if (e.getLastException() == null)
return; return;
String appendix = StringUtils.getStackTrace(e.getLastException()); String appendix = StringUtils.getStackTrace(executor.getLastException());
if (settings.containsKey("failure_message") && settings.get("failure_message") instanceof String) if (settings.containsKey("failure_message") && settings.get("failure_message") instanceof String)
JFXUtilities.runInFX(() -> Controllers.dialog(appendix, (String) settings.get("failure_message"), MessageBox.ERROR_MESSAGE, () -> Controllers.navigate(null))); JFXUtilities.runInFX(() -> Controllers.dialog(appendix, (String) settings.get("failure_message"), MessageBox.ERROR_MESSAGE, () -> Controllers.navigate(null)));
else if (!settings.containsKey("forbid_failure_message")) else if (!settings.containsKey("forbid_failure_message"))
JFXUtilities.runInFX(() -> Controllers.dialog(appendix, Main.i18n("wizard.failed"), MessageBox.ERROR_MESSAGE, () -> Controllers.navigate(null))); JFXUtilities.runInFX(() -> Controllers.dialog(appendix, Main.i18n("wizard.failed"), MessageBox.ERROR_MESSAGE, () -> Controllers.navigate(null)));
} }
}
}); });
pane.setExecutor(executor); pane.setExecutor(executor);
Controllers.dialog(pane); Controllers.dialog(pane);

View File

@ -187,7 +187,6 @@ launcher=Launcher
launcher.background=Background Image launcher.background=Background Image
launcher.background.choose=Choose background path. launcher.background.choose=Choose background path.
launcher.background.default=Default launcher.background.default=Default
launcher.background.tooltip=The laucher uses a default background.\nIf you use custom background.png, link it and it will be used.\nIf there is "bg" subdirectory, this app will chooses one picture in "bgskin" randomly.\nIf you set the background setting, this app will use it.
launcher.common_directory=Common Directory launcher.common_directory=Common Directory
launcher.common_directory.choose=Choose common directory. launcher.common_directory.choose=Choose common directory.
launcher.contact=Contact Us launcher.contact=Contact Us

View File

@ -186,8 +186,7 @@ launch.wrong_javadir=错误的Java路径将自动重置为默认Java路径。
launcher=启动器 launcher=启动器
launcher.background=背景地址 launcher.background=背景地址
launcher.background.choose=选择背景路径 launcher.background.choose=选择背景路径
launcher.background.default=默认 launcher.background.default=默认自动检索启动器同目录下的background.png/jpg及bg文件夹内的图片
launcher.background.tooltip=启动器默认使用自带的背景\n如果当前目录有background.png则会使用该文件作为背景\n如果当前目录有bg子目录则会随机使用里面的一张图作为背景\n如果该背景地址被修改则会使用背景地址里的一张图作为背景\n背景地址允许有多个地址使用半角分号";"(不包含双引号)分隔
launcher.common_directory=公共文件夹 launcher.common_directory=公共文件夹
launcher.common_directory.choose=选择公共文件夹 launcher.common_directory.choose=选择公共文件夹
launcher.contact=联系我们 launcher.contact=联系我们

View File

@ -40,7 +40,7 @@ public class AuthlibInjectorAccount extends YggdrasilAccount {
Arguments arguments = Arguments.addJVMArguments(null, arg); Arguments arguments = Arguments.addJVMArguments(null, arg);
if (flag.get()) if (flag.get())
arguments = Arguments.addJVMArguments(arguments, "-Dorg.to2mbn.authlibinjector.config.prefetched=" + getTask.getResult()); arguments = Arguments.addJVMArguments(arguments, "-Dorg.to2mbn.authlibinjector.config.prefetched=" + new String(Base64.getEncoder().encode(getTask.getResult().getBytes())));
return info.setArguments(arguments); return info.setArguments(arguments);
} catch (Exception e) { } catch (Exception e) {

View File

@ -166,7 +166,7 @@ public class YggdrasilAccount extends Account {
isOnline = true; isOnline = true;
return; return;
} }
logIn1(routeRefresh, new RefreshRequest(accessToken, clientToken), proxy); logIn1(routeRefresh, new RefreshRequest(accessToken, clientToken, getSelectedProfile()), proxy);
} }
public void logInWithPassword0(String password, Proxy proxy) throws AuthenticationException { public void logInWithPassword0(String password, Proxy proxy) throws AuthenticationException {

View File

@ -208,9 +208,9 @@ public abstract class Task {
return new TaskExecutor(this); return new TaskExecutor(this);
} }
public final TaskExecutor executor(Function<TaskExecutor, TaskListener> taskListener) { public final TaskExecutor executor(TaskListener taskListener) {
TaskExecutor executor = new TaskExecutor(this); TaskExecutor executor = new TaskExecutor(this);
executor.addTaskListener(taskListener.apply(executor)); executor.addTaskListener(taskListener);
return executor; return executor;
} }

View File

@ -66,13 +66,8 @@ public final class TaskExecutor {
public TaskExecutor start() { public TaskExecutor start() {
taskListeners.forEach(TaskListener::onStart); taskListeners.forEach(TaskListener::onStart);
workerQueue.add(scheduler.schedule(() -> { workerQueue.add(scheduler.schedule(() -> {
if (executeTasks(Collections.singleton(firstTask))) boolean flag = executeTasks(Collections.singleton(firstTask));
taskListeners.forEach(TaskListener::onSucceed); taskListeners.forEach(it -> it.onStop(flag, this));
else
taskListeners.forEach(it -> {
it.onTerminate();
it.onTerminate(variables);
});
})); }));
return this; return this;
} }
@ -81,14 +76,8 @@ public final class TaskExecutor {
taskListeners.forEach(TaskListener::onStart); taskListeners.forEach(TaskListener::onStart);
AtomicBoolean flag = new AtomicBoolean(true); AtomicBoolean flag = new AtomicBoolean(true);
Future<?> future = scheduler.schedule(() -> { Future<?> future = scheduler.schedule(() -> {
if (!executeTasks(Collections.singleton(firstTask))) { flag.set(executeTasks(Collections.singleton(firstTask)));
taskListeners.forEach(it -> { taskListeners.forEach(it -> it.onStop(flag.get(), this));
it.onTerminate();
it.onTerminate(variables);
});
flag.set(false);
} else
taskListeners.forEach(TaskListener::onSucceed);
}); });
workerQueue.add(future); workerQueue.add(future);
Lang.invoke(() -> future.get()); Lang.invoke(() -> future.get());
@ -207,6 +196,10 @@ 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

@ -39,16 +39,12 @@ public abstract class TaskListener implements EventListener {
public void onFailed(Task task, Throwable throwable) { public void onFailed(Task task, Throwable throwable) {
} }
public void onTerminate() { public void onStop(boolean success, TaskExecutor executor) {
}
public void onTerminate(AutoTypingMap<String> variables) {
}
public void onSucceed() {
} }
public static class DefaultTaskListener extends TaskListener { public static class DefaultTaskListener extends TaskListener {
private DefaultTaskListener() {
}
public static final DefaultTaskListener INSTANCE = new DefaultTaskListener(); public static final DefaultTaskListener INSTANCE = new DefaultTaskListener();
} }

View File

@ -8,6 +8,7 @@ package org.jackhuang.hmcl.util;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -249,6 +250,17 @@ public final class Lang {
return result; return result;
} }
public static void executeDelayed(Runnable runnable, TimeUnit timeUnit, long timeout, boolean isDaemon) {
thread(() -> {
try {
timeUnit.sleep(timeout);
runnable.run();
} catch (InterruptedException ignore) {
}
}, null, isDaemon);
}
public static Thread thread(Runnable runnable) { public static Thread thread(Runnable runnable) {
return thread(runnable, null); return thread(runnable, null);
} }

View File

@ -122,4 +122,10 @@ public enum OperatingSystem {
c.putString(string); c.putString(string);
Clipboard.getSystemClipboard().setContent(c); Clipboard.getSystemClipboard().setContent(c);
} }
public static void forceGC() {
System.gc();
System.runFinalization();
System.gc();
}
} }