diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java index ac9456cdc..d74ef360e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java @@ -82,6 +82,7 @@ public class LaunchingUIDaemon { HMCLApi.EVENT_BUS.channel(JavaProcessStoppedEvent.class).register(event -> checkExit((LauncherVisibility) ((ProcessMonitor) event.getSource()).getTag())); HMCLApi.EVENT_BUS.channel(JavaProcessExitedAbnormallyEvent.class).register(event -> { int exitCode = event.getValue().getExitCode(); + event.getValue().waitForCommandLineCompletion(); HMCLog.err("The game exited abnormally, exit code: " + exitCode); String[] logs = event.getValue().getStdOutLines().toArray(new String[0]); String errorText = null; diff --git a/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/IProcess.java b/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/IProcess.java index ae173529b..a4dec1ca0 100644 --- a/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/IProcess.java +++ b/HMCLAPI/src/main/java/org/jackhuang/hmcl/api/IProcess.java @@ -17,7 +17,6 @@ */ package org.jackhuang.hmcl.api; -import java.util.ArrayList; import java.util.List; /** @@ -34,10 +33,12 @@ public interface IProcess { List getStartupCommands(); - ArrayList getStdOutLines(); + List getStdOutLines(); boolean isRunning(); void stop(); + void waitForCommandLineCompletion(); + } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java index fa91a1f1d..2c6f25b37 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/JavaProcess.java @@ -18,9 +18,11 @@ package org.jackhuang.hmcl.util.sys; import org.jackhuang.hmcl.api.IProcess; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Vector; +import java.util.concurrent.CountDownLatch; +import org.jackhuang.hmcl.api.HMCLog; /** * @@ -28,9 +30,10 @@ import java.util.List; */ public class JavaProcess implements IProcess { + private final CountDownLatch latch = new CountDownLatch(2); private final List commands; private final Process process; - private final ArrayList stdOutLines = new ArrayList<>(); + private final Vector stdOutLines = new Vector<>(); public JavaProcess(List commands, Process process) { this.commands = commands; @@ -57,7 +60,7 @@ public class JavaProcess implements IProcess { } @Override - public ArrayList getStdOutLines() { + public List getStdOutLines() { return this.stdOutLines; } @@ -72,6 +75,19 @@ public class JavaProcess implements IProcess { return false; } + CountDownLatch getLatch() { + return latch; + } + + @Override + public void waitForCommandLineCompletion() { + try { + latch.await(); + } catch (InterruptedException ignore) { + HMCLog.warn("Thread has been interrupted.", ignore); + } + } + @Override public int getExitCode() { try { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java index 06bc3245f..6bb61cbfc 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessMonitor.java @@ -77,13 +77,14 @@ public class ProcessMonitor { errorThread.start(); } - private void threadStopped() { + private void threadStopped(SimpleEvent event) { + ProcessThread t = (ProcessThread) event.getSource(); HMCLog.log("Process exit code: " + p.getExitCode()); - if (p.getExitCode() != 0 || StrUtils.containsOne(p.getStdOutLines(), + if (p.getExitCode() != 0 || StrUtils.containsOne(t.getLines(), Arrays.asList("Unable to launch"), x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR))) HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(ProcessMonitor.this, p)); - if (p.getExitCode() != 0 && StrUtils.containsOne(p.getStdOutLines(), + if (p.getExitCode() != 0 && StrUtils.containsOne(t.getLines(), Arrays.asList("Could not create the Java Virtual Machine.", "Error occurred during initialization of VM", "A fatal exception has occurred. Program will exit.", diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java index 6595405c1..e25e492d7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/sys/ProcessThread.java @@ -21,6 +21,8 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.List; +import java.util.Vector; import org.jackhuang.hmcl.api.HMCLog; import org.jackhuang.hmcl.api.event.EventHandler; import org.jackhuang.hmcl.api.event.SimpleEvent; @@ -28,11 +30,13 @@ import org.jackhuang.hmcl.util.code.Charsets; import org.jackhuang.hmcl.api.IProcess; /** + * Watch the process command line output(stdout or stderr). * * @author huangyuhui */ public class ProcessThread extends Thread { + Vector lines = new Vector<>(); ProcessMonitor monitor; boolean readError; public final EventHandler> printlnEvent = new EventHandler<>(); @@ -48,6 +52,13 @@ public class ProcessThread extends Thread { return monitor.getProcess(); } + /** + * Only get stdout or stderr output according to readError(). + */ + public List getLines() { + return lines; + } + @Override public void run() { setName("ProcessMonitor"); @@ -62,18 +73,22 @@ public class ProcessThread extends Thread { while ((line = br.readLine()) != null) { printlnEvent.fire(new SimpleEvent<>(monitor, line)); System.out.println("MC: " + line); + lines.add(line); p.getStdOutLines().add(line); } while ((line = br.readLine()) != null) { printlnEvent.fire(new SimpleEvent<>(monitor, line)); System.out.println("MC: " + line); + lines.add(line); p.getStdOutLines().add(line); } - stopEvent.fire(new SimpleEvent<>(this, p)); } catch (IOException e) { HMCLog.err("An error occured when reading process stdout/stderr.", e); } finally { IOUtils.closeQuietly(br); } + if (p instanceof JavaProcess) + ((JavaProcess) p).getLatch().countDown(); + stopEvent.fire(new SimpleEvent<>(this, p)); } }