Remove logging support which is meaningless
This commit is contained in:
@@ -65,7 +65,6 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
|
|||||||
public Task checkGameCompletionAsync(Version version) {
|
public Task checkGameCompletionAsync(Version version) {
|
||||||
return new ParallelTask(
|
return new ParallelTask(
|
||||||
new GameAssetDownloadTask(this, version),
|
new GameAssetDownloadTask(this, version),
|
||||||
new GameLoggingDownloadTask(this, version),
|
|
||||||
new GameLibrariesTask(this, version)
|
new GameLibrariesTask(this, version)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ public class DefaultGameBuilder extends GameBuilder {
|
|||||||
variables.set("version", version);
|
variables.set("version", version);
|
||||||
Task result = new ParallelTask(
|
Task result = new ParallelTask(
|
||||||
new GameAssetDownloadTask(dependencyManager, version),
|
new GameAssetDownloadTask(dependencyManager, version),
|
||||||
new GameLoggingDownloadTask(dependencyManager, version),
|
|
||||||
downloadGameAsync(gameVersion, version),
|
downloadGameAsync(gameVersion, version),
|
||||||
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
||||||
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher.
|
|
||||||
* Copyright (C) 2018 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.download.game;
|
|
||||||
|
|
||||||
import org.jackhuang.hmcl.download.DependencyManager;
|
|
||||||
import org.jackhuang.hmcl.game.DownloadType;
|
|
||||||
import org.jackhuang.hmcl.game.LoggingInfo;
|
|
||||||
import org.jackhuang.hmcl.game.Version;
|
|
||||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
|
||||||
import org.jackhuang.hmcl.task.Task;
|
|
||||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This task is to download log4j configuration file provided in minecraft.json.
|
|
||||||
*
|
|
||||||
* @author huangyuhui
|
|
||||||
*/
|
|
||||||
public final class GameLoggingDownloadTask extends Task {
|
|
||||||
|
|
||||||
private final DependencyManager dependencyManager;
|
|
||||||
private final Version version;
|
|
||||||
private final List<Task> dependencies = new LinkedList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*
|
|
||||||
* @param dependencyManager the dependency manager that can provides {@link org.jackhuang.hmcl.game.GameRepository}
|
|
||||||
* @param version the <b>resolved</b> version
|
|
||||||
*/
|
|
||||||
public GameLoggingDownloadTask(DependencyManager dependencyManager, Version version) {
|
|
||||||
this.dependencyManager = dependencyManager;
|
|
||||||
this.version = version;
|
|
||||||
setSignificance(TaskSignificance.MODERATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<Task> getDependencies() {
|
|
||||||
return dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute() {
|
|
||||||
if (version.getLogging() == null || !version.getLogging().containsKey(DownloadType.CLIENT))
|
|
||||||
return;
|
|
||||||
|
|
||||||
LoggingInfo logging = version.getLogging().get(DownloadType.CLIENT);
|
|
||||||
File file = dependencyManager.getGameRepository().getLoggingObject(version.getId(), version.getAssetIndex().getId(), logging);
|
|
||||||
if (!file.exists())
|
|
||||||
dependencies.add(new FileDownloadTask(NetworkUtils.toURL(logging.getFile().getUrl()), file));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -47,7 +47,7 @@ public class DefaultLauncher extends Launcher {
|
|||||||
super(repository, versionId, authInfo, options, listener, daemon);
|
super(repository, versionId, authInfo, options, listener, daemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandBuilder generateCommandLine(File nativeFolder, boolean enableLoggingInfo) throws IOException {
|
private CommandBuilder generateCommandLine(File nativeFolder) throws IOException {
|
||||||
CommandBuilder res = new CommandBuilder();
|
CommandBuilder res = new CommandBuilder();
|
||||||
|
|
||||||
// Executable
|
// Executable
|
||||||
@@ -70,16 +70,6 @@ public class DefaultLauncher extends Launcher {
|
|||||||
res.add("-Xdock:icon=" + repository.getAssetObject(version.getId(), version.getAssetIndex().getId(), "icons/minecraft.icns").getAbsolutePath());
|
res.add("-Xdock:icon=" + repository.getAssetObject(version.getId(), version.getAssetIndex().getId(), "icons/minecraft.icns").getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<DownloadType, LoggingInfo> logging = version.getLogging();
|
|
||||||
if (logging != null && enableLoggingInfo) {
|
|
||||||
LoggingInfo loggingInfo = logging.get(DownloadType.CLIENT);
|
|
||||||
if (loggingInfo != null) {
|
|
||||||
File loggingFile = repository.getLoggingObject(version.getId(), version.getAssetIndex().getId(), loggingInfo);
|
|
||||||
if (loggingFile.exists())
|
|
||||||
res.add(loggingInfo.getArgument().replace("${path}", loggingFile.getAbsolutePath()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
|
if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS)
|
||||||
res.add("-Duser.home=" + options.getGameDir().getParent());
|
res.add("-Duser.home=" + options.getGameDir().getParent());
|
||||||
|
|
||||||
@@ -252,7 +242,7 @@ public class DefaultLauncher extends Launcher {
|
|||||||
File nativeFolder = Files.createTempDirectory("minecraft").toFile();
|
File nativeFolder = Files.createTempDirectory("minecraft").toFile();
|
||||||
|
|
||||||
// To guarantee that when failed to generate launch command line, we will not call pre-launch command
|
// To guarantee that when failed to generate launch command line, we will not call pre-launch command
|
||||||
List<String> rawCommandLine = generateCommandLine(nativeFolder, isEnablingLoggingInfo()).asList();
|
List<String> rawCommandLine = generateCommandLine(nativeFolder).asList();
|
||||||
|
|
||||||
decompressNatives(nativeFolder);
|
decompressNatives(nativeFolder);
|
||||||
|
|
||||||
@@ -304,50 +294,17 @@ public class DefaultLauncher extends Launcher {
|
|||||||
writer.write(options.getPreLaunchCommand());
|
writer.write(options.getPreLaunchCommand());
|
||||||
writer.newLine();
|
writer.newLine();
|
||||||
}
|
}
|
||||||
writer.write(generateCommandLine(nativeFolder, false).toString());
|
writer.write(generateCommandLine(nativeFolder).toString());
|
||||||
}
|
}
|
||||||
if (!scriptFile.setExecutable(true))
|
if (!scriptFile.setExecutable(true))
|
||||||
throw new PermissionException();
|
throw new PermissionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isEnablingLoggingInfo() {
|
|
||||||
return version.getLogging() != null && version.getLogging().containsKey(DownloadType.CLIENT)
|
|
||||||
&& !"net.minecraft.launchwrapper.Launch".equals(version.getMainClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener) {
|
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener) {
|
||||||
startMonitors(managedProcess, processListener, true);
|
startMonitors(managedProcess, processListener, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, boolean isDaemon) {
|
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, boolean isDaemon) {
|
||||||
if (isEnablingLoggingInfo())
|
|
||||||
startMonitorsWithLoggingInfo(managedProcess, processListener, isDaemon);
|
|
||||||
else
|
|
||||||
startMonitorsWithoutLoggingInfo(managedProcess, processListener, isDaemon);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startMonitorsWithLoggingInfo(ManagedProcess managedProcess, ProcessListener processListener, boolean isDaemon) {
|
|
||||||
processListener.setProcess(managedProcess);
|
|
||||||
Log4jHandler logHandler = new Log4jHandler((line, level) -> {
|
|
||||||
processListener.onLog(line, level);
|
|
||||||
managedProcess.addLine(line);
|
|
||||||
});
|
|
||||||
logHandler.start();
|
|
||||||
managedProcess.addRelatedThread(logHandler);
|
|
||||||
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), logHandler::newLine), "stdout-pump", isDaemon);
|
|
||||||
managedProcess.addRelatedThread(stdout);
|
|
||||||
Thread stderr = Lang.thread(new StreamPump(managedProcess.getProcess().getErrorStream(), it -> {
|
|
||||||
processListener.onLog(it + OperatingSystem.LINE_SEPARATOR, Log4jLevel.ERROR);
|
|
||||||
managedProcess.addLine(it);
|
|
||||||
}), "stderr-pump", isDaemon);
|
|
||||||
managedProcess.addRelatedThread(stderr);
|
|
||||||
managedProcess.addRelatedThread(Lang.thread(new ExitWaiter(managedProcess, Arrays.asList(stdout, stderr), (exitCode, exitType) -> {
|
|
||||||
logHandler.onStopped();
|
|
||||||
processListener.onExit(exitCode, exitType);
|
|
||||||
}), "exit-waiter", isDaemon));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startMonitorsWithoutLoggingInfo(ManagedProcess managedProcess, ProcessListener processListener, boolean isDaemon) {
|
|
||||||
processListener.setProcess(managedProcess);
|
processListener.setProcess(managedProcess);
|
||||||
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> {
|
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> {
|
||||||
processListener.onLog(it + OperatingSystem.LINE_SEPARATOR, Optional.ofNullable(Log4jLevel.guessLevel(it)).orElse(Log4jLevel.INFO));
|
processListener.onLog(it + OperatingSystem.LINE_SEPARATOR, Optional.ofNullable(Log4jLevel.guessLevel(it)).orElse(Log4jLevel.INFO));
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Hello Minecraft! Launcher.
|
|
||||||
* Copyright (C) 2018 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.launch;
|
|
||||||
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
|
||||||
import org.jackhuang.hmcl.util.*;
|
|
||||||
import org.xml.sax.Attributes;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
import org.xml.sax.XMLReader;
|
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
|
||||||
import org.xml.sax.helpers.XMLReaderFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InterruptedIOException;
|
|
||||||
import java.io.PipedInputStream;
|
|
||||||
import java.io.PipedOutputStream;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is to parse log4j classic XML layout logging,
|
|
||||||
* since only vanilla Minecraft will enable this layout.
|
|
||||||
*
|
|
||||||
* Also supports plain logs.
|
|
||||||
*
|
|
||||||
* @author huangyuhui
|
|
||||||
*/
|
|
||||||
final class Log4jHandler extends Thread {
|
|
||||||
|
|
||||||
private final XMLReader reader;
|
|
||||||
private final BiConsumer<String, Log4jLevel> callback;
|
|
||||||
private final PipedOutputStream outputStream = new PipedOutputStream();
|
|
||||||
private final PipedInputStream inputStream = Lang.invoke(() -> new PipedInputStream(outputStream));
|
|
||||||
private final AtomicBoolean interrupted = new AtomicBoolean(false);
|
|
||||||
private final List<String> logs = new LinkedList<>();
|
|
||||||
private boolean broken = false;
|
|
||||||
|
|
||||||
public Log4jHandler(BiConsumer<String, Log4jLevel> callback) {
|
|
||||||
this.callback = callback;
|
|
||||||
newLine("<output>");
|
|
||||||
|
|
||||||
reader = Lang.invoke((ExceptionalSupplier<XMLReader, SAXException>) XMLReaderFactory::createXMLReader);
|
|
||||||
reader.setContentHandler(new Log4jHandlerImpl());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
setName("log4j-handler");
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputSource inputSource = new InputSource(inputStream);
|
|
||||||
reader.parse(inputSource);
|
|
||||||
} catch (InterruptedIOException e) {
|
|
||||||
// Game has been interrupted.
|
|
||||||
interrupted.set(true);
|
|
||||||
} catch (SAXException | IOException e) {
|
|
||||||
Logging.LOG.log(Level.WARNING, "An error occurred when reading console lines", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onStopped() {
|
|
||||||
if (interrupted.get())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Lang.invoke(() -> Schedulers.newThread().schedule(() -> {
|
|
||||||
if (!interrupted.get()) {
|
|
||||||
newLine("</output>").get();
|
|
||||||
outputStream.close();
|
|
||||||
join();
|
|
||||||
}
|
|
||||||
}).get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Future<?> newLine(String log) {
|
|
||||||
return Schedulers.computation().schedule(() -> {
|
|
||||||
try {
|
|
||||||
// Prevent from namespace parsing
|
|
||||||
String line = log.replace("log4j:", "log4j_");
|
|
||||||
logs.add(line);
|
|
||||||
if (broken)
|
|
||||||
System.out.println(line);
|
|
||||||
|
|
||||||
byte[] bytes = (line + OperatingSystem.LINE_SEPARATOR).getBytes(Constants.SYSTEM_CHARSET);
|
|
||||||
outputStream.write(bytes);
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Ignoring IOException, including read end dead.
|
|
||||||
if (!broken) {
|
|
||||||
Logging.LOG.log(Level.WARNING, "An error occurred when writing console lines", e);
|
|
||||||
logs.forEach(System.out::println);
|
|
||||||
broken = true;
|
|
||||||
} else {
|
|
||||||
// Output plain XML to user
|
|
||||||
callback.accept(log, Log4jLevel.INFO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Log4jHandlerImpl extends DefaultHandler {
|
|
||||||
|
|
||||||
private final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
|
|
||||||
|
|
||||||
private String date = "", thread = "", logger = "";
|
|
||||||
private StringBuilder message;
|
|
||||||
private Log4jLevel level;
|
|
||||||
private boolean readingMessage = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
|
||||||
switch (localName) {
|
|
||||||
case "log4j_Event":
|
|
||||||
message = new StringBuilder();
|
|
||||||
Date d = new Date(Long.parseLong(attributes.getValue("timestamp")));
|
|
||||||
date = format.format(d);
|
|
||||||
try {
|
|
||||||
level = Log4jLevel.valueOf(attributes.getValue("level"));
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
level = Log4jLevel.INFO;
|
|
||||||
}
|
|
||||||
thread = attributes.getValue("thread");
|
|
||||||
logger = attributes.getValue("logger");
|
|
||||||
if ("STDERR".equals(logger))
|
|
||||||
level = Log4jLevel.ERROR;
|
|
||||||
break;
|
|
||||||
case "log4j_Message":
|
|
||||||
readingMessage = true;
|
|
||||||
break;
|
|
||||||
case "log4j_Throwable":
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endElement(String uri, String localName, String qName) {
|
|
||||||
switch (localName) {
|
|
||||||
case "log4j_Event":
|
|
||||||
callback.accept("[" + date + "] [" + thread + "/" + level.name() + "] [" + logger + "] " + message.toString(), level);
|
|
||||||
break;
|
|
||||||
case "log4j_Message":
|
|
||||||
readingMessage = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void characters(char[] ch, int start, int length) {
|
|
||||||
String line = new String(ch, start, length);
|
|
||||||
if (line.trim().isEmpty())
|
|
||||||
return;
|
|
||||||
if (readingMessage)
|
|
||||||
message.append(line).append(OperatingSystem.LINE_SEPARATOR);
|
|
||||||
else
|
|
||||||
callback.accept(line, Optional.ofNullable(Log4jLevel.guessLevel(line)).orElse(Log4jLevel.INFO));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user