Fixed outputing crash advice twice
This commit is contained in:
@@ -38,10 +38,10 @@ import org.jackhuang.hmcl.util.C;
|
|||||||
import org.jackhuang.hmcl.util.MessageBox;
|
import org.jackhuang.hmcl.util.MessageBox;
|
||||||
import org.jackhuang.hmcl.api.func.Consumer;
|
import org.jackhuang.hmcl.api.func.Consumer;
|
||||||
import org.jackhuang.hmcl.api.HMCLog;
|
import org.jackhuang.hmcl.api.HMCLog;
|
||||||
import org.jackhuang.hmcl.api.event.SimpleEvent;
|
|
||||||
import org.jackhuang.hmcl.api.event.launch.LaunchingState;
|
import org.jackhuang.hmcl.api.event.launch.LaunchingState;
|
||||||
import org.jackhuang.hmcl.util.DefaultPlugin;
|
import org.jackhuang.hmcl.util.DefaultPlugin;
|
||||||
import org.jackhuang.hmcl.util.sys.FileUtils;
|
import org.jackhuang.hmcl.util.sys.FileUtils;
|
||||||
|
import org.jackhuang.hmcl.util.sys.PrintlnEvent;
|
||||||
import org.jackhuang.hmcl.util.sys.ProcessMonitor;
|
import org.jackhuang.hmcl.util.sys.ProcessMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,9 +81,10 @@ public class LaunchingUIDaemon {
|
|||||||
});
|
});
|
||||||
HMCLApi.EVENT_BUS.channel(JavaProcessStoppedEvent.class).register(event -> checkExit((LauncherVisibility) ((ProcessMonitor) event.getSource()).getTag()));
|
HMCLApi.EVENT_BUS.channel(JavaProcessStoppedEvent.class).register(event -> checkExit((LauncherVisibility) ((ProcessMonitor) event.getSource()).getTag()));
|
||||||
HMCLApi.EVENT_BUS.channel(JavaProcessExitedAbnormallyEvent.class).register(event -> {
|
HMCLApi.EVENT_BUS.channel(JavaProcessExitedAbnormallyEvent.class).register(event -> {
|
||||||
|
ProcessMonitor monitor = (ProcessMonitor) event.getSource();
|
||||||
int exitCode = event.getValue().getExitCode();
|
int exitCode = event.getValue().getExitCode();
|
||||||
event.getValue().waitForCommandLineCompletion();
|
|
||||||
HMCLog.err("The game exited abnormally, exit code: " + exitCode);
|
HMCLog.err("The game exited abnormally, exit code: " + exitCode);
|
||||||
|
monitor.waitForCommandLineCompletion();
|
||||||
String[] logs = event.getValue().getStdOutLines().toArray(new String[0]);
|
String[] logs = event.getValue().getStdOutLines().toArray(new String[0]);
|
||||||
String errorText = null;
|
String errorText = null;
|
||||||
for (String s : logs) {
|
for (String s : logs) {
|
||||||
@@ -135,9 +136,9 @@ public class LaunchingUIDaemon {
|
|||||||
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
|
}, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Consumer<SimpleEvent<String>> PRINTLN = t -> {
|
private static final Consumer<PrintlnEvent> PRINTLN = t -> {
|
||||||
LauncherVisibility l = ((LauncherVisibility) ((ProcessMonitor) t.getSource()).getTag());
|
LauncherVisibility l = ((LauncherVisibility) ((ProcessMonitor) t.getSource()).getTag());
|
||||||
if (t.getValue().contains("LWJGL Version: ") && l != LauncherVisibility.KEEP)
|
if (t.getLine().contains("LWJGL Version: ") && l != LauncherVisibility.KEEP)
|
||||||
if (l != LauncherVisibility.HIDE_AND_REOPEN)
|
if (l != LauncherVisibility.HIDE_AND_REOPEN)
|
||||||
MainFrame.INSTANCE.dispose();
|
MainFrame.INSTANCE.dispose();
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -39,6 +39,4 @@ public interface IProcess {
|
|||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void waitForCommandLineCompletion();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.sys;
|
package org.jackhuang.hmcl.util.sys;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import org.jackhuang.hmcl.api.IProcess;
|
import org.jackhuang.hmcl.api.IProcess;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import org.jackhuang.hmcl.api.HMCLog;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -30,10 +29,9 @@ import org.jackhuang.hmcl.api.HMCLog;
|
|||||||
*/
|
*/
|
||||||
public class JavaProcess implements IProcess {
|
public class JavaProcess implements IProcess {
|
||||||
|
|
||||||
private final CountDownLatch latch = new CountDownLatch(2);
|
|
||||||
private final List<String> commands;
|
private final List<String> commands;
|
||||||
private final Process process;
|
private final Process process;
|
||||||
private final Vector<String> stdOutLines = new Vector<>();
|
private final List<String> stdOutLines = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
public JavaProcess(List<String> commands, Process process) {
|
public JavaProcess(List<String> commands, Process process) {
|
||||||
this.commands = commands;
|
this.commands = commands;
|
||||||
@@ -75,19 +73,6 @@ public class JavaProcess implements IProcess {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CountDownLatch getLatch() {
|
|
||||||
return latch;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void waitForCommandLineCompletion() {
|
|
||||||
try {
|
|
||||||
latch.await();
|
|
||||||
} catch (InterruptedException ignore) {
|
|
||||||
HMCLog.warn("Thread has been interrupted.", ignore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getExitCode() {
|
public int getExitCode() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2013 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* 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 {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.util.sys;
|
||||||
|
|
||||||
|
import java.util.EventObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For ProcessThread.
|
||||||
|
* @author huang
|
||||||
|
*/
|
||||||
|
public class PrintlnEvent extends EventObject {
|
||||||
|
|
||||||
|
String line;
|
||||||
|
boolean error;
|
||||||
|
|
||||||
|
public PrintlnEvent(Object source, String line, boolean isError) {
|
||||||
|
super(source);
|
||||||
|
this.line = line;
|
||||||
|
this.error = isError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLine() {
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.util.sys;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import org.jackhuang.hmcl.api.HMCLApi;
|
import org.jackhuang.hmcl.api.HMCLApi;
|
||||||
import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent;
|
import org.jackhuang.hmcl.api.event.process.JVMLaunchFailedEvent;
|
||||||
import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent;
|
import org.jackhuang.hmcl.api.event.process.JavaProcessExitedAbnormallyEvent;
|
||||||
@@ -39,6 +40,7 @@ public class ProcessMonitor {
|
|||||||
|
|
||||||
public static final HashSet<ProcessMonitor> MONITORS = new HashSet<>();
|
public static final HashSet<ProcessMonitor> MONITORS = new HashSet<>();
|
||||||
|
|
||||||
|
private final CountDownLatch latch = new CountDownLatch(2);
|
||||||
ProcessThread inputThread, errorThread;
|
ProcessThread inputThread, errorThread;
|
||||||
private final IProcess p;
|
private final IProcess p;
|
||||||
|
|
||||||
@@ -64,13 +66,14 @@ public class ProcessMonitor {
|
|||||||
public void setTag(Object tag) {
|
public void setTag(Object tag) {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPrintlnEvent(Consumer<SimpleEvent<String>> c) {
|
public void registerPrintlnEvent(Consumer<PrintlnEvent> c) {
|
||||||
inputThread.printlnEvent.register(c);
|
inputThread.printlnEvent.register(c);
|
||||||
errorThread.printlnEvent.register(c);
|
errorThread.printlnEvent.register(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
|
hasFired = false;
|
||||||
MONITORS.add(this);
|
MONITORS.add(this);
|
||||||
HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStartingEvent(this, p));
|
HMCLApi.EVENT_BUS.fireChannel(new JavaProcessStartingEvent(this, p));
|
||||||
inputThread.start();
|
inputThread.start();
|
||||||
@@ -78,21 +81,34 @@ public class ProcessMonitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void threadStopped(SimpleEvent<IProcess> event) {
|
private void threadStopped(SimpleEvent<IProcess> event) {
|
||||||
|
latch.countDown();
|
||||||
ProcessThread t = (ProcessThread) event.getSource();
|
ProcessThread t = (ProcessThread) event.getSource();
|
||||||
HMCLog.log("Process exit code: " + p.getExitCode());
|
HMCLog.log("Process exit code: " + p.getExitCode());
|
||||||
if (p.getExitCode() != 0 || StrUtils.containsOne(t.getLines(),
|
if (p.getExitCode() != 0 || StrUtils.containsOne(t.getLines(),
|
||||||
Arrays.asList("Unable to launch"),
|
Arrays.asList("Unable to launch"),
|
||||||
x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR)))
|
x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR)))
|
||||||
HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(ProcessMonitor.this, p));
|
synchronized (this) {
|
||||||
|
if (!hasFired) {
|
||||||
|
hasFired = true;
|
||||||
|
HMCLApi.EVENT_BUS.fireChannel(new JavaProcessExitedAbnormallyEvent(ProcessMonitor.this, p));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (p.getExitCode() != 0 && StrUtils.containsOne(t.getLines(),
|
if (p.getExitCode() != 0 && StrUtils.containsOne(t.getLines(),
|
||||||
Arrays.asList("Could not create the Java Virtual Machine.",
|
Arrays.asList("Could not create the Java Virtual Machine.",
|
||||||
"Error occurred during initialization of VM",
|
"Error occurred during initialization of VM",
|
||||||
"A fatal exception has occurred. Program will exit.",
|
"A fatal exception has occurred. Program will exit.",
|
||||||
"Unable to launch"),
|
"Unable to launch"),
|
||||||
x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR)))
|
x -> Level.guessLevel(x, Level.INFO).lessOrEqual(Level.ERROR)))
|
||||||
HMCLApi.EVENT_BUS.fireChannel(new JVMLaunchFailedEvent(ProcessMonitor.this, p));
|
synchronized (this) {
|
||||||
|
if (!hasFired) {
|
||||||
|
hasFired = true;
|
||||||
|
HMCLApi.EVENT_BUS.fireChannel(new JVMLaunchFailedEvent(ProcessMonitor.this, p));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean hasFired = false;
|
||||||
|
|
||||||
private void processThreadStopped(ProcessThread t1) {
|
private void processThreadStopped(ProcessThread t1) {
|
||||||
MONITORS.remove(this);
|
MONITORS.remove(this);
|
||||||
errorThread.interrupt();
|
errorThread.interrupt();
|
||||||
@@ -106,4 +122,12 @@ public class ProcessMonitor {
|
|||||||
monitor.errorThread.interrupt();
|
monitor.errorThread.interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void waitForCommandLineCompletion() {
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
HMCLog.warn("Thread has been interrupted.", ignore);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import java.io.BufferedReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
|
||||||
import org.jackhuang.hmcl.api.HMCLog;
|
import org.jackhuang.hmcl.api.HMCLog;
|
||||||
import org.jackhuang.hmcl.api.event.EventHandler;
|
import org.jackhuang.hmcl.api.event.EventHandler;
|
||||||
import org.jackhuang.hmcl.api.event.SimpleEvent;
|
import org.jackhuang.hmcl.api.event.SimpleEvent;
|
||||||
@@ -36,24 +36,27 @@ import org.jackhuang.hmcl.api.IProcess;
|
|||||||
*/
|
*/
|
||||||
public class ProcessThread extends Thread {
|
public class ProcessThread extends Thread {
|
||||||
|
|
||||||
Vector<String> lines = new Vector<>();
|
List<String> lines = new ArrayList<>();
|
||||||
ProcessMonitor monitor;
|
ProcessMonitor monitor;
|
||||||
|
IProcess p;
|
||||||
boolean readError;
|
boolean readError;
|
||||||
public final EventHandler<SimpleEvent<String>> printlnEvent = new EventHandler<>();
|
public final EventHandler<PrintlnEvent> printlnEvent = new EventHandler<>();
|
||||||
public final EventHandler<SimpleEvent<IProcess>> stopEvent = new EventHandler<>();
|
public final EventHandler<SimpleEvent<IProcess>> stopEvent = new EventHandler<>();
|
||||||
|
|
||||||
public ProcessThread(ProcessMonitor monitor, boolean readError) {
|
public ProcessThread(ProcessMonitor monitor, boolean readError) {
|
||||||
this.monitor = monitor;
|
this.monitor = monitor;
|
||||||
this.readError = readError;
|
this.readError = readError;
|
||||||
|
p = monitor.getProcess();
|
||||||
setDaemon(readError);
|
setDaemon(readError);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProcess getProcess() {
|
public IProcess getProcess() {
|
||||||
return monitor.getProcess();
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only get stdout or stderr output according to readError().
|
* Only get stdout or stderr output according to readError().
|
||||||
|
* Invoke this method only if the process thread has stopped.
|
||||||
*/
|
*/
|
||||||
public List<String> getLines() {
|
public List<String> getLines() {
|
||||||
return lines;
|
return lines;
|
||||||
@@ -63,32 +66,28 @@ public class ProcessThread extends Thread {
|
|||||||
public void run() {
|
public void run() {
|
||||||
setName("ProcessMonitor");
|
setName("ProcessMonitor");
|
||||||
BufferedReader br = null;
|
BufferedReader br = null;
|
||||||
IProcess p = monitor.getProcess();
|
|
||||||
try {
|
try {
|
||||||
InputStream in = readError ? p.getRawProcess().getErrorStream() : p.getRawProcess().getInputStream();
|
InputStream in = readError ? p.getRawProcess().getErrorStream() : p.getRawProcess().getInputStream();
|
||||||
br = new BufferedReader(new InputStreamReader(in, Charsets.toCharset()));
|
br = new BufferedReader(new InputStreamReader(in, Charsets.toCharset()));
|
||||||
|
|
||||||
String line;
|
String line;
|
||||||
while (p.isRunning())
|
while (p.isRunning())
|
||||||
while ((line = br.readLine()) != null) {
|
while ((line = br.readLine()) != null)
|
||||||
printlnEvent.fire(new SimpleEvent<>(monitor, line));
|
println(line);
|
||||||
System.out.println("MC: " + line);
|
while ((line = br.readLine()) != null)
|
||||||
lines.add(line);
|
println(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);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
HMCLog.err("An error occured when reading process stdout/stderr.", e);
|
HMCLog.err("An error occured when reading process stdout/stderr.", e);
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(br);
|
IOUtils.closeQuietly(br);
|
||||||
}
|
}
|
||||||
if (p instanceof JavaProcess)
|
|
||||||
((JavaProcess) p).getLatch().countDown();
|
|
||||||
stopEvent.fire(new SimpleEvent<>(this, p));
|
stopEvent.fire(new SimpleEvent<>(this, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void println(String line) {
|
||||||
|
printlnEvent.fire(new PrintlnEvent(monitor, line, readError));
|
||||||
|
(readError ? System.err : System.out).println("MC: " + line);
|
||||||
|
lines.add(line);
|
||||||
|
p.getStdOutLines().add(line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ public class BEButtonUI extends BasicButtonUI implements Skin {
|
|||||||
state = State.ROLLOVER;
|
state = State.ROLLOVER;
|
||||||
else if (b instanceof JButton
|
else if (b instanceof JButton
|
||||||
&& ((JButton) b).isDefaultButton())
|
&& ((JButton) b).isDefaultButton())
|
||||||
state = State.DEFAULTED;
|
state = State.DEFAULT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
state = State.NORMAL;
|
state = State.NORMAL;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ public class AnimationController implements ActionListener, PropertyChangeListen
|
|||||||
State oldState = controller.getState(c, part);
|
State oldState = controller.getState(c, part);
|
||||||
if (oldState != newState) {
|
if (oldState != newState) {
|
||||||
controller.putState(c, part, newState);
|
controller.putState(c, part, newState);
|
||||||
if (newState == State.DEFAULTED)
|
if (newState == State.DEFAULT)
|
||||||
// it seems for DEFAULTED button state Vista does animation from
|
// it seems for DEFAULTED button state Vista does animation from
|
||||||
// HOT
|
// HOT
|
||||||
oldState = State.ROLLOVER;
|
oldState = State.ROLLOVER;
|
||||||
@@ -182,7 +182,7 @@ public class AnimationController implements ActionListener, PropertyChangeListen
|
|||||||
State endState,
|
State endState,
|
||||||
long millis) {
|
long millis) {
|
||||||
boolean isForwardAndReverse = false;
|
boolean isForwardAndReverse = false;
|
||||||
if (endState == State.DEFAULTED)
|
if (endState == State.DEFAULT)
|
||||||
isForwardAndReverse = true;
|
isForwardAndReverse = true;
|
||||||
Map<Part, AnimationState> map = animationStateMap.get(component);
|
Map<Part, AnimationState> map = animationStateMap.get(component);
|
||||||
if (millis <= 0) {
|
if (millis <= 0) {
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ public class TMSchema {
|
|||||||
BULLETNORMAL,
|
BULLETNORMAL,
|
||||||
BULLETDISABLED,
|
BULLETDISABLED,
|
||||||
CLOSED,
|
CLOSED,
|
||||||
DEFAULTED,
|
DEFAULT,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
DISABLEDHOT,
|
DISABLEDHOT,
|
||||||
DISABLEDPUSHED,
|
DISABLEDPUSHED,
|
||||||
@@ -304,7 +304,7 @@ public class TMSchema {
|
|||||||
});
|
});
|
||||||
|
|
||||||
stateMap.put(Part.BP_PUSHBUTTON,
|
stateMap.put(Part.BP_PUSHBUTTON,
|
||||||
new State[] { NORMAL, ROLLOVER, PRESSED, DISABLED, DEFAULTED });
|
new State[] { NORMAL, ROLLOVER, PRESSED, DISABLED, DEFAULT });
|
||||||
|
|
||||||
stateMap.put(Part.BP_RADIOBUTTON,
|
stateMap.put(Part.BP_RADIOBUTTON,
|
||||||
new State[] {
|
new State[] {
|
||||||
|
|||||||
Reference in New Issue
Block a user