diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java index c1798ad80..852edc888 100755 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameSettingsPanel.java @@ -187,7 +187,7 @@ public final class GameSettingsPanel extends RepaintPage implements DropTargetLi itm = new JMenuItem(C.i18n("versions.manage.redownload_json")); itm.addActionListener((e) -> { if (mcVersion != null) - Settings.getLastProfile().service().download().downloadMinecraftVersionJson(mcVersion); + TaskWindow.factory().execute(Settings.getLastProfile().service().download().downloadMinecraftVersionJson(mcVersion)); }); ppmManage.add(itm); itm = new JMenuItem(C.i18n("versions.manage.redownload_assets_index")); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/JLineWrapTextPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/JLineWrapTextPane.java new file mode 100644 index 000000000..3223aede7 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/JLineWrapTextPane.java @@ -0,0 +1,101 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * 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.ui; + +import javax.swing.JTextPane; +import javax.swing.text.AbstractDocument; +import javax.swing.text.BoxView; +import javax.swing.text.ComponentView; +import javax.swing.text.Element; +import javax.swing.text.IconView; +import javax.swing.text.LabelView; +import javax.swing.text.ParagraphView; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledEditorKit; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; + +/** + * + * @author huang + */ +public class JLineWrapTextPane extends JTextPane { + + // 内部类 + // 以下内部类全都用于实现自动强制折行 + + private class WarpEditorKit extends StyledEditorKit { + + private ViewFactory defaultFactory = new WarpColumnFactory(); + + @Override + public ViewFactory getViewFactory() { + return defaultFactory; + } + } + + private class WarpColumnFactory implements ViewFactory { + + public View create(Element elem) { + String kind = elem.getName(); + if (kind != null) { + if (kind.equals(AbstractDocument.ContentElementName)) { + return new WarpLabelView(elem); + } else if (kind.equals(AbstractDocument.ParagraphElementName)) { + return new ParagraphView(elem); + } else if (kind.equals(AbstractDocument.SectionElementName)) { + return new BoxView(elem, View.Y_AXIS); + } else if (kind.equals(StyleConstants.ComponentElementName)) { + return new ComponentView(elem); + } else if (kind.equals(StyleConstants.IconElementName)) { + return new IconView(elem); + } + } + + // default to text display + return new LabelView(elem); + } + } + + private class WarpLabelView extends LabelView { + + public WarpLabelView(Element elem) { + super(elem); + } + + @Override + public float getMinimumSpan(int axis) { + switch (axis) { + case View.X_AXIS: + return 0; + case View.Y_AXIS: + return super.getMinimumSpan(axis); + default: + throw new IllegalArgumentException("Invalid axis: " + axis); + } + } + } + + // 本类 + + // 构造函数 + public JLineWrapTextPane() { + super(); + this.setEditorKit(new WarpEditorKit()); + } +} 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 34ac90e18..1b1686ec0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LaunchingUIDaemon.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui; import java.io.File; import java.io.IOException; +import java.io.PipedOutputStream; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.jackhuang.hmcl.api.HMCLApi; @@ -40,15 +41,19 @@ import org.jackhuang.hmcl.api.func.Consumer; import org.jackhuang.hmcl.api.HMCLog; import org.jackhuang.hmcl.api.event.launch.LaunchingState; import org.jackhuang.hmcl.util.DefaultPlugin; +import org.jackhuang.hmcl.util.Log4jHandler; import org.jackhuang.hmcl.util.sys.FileUtils; import org.jackhuang.hmcl.util.sys.PrintlnEvent; import org.jackhuang.hmcl.util.sys.ProcessMonitor; +import org.xml.sax.XMLReader; /** * * @author huangyuhui */ public class LaunchingUIDaemon { + + XMLReader reader; public LaunchingUIDaemon() { HMCLApi.EVENT_BUS.channel(LaunchingStateChangedEvent.class).register(LAUNCHING_STATE_CHANGED); @@ -68,8 +73,15 @@ public class LaunchingUIDaemon { // We promise that JavaProcessMonitor.tag is LauncherVisibility // See events below. ProcessMonitor monitor = new ProcessMonitor(p.getValue()); - monitor.registerPrintlnEvent(PRINTLN); + PipedOutputStream os = new PipedOutputStream(); monitor.setTag(obj); + try { + Log4jHandler handler = new Log4jHandler(os); + handler.start(); + } catch(Exception e) { + HMCLog.err("", e); + } + monitor.registerPrintlnEvent(new PrintlnProcessor(obj, os)); monitor.start(); }); HMCLApi.EVENT_BUS.channel(LaunchSucceededEvent.class).register(p -> { @@ -145,19 +157,39 @@ public class LaunchingUIDaemon { ((HMCLGameLauncher.GameLauncherTag) value.getTag()).state = 2; }, MainFrame.INSTANCE::failed, Settings.getInstance().getAuthenticator().getPassword()); } + + class PrintlnProcessor implements Consumer { + + GameLauncher launcher; + PipedOutputStream os; - private static final Consumer PRINTLN = t -> { - GameLauncher launcher = ((GameLauncher) ((ProcessMonitor) t.getSource()).getTag()); - HMCLGameLauncher.GameLauncherTag tag = (HMCLGameLauncher.GameLauncherTag) launcher.getTag(); - LauncherVisibility l = tag.launcherVisibility; - if (t.getLine().contains("LWJGL Version: ") && l != LauncherVisibility.KEEP) - if (l != LauncherVisibility.HIDE_AND_REOPEN) - MainFrame.INSTANCE.dispose(); - else { // If current state is 'hide and reopen', closes the main window and reset the state to normal. - MainFrame.INSTANCE.setVisible(false); - HMCLApi.EVENT_BUS.fireChannel(new LaunchingStateChangedEvent(launcher, LaunchingState.Done)); - } - }; + public PrintlnProcessor(GameLauncher launcher, PipedOutputStream os) { + this.launcher = launcher; + this.os = os; + } + + @Override + public void accept(PrintlnEvent t) { + if (!t.isError()) + try { + os.write((t.getLine() + C.LINE_SEPARATOR).replace("log4j:Event", "log4j_Event").replace("log4j:Message", "log4j_Message").getBytes()); + os.flush(); + } catch(IOException e) { + HMCLog.err("", e); + } + else System.err.println(t.getLine()); + HMCLGameLauncher.GameLauncherTag tag = (HMCLGameLauncher.GameLauncherTag) launcher.getTag(); + LauncherVisibility l = tag.launcherVisibility; + if (t.getLine().contains("LWJGL Version: ") && l != LauncherVisibility.KEEP) + if (l != LauncherVisibility.HIDE_AND_REOPEN) + MainFrame.INSTANCE.dispose(); + else { // If current state is 'hide and reopen', closes the main window and reset the state to normal. + MainFrame.INSTANCE.setVisible(false); + HMCLApi.EVENT_BUS.fireChannel(new LaunchingStateChangedEvent(launcher, LaunchingState.Done)); + } + } + + } private static final Consumer LAUNCHING_STATE_CHANGED = t -> { String message = null; @@ -217,4 +249,5 @@ public class LaunchingUIDaemon { } MainFrame.INSTANCE.closeMessage(); }; + } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form index 3b02342c2..2291ba0f5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.form @@ -32,10 +32,9 @@ - - + @@ -60,6 +59,7 @@ + @@ -161,6 +161,9 @@ + + + diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java index b49a86c3a..810de1071 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindow.java @@ -39,7 +39,8 @@ import org.jackhuang.hmcl.util.ui.SwingUtils; * @author huangyuhui */ public class LogWindow extends javax.swing.JFrame { - + public static LogWindowOutputStream outputStream; + NonFunction listener; /** @@ -48,7 +49,7 @@ public class LogWindow extends javax.swing.JFrame { public LogWindow() { initComponents(); - DoubleOutputStream out = new DoubleOutputStream(new LogWindowOutputStream(this, Level.INFO), System.out); + DoubleOutputStream out = new DoubleOutputStream(outputStream = new LogWindowOutputStream(this, Level.INFO), System.out); System.setOut(new PrintStream(out)); DoubleOutputStream err = new DoubleOutputStream(new LogWindowOutputStream(this, Level.ERROR), System.err); System.setErr(new PrintStream(err)); @@ -78,7 +79,7 @@ public class LogWindow extends javax.swing.JFrame { btnContact = new javax.swing.JButton(); btnTerminateGame = new javax.swing.JButton(); pnlLog = new javax.swing.JScrollPane(); - txtLog = new javax.swing.JTextPane(); + txtLog = new JLineWrapTextPane(); jLabel1 = new javax.swing.JLabel(); cboShowLines = new javax.swing.JComboBox<>(); btnDebug = new javax.swing.JToggleButton(); @@ -161,10 +162,9 @@ public class LogWindow extends javax.swing.JFrame { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnlLog, javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addComponent(btnContact) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 183, Short.MAX_VALUE) .addComponent(btnTerminateGame) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnCopy) @@ -186,7 +186,8 @@ public class LogWindow extends javax.swing.JFrame { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnInfo) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnDebug))) + .addComponent(btnDebug)) + .addComponent(pnlLog)) .addContainerGap()) ); layout.setVerticalGroup( diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java index b9d8dd901..a52503347 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LogWindowOutputStream.java @@ -50,6 +50,9 @@ public class LogWindowOutputStream extends OutputStream { Level lastLevel = null; private void append(final String str) { + synchronized(this) { + if (manual) return; + } SwingUtilities.invokeLater(() -> { Level level = Level.guessLevel(str); if (level == null) level = lastLevel; @@ -62,4 +65,19 @@ public class LogWindowOutputStream extends OutputStream { public final void write(int i) { append(new String(new byte[] { (byte) i })); } -} + + boolean manual = false; + + public void log(String s, Level l) { + synchronized(this) { + manual = true; + System.out.print(s); + manual = false; + } + if (l == null) append(s); + else + SwingUtilities.invokeLater(() -> { + txt.log(s, l); + }); + } +} \ No newline at end of file diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftLoader.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftLoader.java new file mode 100644 index 000000000..69ba369e0 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftLoader.java @@ -0,0 +1,45 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * 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; + +import java.util.List; +import org.jackhuang.hmcl.Main; +import org.jackhuang.hmcl.api.auth.UserProfileProvider; +import org.jackhuang.hmcl.api.game.LaunchOptions; +import org.jackhuang.hmcl.core.GameException; +import org.jackhuang.hmcl.core.launch.MinecraftLoader; +import org.jackhuang.hmcl.core.service.IMinecraftService; + +/** + * + * @author huang + */ +public class HMCLMinecraftLoader extends MinecraftLoader { + + public HMCLMinecraftLoader(LaunchOptions p, IMinecraftService provider, UserProfileProvider lr) throws GameException { + super(p, provider, lr); + } + + @Override + protected void appendJVMArgs(List list) { + super.appendJVMArgs(list); + + list.add("-Dminecraft.launcher.version=" + Main.LAUNCHER_VERSION); + list.add("-Dminecraft.launcher.brand=" + Main.LAUNCHER_NAME); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftService.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftService.java index 9780f6ec5..a59611be5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftService.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/HMCLMinecraftService.java @@ -175,7 +175,7 @@ public class HMCLMinecraftService extends IMinecraftService { @Override public IMinecraftLoader launch(LaunchOptions options, UserProfileProvider p) throws GameException { - MinecraftLoader l = new MinecraftLoader(options, this, p); + MinecraftLoader l = new HMCLMinecraftLoader(options, this, p); l.setAssetProvider(mas.ASSET_PROVIDER_IMPL); return l; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java new file mode 100644 index 000000000..2e075b49f --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/Log4jHandler.java @@ -0,0 +1,124 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * 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; + +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import javax.xml.parsers.ParserConfigurationException; +import org.jackhuang.hmcl.ui.LogWindow; +import org.jackhuang.hmcl.util.log.Level; +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; + +/** + * + * @author huang + */ +public class Log4jHandler extends Thread { + + XMLReader reader; + PipedInputStream inputStream; + PipedOutputStream outputStream; + + public Log4jHandler(PipedOutputStream outputStream) throws ParserConfigurationException, IOException, SAXException { + /*SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + .*/ + reader = XMLReaderFactory.createXMLReader(); + inputStream = new PipedInputStream(outputStream); + this.outputStream = outputStream; + } + + @Override + public void run() { + try { + outputStream.write("".getBytes()); + outputStream.flush(); + //reader.parse(inputStream, new Log4jHandlerImpl()); + reader.setContentHandler(new Log4jHandlerImpl()); + reader.parse(new InputSource(inputStream)); + } catch (SAXException | IOException e) { + + } + } + + class Log4jHandlerImpl extends DefaultHandler { + private final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); + + String message = "", date = "", thread = "", logger = ""; + Level l = null; + boolean readingMessage = false; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + switch (localName) { + case "log4j_Event": + message = ""; + Date d = new Date(Long.valueOf(attributes.getValue("timestamp"))); + date = df.format(d); + try { + l = Level.valueOf(attributes.getValue("level")); + } catch(IllegalArgumentException e) { + l = Level.INFO; + } + thread = attributes.getValue("thread"); + logger = attributes.getValue("logger"); + if ("STDERR".equals(logger)) + l = Level.ERROR; + break; + case "log4j_Message": + readingMessage = true; + break; + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + switch (localName) { + case "log4j_Event": + println("[" + date + "] [" + thread + "/" + l.name() + "] [" + logger + "] " + message, l); + break; + case "log4j_Message": + readingMessage = false; + break; + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + String line = new String(ch, start, length); + if (line.trim().isEmpty()) return; + if (readingMessage) + message += line + C.LINE_SEPARATOR; + else + println(line, Level.guessLevel(line)); + } + + public void println(String message, Level l) { + if (LogWindow.outputStream != null) + LogWindow.outputStream.log(message, l); + } + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/asset/MinecraftAssetService.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/asset/MinecraftAssetService.java index 55d64b547..ff569d270 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/asset/MinecraftAssetService.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/asset/MinecraftAssetService.java @@ -32,10 +32,12 @@ import org.jackhuang.hmcl.core.version.AssetIndexDownloadInfo; import org.jackhuang.hmcl.core.version.MinecraftVersion; import org.jackhuang.hmcl.util.MessageBox; import org.jackhuang.hmcl.api.HMCLog; +import org.jackhuang.hmcl.core.version.LoggingInfo; import org.jackhuang.hmcl.util.task.Task; import org.jackhuang.hmcl.util.task.TaskWindow; import org.jackhuang.hmcl.util.net.FileDownloadTask; import org.jackhuang.hmcl.util.sys.FileUtils; +import org.jackhuang.hmcl.util.task.ParallelTask; import org.jackhuang.hmcl.util.task.TaskInfo; /** @@ -56,7 +58,21 @@ public class MinecraftAssetService extends IMinecraftAssetService { public Task downloadAssets(final MinecraftVersion mv) throws GameException { if (mv == null) return null; - return IAssetsHandler.ASSETS_HANDLER.getList(mv.resolve(service.version()), service.asset()).with(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(service.getDownloadType().getProvider())); + Task task = IAssetsHandler.ASSETS_HANDLER.getList(mv.resolve(service.version()), service.asset()) + .with(IAssetsHandler.ASSETS_HANDLER.getDownloadTask(service.getDownloadType().getProvider())); + if (mv.logging != null && mv.logging.containsKey("client")) { + LoggingInfo info = mv.logging.get("client"); + File file = getLoggingObject(mv.assetIndex.getId(), info); + if (!file.exists()) + return new ParallelTask().addTask(task) + .addTask(new FileDownloadTask(info.file.url, file, info.file.sha1)); + } + return task; + } + + @Override + public File getLoggingObject(String assetId, LoggingInfo logging) { + return new File(getAssets(assetId), "log_configs/" + logging.file.getId()); } @Override @@ -143,7 +159,7 @@ public class MinecraftAssetService extends IMinecraftAssetService { } } - protected boolean checkAssetsExistance(AssetIndexDownloadInfo assetIndex) { + protected boolean checkAssetsExistance(AssetIndexDownloadInfo assetIndex, LoggingInfo info) { String assetId = assetIndex.getId(); File indexFile = getIndexFile(assetId); File assetDir = getAssets(assetId); @@ -157,6 +173,10 @@ public class MinecraftAssetService extends IMinecraftAssetService { if (index == null) return false; + + if (info != null && !getLoggingObject(assetId, info).exists()) + return false; + for (Map.Entry entry : index.getFileMap().entrySet()) if (!assetObjectPath(assetDir, (AssetsObject) entry.getValue()).exists()) return false; @@ -217,7 +237,10 @@ public class MinecraftAssetService extends IMinecraftAssetService { } public final IAssetProvider ASSET_PROVIDER_IMPL = (t, allow) -> { - if (allow && !checkAssetsExistance(t.getAssetsIndex())) + LoggingInfo logging = null; + if (t.logging != null) + logging = t.logging.get("client"); + if (allow && !checkAssetsExistance(t.getAssetsIndex(), logging)) if (MessageBox.show(C.i18n("assets.no_assets"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) TaskWindow.factory().execute(downloadAssets(t)); return reconstructAssets(t.getAssetsIndex()).getAbsolutePath(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/MinecraftLoader.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/MinecraftLoader.java index f82889ce9..d096830e2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/MinecraftLoader.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/launch/MinecraftLoader.java @@ -30,6 +30,7 @@ import org.jackhuang.hmcl.core.GameException; import org.jackhuang.hmcl.api.auth.UserProfileProvider; import org.jackhuang.hmcl.core.version.MinecraftLibrary; import org.jackhuang.hmcl.core.service.IMinecraftService; +import org.jackhuang.hmcl.core.version.LoggingInfo; /** * @@ -111,6 +112,15 @@ public class MinecraftLoader extends AbstractMinecraftLoader { } catch (IOException e) { HMCLog.err("Failed to append jvm arguments when searching for asset objects.", e); } + + list.add("-Dminecraft.client.jar=" + version.getJar(service.baseDirectory()).getAbsolutePath()); + + if (version.logging != null && version.logging.containsKey("client")) { + LoggingInfo logging = version.logging.get("client"); + File file = service.asset().getLoggingObject(version.getAssetsIndex().getId(), logging); + if (file.exists()) + list.add(logging.argument.replace("${path}", file.getAbsolutePath())); + } } private final IAssetProvider DEFAULT_ASSET_PROVIDER = (t, allow) -> { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/service/IMinecraftAssetService.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/service/IMinecraftAssetService.java index 030ae0f1a..3c1dcc4d5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/service/IMinecraftAssetService.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/service/IMinecraftAssetService.java @@ -22,6 +22,7 @@ import java.io.IOException; import org.jackhuang.hmcl.core.GameException; import org.jackhuang.hmcl.core.asset.AssetsObject; import org.jackhuang.hmcl.core.version.AssetIndexDownloadInfo; +import org.jackhuang.hmcl.core.version.LoggingInfo; import org.jackhuang.hmcl.util.task.Task; /** @@ -56,4 +57,6 @@ public abstract class IMinecraftAssetService extends IMinecraftBasicService { public abstract File getAssetObject(String assetVersion, String name) throws IOException; public abstract File getAssetObject(String assetId, AssetsObject assetsObject); + + public abstract File getLoggingObject(String assetId, LoggingInfo id); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/GameDownloadInfo.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/GameDownloadInfo.java index f3cf2e508..43b7dada5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/GameDownloadInfo.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/GameDownloadInfo.java @@ -36,7 +36,9 @@ public class GameDownloadInfo implements Cloneable { /** * Ready for AssetIndexDownloadInfo, and GameDownloadInfo also need this. + * And LoggingInfo will have this field in json. */ + @SerializedName("id") protected String id; /** diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/LoggingInfo.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/LoggingInfo.java new file mode 100644 index 000000000..a9aae5e7d --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/LoggingInfo.java @@ -0,0 +1,41 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * 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.core.version; + +/** + * + * @author huang + */ +public class LoggingInfo implements Cloneable { + public GameDownloadInfo file; + public String argument; + public String type; + + @Override + public Object clone() { + try { + LoggingInfo info = (LoggingInfo) super.clone(); + info.file = (GameDownloadInfo) file.clone(); + return info; + } catch(CloneNotSupportedException e) { + throw new Error(e); + } + } + + +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/MinecraftVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/MinecraftVersion.java index 438746ddf..504fd423b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/MinecraftVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/core/version/MinecraftVersion.java @@ -73,11 +73,13 @@ public class MinecraftVersion implements Cloneable, Comparable private Map downloads; @SerializedName("libraries") public ArrayList libraries; + @SerializedName("logging") + public Map logging; public MinecraftVersion() { } - public MinecraftVersion(String minecraftArguments, String mainClass, String time, String id, String type, String processArguments, String releaseTime, String assets, String jar, String inheritsFrom, String runDir, int minimumLauncherVersion, List libraries, boolean hidden, Map downloads, AssetIndexDownloadInfo assetIndexDownloadInfo) { + public MinecraftVersion(String minecraftArguments, String mainClass, String time, String id, String type, String processArguments, String releaseTime, String assets, String jar, String inheritsFrom, String runDir, int minimumLauncherVersion, List libraries, boolean hidden, Map downloads, AssetIndexDownloadInfo assetIndexDownloadInfo, Map logging) { this(); this.minecraftArguments = minecraftArguments; this.mainClass = mainClass; @@ -111,6 +113,13 @@ public class MinecraftVersion implements Cloneable, Comparable for (Map.Entry entry : downloads.entrySet()) this.downloads.put(entry.getKey(), (GameDownloadInfo) entry.getValue().clone()); } + if (logging == null) + this.logging = null; + else { + this.logging = new HashMap<>(logging.size()); + for (Map.Entry entry : logging.entrySet()) + this.logging.put(entry.getKey(), (LoggingInfo) entry.getValue().clone()); + } } @Override @@ -150,7 +159,8 @@ public class MinecraftVersion implements Cloneable, Comparable null, this.runDir, parent.minimumLauncherVersion, this.libraries != null ? ArrayUtils.merge(this.libraries, parent.libraries) : parent.libraries, this.hidden, this.downloads != null ? this.downloads : parent.downloads, - this.assetIndex != null ? this.assetIndex : parent.assetIndex); + this.assetIndex != null ? this.assetIndex : parent.assetIndex, + this.logging != null ? this.logging : parent.logging); return result; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/C.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/C.java index e9c3924cd..ff34d3665 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/C.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/C.java @@ -35,6 +35,8 @@ public final class C { public static final String URL_FORGE_LIST = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json"; public static final String URL_LITELOADER_LIST = "http://dl.liteloader.com/versions/versions.json"; + + public static final String LINE_SEPARATOR = System.getProperty("line.separator"); private C() { } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Parser.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Parser.java new file mode 100644 index 000000000..6ba5b2491 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/log/Parser.java @@ -0,0 +1,26 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2013 huangyuhui + * + * 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.log; + +/** + * + * @author huang + */ +public class Parser { + +} 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 c990eeb69..e74c480f8 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 @@ -86,7 +86,6 @@ public class ProcessThread extends Thread { protected void println(String line) { printlnEvent.fire(new PrintlnEvent(monitor, line, readError)); - (readError ? System.err : System.out).println(line); lines.add(line); p.getStdOutLines().add(line); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/DoubleTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/DoubleTask.java index f89a4e123..2bd7d2fa5 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/DoubleTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/DoubleTask.java @@ -27,15 +27,21 @@ import java.util.Collection; public class DoubleTask extends TaskInfo { Task a, b; + boolean reliant; public DoubleTask(Task a, Task b) { - this(a, b, "Double Task"); + this(a, b, true); } - public DoubleTask(Task a, Task b, String info) { + public DoubleTask(Task a, Task b, boolean reliant) { + this(a, b, "Double Task", reliant); + } + + public DoubleTask(Task a, Task b, String info, boolean reliant) { super(info); this.a = a; this.b = b; + this.reliant = reliant; hidden = true; } @@ -51,7 +57,7 @@ public class DoubleTask extends TaskInfo { @Override public void executeTask(boolean areDependTasksSucceeded) throws IllegalStateException { - if (!areDependTasksSucceeded) + if (!areDependTasksSucceeded && reliant) throw new IllegalStateException("Depend tasks failed."); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/ParallelTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/ParallelTask.java index 94ef9c824..2cbffa361 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/ParallelTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/task/ParallelTask.java @@ -48,8 +48,9 @@ public class ParallelTask extends Task { return tasks; } - public void addTask(Task t) { + public ParallelTask addTask(Task t) { tasks.add(t); + return this; } } diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.lang b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.lang index 911a31c2a..84a79fc46 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.lang +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.lang @@ -390,8 +390,8 @@ update.failed=Failed to check for updates. update.found=(Found Update!) logwindow.terminate_game=Terminate Game -logwindow.tieba=Baidu Tieba logwindow.title=Log +logwindow.contact=Contact Us selector.choose=Choose diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.properties b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.properties index d0eb913a8..e9b21b99a 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.properties +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N.properties @@ -390,8 +390,8 @@ update.failed=Failed to check for updates. update.found=(Found Update!) logwindow.terminate_game=Terminate Game -logwindow.tieba=Baidu Tieba logwindow.title=Log +logwindow.contact=Contact Us selector.choose=Choose @@ -433,4 +433,3 @@ wizard.steps=Steps lang=English lang.default=Belong to OS language. -logwindow.contact=Contact Us diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.lang b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.lang index fc750306a..b8a9af3f6 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.lang +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.lang @@ -388,8 +388,8 @@ update.failed=Kiểm tra cập nhật thất bại. update.found=(Đã tìm thấy bản cập nhật!) logwindow.terminate_game=Tắt Game -logwindow.tieba=Baidu Tieba logwindow.title=HMCL Error Log (Hãy đăng cái này lên forum!) +logwindow.contact=Contact Us selector.choose=Chọn diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.properties b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.properties index c014c58bf..7152ce868 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.properties +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_vi.properties @@ -388,8 +388,8 @@ update.failed=Ki\u1ec3m tra c\u1eadp nh\u1eadt th\u1ea5t b\u1ea1i. update.found=(\u0110\u00e3 t\u00ecm th\u1ea5y b\u1ea3n c\u1eadp nh\u1eadt!) logwindow.terminate_game=T\u1eaft Game -logwindow.tieba=Baidu Tieba logwindow.title=HMCL Error Log (H\u00e3y \u0111\u0103ng c\u00e1i n\u00e0y l\u00ean forum!) +logwindow.contact=Contact Us selector.choose=Ch\u1ecdn diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.lang b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.lang index 9dc15a08b..158d41a4e 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.lang +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.lang @@ -390,8 +390,8 @@ update.failed=檢查更新失敗 update.found=(發現更新!) logwindow.terminate_game=結束遊戲進程 -logwindow.tieba=貼吧 logwindow.title=日誌 +logwindow.contact=聯繫我們 selector.choose=選擇 diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.properties b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.properties index 316efac0a..dcf78019e 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.properties +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh.properties @@ -390,8 +390,8 @@ update.failed=\u6aa2\u67e5\u66f4\u65b0\u5931\u6557 update.found=(\u767c\u73fe\u66f4\u65b0!) logwindow.terminate_game=\u7d50\u675f\u904a\u6232\u9032\u7a0b -logwindow.tieba=\u8cbc\u5427 logwindow.title=\u65e5\u8a8c +logwindow.contact=\u806f\u7e6b\u6211\u5011 selector.choose=\u9078\u64c7 diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.lang b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.lang index 77803ea81..c041f9d99 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.lang +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.lang @@ -390,8 +390,8 @@ update.failed=检查更新失败 update.found=(发现更新!) logwindow.terminate_game=结束游戏进程 -logwindow.tieba=贴吧 logwindow.title=日志 +logwindow.contact=联系我们 selector.choose=选择 diff --git a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.properties b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.properties index b4e0058be..12d8fb306 100644 --- a/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.properties +++ b/HMCLCore/src/main/resources/org/jackhuang/hmcl/lang/I18N_zh_CN.properties @@ -390,8 +390,8 @@ update.failed=\u68c0\u67e5\u66f4\u65b0\u5931\u8d25 update.found=(\u53d1\u73b0\u66f4\u65b0!) logwindow.terminate_game=\u7ed3\u675f\u6e38\u620f\u8fdb\u7a0b -logwindow.tieba=\u8d34\u5427 logwindow.title=\u65e5\u5fd7 +logwindow.contact=\u8054\u7cfb\u6211\u4eec selector.choose=\u9009\u62e9