diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java b/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java index 8ab8260fc4e..71ec791dc27 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/countly/CrashReport.java @@ -18,29 +18,13 @@ package org.jackhuang.hmcl.countly; import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -public class CrashReport { - - private final Thread thread; - private final Throwable throwable; - private final String stackTrace; - - public CrashReport(Thread thread, Throwable throwable) { - this.thread = thread; - this.throwable = throwable; - stackTrace = StringUtils.getStackTrace(throwable); - } - - public Throwable getThrowable() { - return this.throwable; - } - +public record CrashReport(Thread thread, Throwable throwable, String stackTrace) { public boolean shouldBeReport() { if (!stackTrace.contains("org.jackhuang")) return false; @@ -52,20 +36,20 @@ public boolean shouldBeReport() { } public String getDisplayText() { - return "---- Hello Minecraft! Crash Report ----\n" + - " Version: " + Metadata.VERSION + "\n" + - " Time: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) + "\n" + - " Thread: " + thread + "\n" + - "\n Content: \n " + - stackTrace + "\n\n" + + return "---- Hello Minecraft! Launcher Crash Report ----\n" + + "Version: " + Metadata.VERSION + "\n" + + "Time: " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) + "\n" + + "Thread: " + thread + "\n" + + "\nContent: \n" + + stackTrace + "\n" + "-- System Details --\n" + - " Operating System: " + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION.getVersion() + "\n" + - " System Architecture: " + Architecture.SYSTEM_ARCH.getDisplayName() + "\n" + - " Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n" + - " Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n" + - " Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n" + - " JVM Max Memory: " + Runtime.getRuntime().maxMemory() + "\n" + - " JVM Total Memory: " + Runtime.getRuntime().totalMemory() + "\n" + - " JVM Free Memory: " + Runtime.getRuntime().freeMemory() + "\n"; + "Operating System: " + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION.getVersion() + "\n" + + "System Architecture: " + Architecture.SYSTEM_ARCH.getDisplayName() + "\n" + + "Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n" + + "Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n" + + "Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n" + + "JVM Max Memory: " + Runtime.getRuntime().maxMemory() + "\n" + + "JVM Total Memory: " + Runtime.getRuntime().totalMemory() + "\n" + + "JVM Free Memory: " + Runtime.getRuntime().freeMemory() + "\n"; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java index 5af27b6a601..130503faabe 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/CrashWindow.java @@ -17,11 +17,10 @@ */ package org.jackhuang.hmcl.ui; +import javafx.application.Platform; import javafx.geometry.Pos; import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.TextArea; +import javafx.scene.control.*; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; @@ -29,34 +28,69 @@ import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.countly.CrashReport; import org.jackhuang.hmcl.upgrade.UpdateChecker; +import org.jackhuang.hmcl.util.LauncherLogExporter; +import org.jackhuang.hmcl.util.Lazy; +import org.jackhuang.hmcl.util.StringUtils; + +import java.io.IOException; +import java.nio.file.Path; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; /** * @author huangyuhui */ -public class CrashWindow extends Stage { +public final class CrashWindow extends Stage { + private static final Lazy instance = new Lazy<>(CrashWindow::new); + + public static CrashWindow getInstance() { + return instance.get(); + } - public CrashWindow(CrashReport report) { + private final TextArea textArea = new TextArea(); + + private CrashWindow() { Label lblCrash = new Label(); - if (report.getThrowable() instanceof InternalError) - lblCrash.setText(i18n("launcher.crash.java_internal_error")); - else if (UpdateChecker.isOutdated()) + lblCrash.setWrapText(true); + + if (UpdateChecker.isOutdated()) { lblCrash.setText(i18n("launcher.crash.hmcl_out_dated")); - else + } else { lblCrash.setText(i18n("launcher.crash")); - lblCrash.setWrapText(true); + } - TextArea textArea = new TextArea(); - textArea.setText(report.getDisplayText()); - textArea.setEditable(false); + StackPane exportPane = new StackPane(); + ProgressIndicator progressIndicator = new ProgressIndicator(); + FXUtils.setLimitHeight(progressIndicator, 20); + + Button btnExport = new Button(); + exportPane.getChildren().setAll(btnExport); + btnExport.setText(i18n("settings.launcher.launcher_log.export")); + btnExport.setOnAction(event -> { + exportPane.getChildren().setAll(progressIndicator); + try { + Path path = LauncherLogExporter.exportLogsAsZip(); + FXUtils.showFileInExplorer(path); + Alert alert = new Alert(Alert.AlertType.INFORMATION, i18n("settings.launcher.launcher_log.export.success", path)); + alert.setTitle(i18n("settings.launcher.launcher_log.export")); + alert.showAndWait(); + } catch (IOException e) { + LOG.warning("Failed to export launcher logs", e); + Alert alert = new Alert(Alert.AlertType.WARNING, i18n("settings.launcher.launcher_log.export.failed") + "\n" + StringUtils.getStackTrace(e)); + alert.setTitle(i18n("message.error")); + alert.setContentText(StringUtils.getStackTrace(e)); + alert.showAndWait(); + } + exportPane.getChildren().setAll(btnExport); + }); Button btnContact = new Button(); btnContact.setText(i18n("launcher.contact")); btnContact.setOnAction(event -> FXUtils.openLink(Metadata.CONTACT_URL)); - HBox box = new HBox(); + HBox box = new HBox(8); box.setStyle("-fx-padding: 8px;"); - box.getChildren().add(btnContact); + box.getChildren().setAll(exportPane, btnContact); box.setAlignment(Pos.CENTER_RIGHT); BorderPane pane = new BorderPane(); @@ -72,7 +106,12 @@ else if (UpdateChecker.isOutdated()) FXUtils.setIcon(this); setTitle(i18n("message.error")); - setOnCloseRequest(e -> javafx.application.Platform.exit()); + setOnCloseRequest(e -> Platform.exit()); } + public void addCrashReport(CrashReport report) { + textArea.setText(textArea.getText() + "\n\n" + report.getDisplayText()); + textArea.setEditable(false); + this.requestFocus(); + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java index 52c32536af8..7bab18073db 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java @@ -44,8 +44,8 @@ import javafx.scene.text.TextFlow; import javafx.util.Duration; import org.jackhuang.hmcl.Metadata; -import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.ComponentVersionList; +import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.setting.DownloadProviders; import org.jackhuang.hmcl.setting.GameDirectoryManager; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index ee8ea5593cf..cc22a3ba8c7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -30,7 +30,6 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; @@ -42,27 +41,13 @@ import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.upgrade.UpdateHandler; import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.LauncherLogExporter; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.SupportedLocale; -import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.io.IOUtils; -import org.tukaani.xz.XZInputStream; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.HashSet; + import java.util.List; -import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.zip.GZIPInputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; import static org.jackhuang.hmcl.setting.SettingsManager.settings; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -221,7 +206,7 @@ else if (locale.isSameLanguage(currentLocale)) exportLogPane.setContent(logButton); logButton.setOnAction(e -> { exportLogPane.showSpinner(); - onExportLogs().whenCompleteAsync((result, exception) -> { + CompletableFuture.supplyAsync(Lang.wrap(LauncherLogExporter::exportLogsAsZip), Schedulers.io()).whenCompleteAsync((result, exception) -> { exportLogPane.hideSpinner(); if (exception == null) { Controllers.dialog(i18n("settings.launcher.launcher_log.export.success", result)); @@ -262,128 +247,4 @@ private void onUpdate() { } UpdateHandler.updateFrom(target); } - - private static String getEntryName(Set entryNames, String name) { - if (entryNames.add(name)) { - return name; - } - - for (long i = 1; ; i++) { - String newName = name + "." + i; - if (entryNames.add(newName)) { - return newName; - } - } - } - - /// This method guarantees to close both `input` and the current zip entry. - /// - /// If no exception occurs, this method returns `true`; - /// If an exception occurs while reading from `input`, this method returns `false`; - /// If an exception occurs while writing to `output`, this method will throw it as is. - private static boolean exportLogFile(ZipOutputStream output, - Path file, // For logging - String entryName, - InputStream input, - byte[] buffer) throws IOException { - //noinspection TryFinallyCanBeTryWithResources - try { - output.putNextEntry(new ZipEntry(entryName)); - int read; - while (true) { - try { - read = input.read(buffer); - if (read <= 0) - return true; - } catch (Throwable ex) { - LOG.warning("Failed to decompress log file " + file, ex); - return false; - } - - output.write(buffer, 0, read); - } - } finally { - try { - input.close(); - } catch (Throwable ex) { - LOG.warning("Failed to close log file " + file, ex); - } - output.closeEntry(); - } - } - - private CompletableFuture onExportLogs() { - return CompletableFuture.supplyAsync(Lang.wrap(() -> { - String nameBase = "hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")); - List recentLogFiles = LOG.findRecentLogFiles(5); - - Path outputFile; - if (recentLogFiles.isEmpty()) { - outputFile = Metadata.CURRENT_DIRECTORY.resolve(nameBase + ".log"); - - LOG.info("Exporting latest logs to " + outputFile); - try (OutputStream output = Files.newOutputStream(outputFile)) { - LOG.exportLogs(output); - } - } else { - outputFile = Metadata.CURRENT_DIRECTORY.resolve(nameBase + ".zip"); - - LOG.info("Exporting latest logs to " + outputFile); - - byte[] buffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE]; - try (var os = Files.newOutputStream(outputFile); - var zos = new ZipOutputStream(os)) { - - Set entryNames = new HashSet<>(); - - for (Path path : recentLogFiles) { - String fileName = FileUtils.getName(path); - String extension = StringUtils.substringAfterLast(fileName, '.'); - - if ("gz".equals(extension) || "xz".equals(extension)) { - // If an exception occurs while decompressing the input file, we should - // ensure the input file and the current zip entry are closed, - // then copy the compressed file content as-is into a new entry in the zip file. - - InputStream input = null; - try { - input = Files.newInputStream(path); - input = "gz".equals(extension) - ? new GZIPInputStream(input) - : new XZInputStream(input); - } catch (Throwable ex) { - LOG.warning("Failed to open log file " + path, ex); - IOUtils.closeQuietly(input, ex); - input = null; - } - - String entryName = getEntryName(entryNames, StringUtils.substringBeforeLast(fileName, ".")); - if (input != null && exportLogFile(zos, path, entryName, input, buffer)) - continue; - } - - // Copy the log file content as-is into a new entry in the zip file. - // If an exception occurs while decompressing the input file, we should - // ensure the input file and the current zip entry are closed. - - InputStream input; - try { - input = Files.newInputStream(path); - } catch (Throwable ex) { - LOG.warning("Failed to open log file " + path, ex); - continue; - } - - exportLogFile(zos, path, getEntryName(entryNames, fileName), input, buffer); - } - - zos.putNextEntry(new ZipEntry(getEntryName(entryNames, "hmcl-latest.log"))); - LOG.exportLogs(zos); - zos.closeEntry(); - } - } - - return outputFile; - }), Schedulers.io()); - } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java index 7cd54164d45..558c1e92196 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/CrashReporter.java @@ -18,63 +18,15 @@ package org.jackhuang.hmcl.util; import javafx.application.Platform; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; import org.jackhuang.hmcl.countly.CrashReport; -import org.jackhuang.hmcl.setting.SettingsManager; import org.jackhuang.hmcl.ui.CrashWindow; -import static org.jackhuang.hmcl.util.Pair.pair; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.logging.Logger.LOG; /** * @author huangyuhui */ public final class CrashReporter implements Thread.UncaughtExceptionHandler { - - // Lazy initialization resources - private static final class Hole { - @SuppressWarnings("unchecked") - static final Pair[] SOURCE = (Pair[]) new Pair[]{ - pair("Location is not set", i18n("crash.NoClassDefFound")), - pair("UnsatisfiedLinkError", i18n("crash.user_fault")), - pair("java.time.zone.ZoneRulesException: Unable to load TZDB time-zone rules", i18n("crash.user_fault")), - pair("java.lang.NoClassDefFoundError", i18n("crash.NoClassDefFound")), - pair("org.jackhuang.hmcl.util.ResourceNotFoundError", i18n("crash.NoClassDefFound")), - pair("java.lang.VerifyError", i18n("crash.NoClassDefFound")), - pair("java.lang.NoSuchMethodError", i18n("crash.NoClassDefFound")), - pair("java.lang.NoSuchFieldError", i18n("crash.NoClassDefFound")), - pair("javax.imageio.IIOException", i18n("crash.NoClassDefFound")), - pair("netscape.javascript.JSException", i18n("crash.NoClassDefFound")), - pair("java.lang.IncompatibleClassChangeError", i18n("crash.NoClassDefFound")), - pair("java.lang.ClassFormatError", i18n("crash.NoClassDefFound")), - pair("com.sun.javafx.css.StyleManager.findMatchingStyles", i18n("launcher.update_java")), - pair("NoSuchAlgorithmException", "Has your operating system been installed completely or is a ghost system?") - }; - } - - private boolean checkThrowable(Throwable e) { - String s = StringUtils.getStackTrace(e); - for (Pair entry : Hole.SOURCE) - if (s.contains(entry.getKey())) { - if (StringUtils.isNotBlank(entry.getValue())) { - String info = entry.getValue(); - LOG.error(info); - try { - Alert alert = new Alert(AlertType.INFORMATION, info); - alert.setTitle(i18n("message.info")); - alert.setHeaderText(i18n("message.info")); - alert.showAndWait(); - } catch (Throwable t) { - LOG.error("Unable to show message", t); - } - } - return false; - } - return true; - } - private final boolean showCrashWindow; public CrashReporter(boolean showCrashWindow) { @@ -86,23 +38,20 @@ public void uncaughtException(Thread t, Throwable e) { LOG.error("Uncaught exception in thread " + t.getName(), e); try { - CrashReport report = new CrashReport(t, e); + CrashReport report = new CrashReport(t, e, StringUtils.getStackTrace(e)); if (!report.shouldBeReport()) return; LOG.error(report.getDisplayText()); Platform.runLater(() -> { - if (checkThrowable(e)) { - if (showCrashWindow) { - new CrashWindow(report).show(); - } + if (showCrashWindow) { + var window = CrashWindow.getInstance(); + window.addCrashReport(report); + window.show(); } }); } catch (Throwable handlingException) { LOG.error("Unable to handle uncaught exception", handlingException); } - - SettingsManager.shutdown(); - LOG.shutdown(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/LauncherLogExporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/LauncherLogExporter.java new file mode 100644 index 00000000000..5c4752f87c9 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/LauncherLogExporter.java @@ -0,0 +1,167 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2026 huangyuhui and contributors + * + * 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 . + */ +package org.jackhuang.hmcl.util; + +import org.jackhuang.hmcl.Metadata; +import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.io.IOUtils; +import org.tukaani.xz.XZInputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.zip.GZIPInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + +public final class LauncherLogExporter { + private LauncherLogExporter() { + throw new AssertionError(); + } + + public static Path exportLogsAsZip() throws IOException { + String nameBase = "hmcl-exported-logs-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")); + List recentLogFiles = LOG.findRecentLogFiles(5); + + Path outputFile; + if (recentLogFiles.isEmpty()) { + outputFile = Metadata.CURRENT_DIRECTORY.resolve(nameBase + ".log"); + + LOG.info("Exporting latest logs to " + outputFile); + try (OutputStream output = Files.newOutputStream(outputFile)) { + LOG.exportLogs(output); + } + } else { + outputFile = Metadata.CURRENT_DIRECTORY.resolve(nameBase + ".zip"); + + LOG.info("Exporting latest logs to " + outputFile); + + byte[] buffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE]; + try (var os = Files.newOutputStream(outputFile); + var zos = new ZipOutputStream(os)) { + + Set entryNames = new HashSet<>(); + + for (Path path : recentLogFiles) { + String fileName = FileUtils.getName(path); + String extension = StringUtils.substringAfterLast(fileName, '.'); + + if ("gz".equals(extension) || "xz".equals(extension)) { + // If an exception occurs while decompressing the input file, we should + // ensure the input file and the current zip entry are closed, + // then copy the compressed file content as-is into a new entry in the zip file. + + InputStream input = null; + try { + input = Files.newInputStream(path); + input = "gz".equals(extension) + ? new GZIPInputStream(input) + : new XZInputStream(input); + } catch (Throwable ex) { + LOG.warning("Failed to open log file " + path, ex); + IOUtils.closeQuietly(input, ex); + input = null; + } + + String entryName = getEntryName(entryNames, StringUtils.substringBeforeLast(fileName, ".")); + if (input != null && exportLogFile(zos, path, entryName, input, buffer)) + continue; + } + + // Copy the log file content as-is into a new entry in the zip file. + // If an exception occurs while decompressing the input file, we should + // ensure the input file and the current zip entry are closed. + + InputStream input; + try { + input = Files.newInputStream(path); + } catch (Throwable ex) { + LOG.warning("Failed to open log file " + path, ex); + continue; + } + + exportLogFile(zos, path, getEntryName(entryNames, fileName), input, buffer); + } + + zos.putNextEntry(new ZipEntry(getEntryName(entryNames, "hmcl-latest.log"))); + LOG.exportLogs(zos); + zos.closeEntry(); + } + } + + return outputFile; + } + + private static String getEntryName(Set entryNames, String name) { + if (entryNames.add(name)) { + return name; + } + + for (long i = 1; ; i++) { + String newName = name + "." + i; + if (entryNames.add(newName)) { + return newName; + } + } + } + + /// This method guarantees to close both `input` and the current zip entry. + /// + /// If no exception occurs, this method returns `true`; + /// If an exception occurs while reading from `input`, this method returns `false`; + /// If an exception occurs while writing to `output`, this method will throw it as is. + private static boolean exportLogFile(ZipOutputStream output, + Path file, // For logging + String entryName, + InputStream input, + byte[] buffer) throws IOException { + //noinspection TryFinallyCanBeTryWithResources + try { + output.putNextEntry(new ZipEntry(entryName)); + int read; + while (true) { + try { + read = input.read(buffer); + if (read <= 0) + return true; + } catch (Throwable ex) { + LOG.warning("Failed to decompress log file " + file, ex); + return false; + } + + output.write(buffer, 0, read); + } + } finally { + try { + input.close(); + } catch (Throwable ex) { + LOG.warning("Failed to close log file " + file, ex); + } + output.closeEntry(); + } + } +} diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 672b254bb31..7c256ea0dae 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -239,9 +239,6 @@ contact.feedback.github.statement=Submit an issue on GitHub. color.recent=Recommended color.custom=Custom Color -crash.NoClassDefFound=Please verify the integrity of this software, or try updating your Java. -crash.user_fault=The launcher crashed due to corrupted Java or system environment. Please make sure your Java or OS is installed properly. - curse.category.0=All # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -955,10 +952,7 @@ launcher.cache_directory.disabled=Disabled launcher.cache_directory.invalid=Failed to create a cache directory, falling back to default. launcher.contact=Contact Us launcher.crash=Hello Minecraft! Launcher has encountered a fatal error! Please copy the following log and ask for help on our Discord, QQ group, GitHub, or other Minecraft forum. -launcher.crash.java_internal_error=Hello Minecraft! Launcher has encountered a fatal error because your Java is corrupted. Please uninstall your Java and download a suitable Java here. launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher has encountered a fatal error! Your launcher is outdated. Please update your launcher! -launcher.update_java=Please update your Java version. - libraries.download=Downloading Libraries login.enter_password=Please enter your password. diff --git a/HMCL/src/main/resources/assets/lang/I18N_ar.properties b/HMCL/src/main/resources/assets/lang/I18N_ar.properties index 3b1e9c7f9a7..4e594d19a14 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ar.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ar.properties @@ -219,9 +219,6 @@ contact.feedback.github.statement=أرسل تقريراً عن مشكلة على color.recent=مقترح color.custom=لون مخصص -crash.NoClassDefFound=يُرجى التحقق من سلامة هذا البرنامج، أو محاولة تحديث Java. -crash.user_fault=تعطّل المشغّل بسبب تلف Java أو بيئة النظام. يُرجى التأكد من تثبيت Java أو نظام التشغيل بشكل صحيح. - curse.category.0=الكل # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -895,10 +892,7 @@ launcher.cache_directory.disabled=معطّل launcher.cache_directory.invalid=فشل إنشاء مجلد الذاكرة المؤقتة، جارٍ الرجوع إلى الافتراضي. launcher.contact=تواصل معنا launcher.crash=واجه Hello Minecraft! Launcher خطأً فادحاً! يُرجى نسخ السجل التالي وطلب المساعدة على Discord أو مجموعة QQ أو GitHub أو أي منتدى Minecraft آخر. -launcher.crash.java_internal_error=واجه Hello Minecraft! Launcher خطأً فادحاً بسبب تلف Java. يُرجى إلغاء تثبيت Java وتنزيل إصدار مناسب من هنا. launcher.crash.hmcl_out_dated=واجه Hello Minecraft! Launcher خطأً فادحاً! المشغّل قديم. يُرجى تحديثه! -launcher.update_java=يُرجى تحديث إصدار Java الخاص بك. - libraries.download=جارٍ تنزيل المكتبات login.enter_password=يُرجى إدخال كلمة المرور. diff --git a/HMCL/src/main/resources/assets/lang/I18N_de.properties b/HMCL/src/main/resources/assets/lang/I18N_de.properties index 059c0fe977a..bfaa837b54e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_de.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_de.properties @@ -239,9 +239,6 @@ contact.feedback.github.statement=Reichen Sie ein Issue auf GitHub ein. color.recent=Empfohlen color.custom=Benutzerdefinierte Farbe -crash.NoClassDefFound=Bitte überprüfen Sie die Integrität dieser Software oder versuchen Sie, Ihr Java zu aktualisieren. -crash.user_fault=Der Launcher ist aufgrund einer beschädigten Java- oder Systemumgebung abgestürzt. Bitte stellen Sie sicher, dass Ihr Java oder Betriebssystem ordnungsgemäß installiert ist. - curse.category.0=Alle # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -952,10 +949,7 @@ launcher.cache_directory.disabled=Deaktiviert launcher.cache_directory.invalid=Fehler beim Erstellen des Cache-Verzeichnisses, Rückgriff auf Standard. launcher.contact=Kontaktiere uns launcher.crash=Hello Minecraft! Launcher ist auf einen fatalen Fehler gestoßen! Bitte kopieren Sie das folgende Protokoll und bitten Sie in unserem Discord, der QQ-Gruppe, auf GitHub oder in einem anderen Minecraft-Forum um Hilfe. -launcher.crash.java_internal_error=Hello Minecraft! Launcher ist auf einen fatalen Fehler gestoßen, da Ihre Java-Installation beschädigt ist. Bitte deinstallieren Sie Java und laden Sie eine geeignete Java-Version hier herunter. launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher ist auf einen fatalen Fehler gestoßen! Ihr Launcher ist veraltet. Bitte aktualisieren Sie Ihren Launcher! -launcher.update_java=Bitte aktualisieren Sie Ihre Java-Version. - libraries.download=Bibliotheken werden heruntergeladen login.enter_password=Bitte geben Sie Ihr Passwort ein. diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index 4d1c14ae69e..eeec1aaaf10 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -199,9 +199,6 @@ contact.feedback.github.statement=Envíe una propuesta en GitHub. color.recent=Recomendado color.custom=Color personalizado -crash.NoClassDefFound=Por favor, verifique la integridad de este software, o intente actualizar su Java. -crash.user_fault=El launcher se ha bloqueado debido a que Java o el entorno del sistema están dañados. Por favor, asegúrese de que su Java o sistema operativo está instalado correctamente. - curse.category.0=Todos # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -848,10 +845,7 @@ launcher.cache_directory.disabled=Desactivado launcher.cache_directory.invalid=No se ha podido crear el directorio de la caché, volviendo a los valores por defecto. launcher.contact=Contacta con nosotros launcher.crash=Hello Minecraft! Launcher ha encontrado un error fatal. Por favor, copie el siguiente registro y pida ayuda en nuestra comunidad en Discord, GitHub o Minecraft Forums. -launcher.crash.java_internal_error=Hello Minecraft! Launcher ha encontrado un error fatal porque su Java está dañado. Por favor, desinstala tu Java y descarga un Java adecuado aquí. launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher ha encontrado un error fatal. Su launcher está desactualizado. Por favor, ¡actualícelo! -launcher.update_java=Por favor, actualice su versión de Java. - libraries.download=Descargando bibliotecas login.enter_password=Por favor, introduzca su contraseña. diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index 5e4fb6d3c35..4eece774183 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -163,9 +163,6 @@ contact.feedback.github.statement=GitHubで問題を送信します。 color.recent=推奨 color.custom=カスタムカラー -crash.NoClassDefFound=このソフトウェアの整合性を確認するか、Javaの更新をお試しください。 -crash.user_fault=JavaまたはOSの環境が壊れているため、ランチャーがクラッシュしました。JavaまたはOSが正しくインストールされているかご確認ください。 - curse.category.0=全て # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -571,8 +568,6 @@ launcher.cache_directory.invalid=無効なディレクトリ。デフォルト launcher.contact=お問い合わせ launcher.crash=Hello Minecraft!ランチャーがクラッシュしました!次のコンテンツをコピーして、MCBBS、Baidu Tieba、GitHub、またはMinecraftForumを介してフィードバックを送信してください。 launcher.crash.hmcl_out_dated=Hello Minecraft!ランチャーがクラッシュしました!ランチャーが古くなっています。ランチャーを更新してください! -launcher.update_java=Javaを更新してください。 - login.enter_password=パスワードを入力してください。 logwindow.show_lines=行を表示 diff --git a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties index 2f517b58983..de2a967aebb 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties @@ -199,7 +199,6 @@ contact.feedback=建言之徑 contact.feedback.github=Github 議題 contact.feedback.github.statement=舉一 Github 議題 -crash.NoClassDefFound=宜驗 HMCL 之案全否,抑更迭爪哇。\n君可求助於 https://docs.hmcl.net/help.html。 crash.user_fault=君之械網與爪哇或有謬,是以崩。宜驗爪哇與算機。\n君可求助於 https://docs.hmcl.net/help.html。 curse.category.0=一覽無遺 @@ -681,7 +680,6 @@ launcher.contact=伏惟候告 launcher.crash=HMCL 有謬而弗能正。宜鈔下文而報謬于右下之鈕。 launcher.crash.java_internal_error=HMCL 不能行,以爪哇壞也。宜去是爪哇,而擊以置爪哇之適者。 launcher.crash.hmcl_out_dated=HMCL 有謬而弗能正之。余識君之啟者舊矣,宜新之。 -launcher.update_java=宜迭更爪哇。\n君可求助於 https://docs.hmcl.net/help.html。 libraries.download=引之所依 diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index 49735dfe6df..cdf7f8395ee 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -195,9 +195,6 @@ contact.feedback.github.statement=Отправить проблему на GitHu color.recent=Рекомендуемые color.custom=Пользовательский цвет -crash.NoClassDefFound=Проверьте целостность этого программного обеспечения или попробуйте обновить версию Java. -crash.user_fault=Лаунчер аварийно завершил работу из-за повреждения Java или системной среды. Убедитесь, что Java или ОС установлены правильно. - curse.category.0=Все # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -841,10 +838,7 @@ launcher.cache_directory.disabled=Отключено launcher.cache_directory.invalid=Не удалось создать папку для кэша, возвращаем к значению по умолчанию. launcher.contact=Связаться с нами launcher.crash=Лаунчер столкнулся с фатальной ошибкой! Скопируйте следующий журнал и попросите помощи в нашем Discord, группе QQ, GitHub или на другом форуме Minecraft. -launcher.crash.java_internal_error=Лаунчер столкнулся с фатальной ошибкой! Пожалуйста, удалите Java и скачайте подходящую Java здесь. launcher.crash.hmcl_out_dated=Лаунчер столкнулся с фатальной ошибкой! Ваш лаунчер устарел. Обновите его! -launcher.update_java=Пожалуйста, обновите версию Java. - libraries.download=Скачивание библиотек login.enter_password=Введите пароль. diff --git a/HMCL/src/main/resources/assets/lang/I18N_uk.properties b/HMCL/src/main/resources/assets/lang/I18N_uk.properties index 25044542c87..8810da0b643 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_uk.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_uk.properties @@ -244,9 +244,6 @@ contact.feedback.github.statement=Надіслати проблему на GitHu color.recent=Рекомендовані color.custom=Власний колір -crash.NoClassDefFound=Перевірте цілісність цього програмного забезпечення або спробуйте оновити Java. -crash.user_fault=Лаунчер зазнав збою через пошкоджене середовище Java або системи. Переконайтеся, що ваша Java або ОС встановлені належним чином. - curse.category.0=Усі curse.category.4474=Наукова фантастика @@ -913,10 +910,7 @@ launcher.cache_directory.disabled=Вимкнено launcher.cache_directory.invalid=Не вдалося створити каталог кешу, повернення до типового. launcher.contact=Зв'яжіться з нами launcher.crash=Hello Minecraft! Лаунчер зіткнувся з фатальною помилкою! Скопіюйте наступний журнал та попросіть допомоги на нашому Discord, групі QQ, GitHub або іншому форумі Minecraft. -launcher.crash.java_internal_error=Hello Minecraft! Лаунчер зіткнувся з фатальною помилкою, оскільки ваша Java пошкоджена. Видаліть вашу Java та завантажте відповідну Java тут. launcher.crash.hmcl_out_dated=Hello Minecraft! Лаунчер зіткнувся з фатальною помилкою! Ваш лаунчер застарів. Оновіть ваш лаунчер! -launcher.update_java=Оновіть вашу версію Java. - libraries.download=Завантаження бібліотек login.enter_password=Введіть свій пароль. diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 48e4524a3da..4517b6626b2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -237,9 +237,6 @@ contact.feedback.github.statement=提交一個 GitHub Issue color.recent=建議 color.custom=自訂顏色 -crash.NoClassDefFound=請確認 Hello Minecraft! Launcher 本體是否完整,或更新你的 Java。 -crash.user_fault=你的系統或 Java 環境可能安裝不當導致本軟體當機,請檢查你的 Java 環境或你的電腦!可以嘗試重新安裝 Java。 - curse.category.0=全部 # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -767,10 +764,7 @@ launcher.cache_directory.disabled=停用 launcher.cache_directory.invalid=無法建立自訂的快取目錄。已還原至預設設定。 launcher.contact=聯絡我們 launcher.crash=Hello Minecraft! Launcher 遇到了無法處理的錯誤。請複製下列內容並透過 GitHub、Discord 或 HMCL QQ 群回報問題。 -launcher.crash.java_internal_error=Hello Minecraft! Launcher 由於目前 Java 損壞而無法繼續執行。請移除目前 Java,點擊 此處 安裝合適的 Java 版本。 launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了無法處理的錯誤。已偵測到你的啟動器不是最新版本,請更新後重試! -launcher.update_java=請更新你的 Java - libraries.download=下載依賴庫 login.enter_password=請輸入你的密碼 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index cc1c47a2dc5..ac3c12eabd8 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -239,9 +239,6 @@ contact.chat.qq_group.statement=欢迎加入 HMCL 官方 QQ 群,加入后请 contact.chat.discord=Discord contact.chat.discord.statement=欢迎加入 Discord 服务器,加入后请遵守讨论区规定 -crash.NoClassDefFound=请确认 Hello Minecraft! Launcher 本体是否完整,或更新你的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。 -crash.user_fault=你的系统或 Java 环境可能安装不当导致本软件崩溃,请检查你的 Java 环境或你的电脑。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。 - curse.category.0=全部 # https://addons-ecs.forgesvc.net/api/v2/category/section/4471 @@ -773,10 +770,7 @@ launcher.cache_directory.disabled=禁用 (总是使用游戏文件夹路径) launcher.cache_directory.invalid=无法创建自定义的缓存文件夹。已经恢复到默认设置。 launcher.contact=联系我们 launcher.crash=Hello Minecraft! Launcher 遇到了无法处理的错误。请复制下列内容并点击右下角的按钮反馈问题。 -launcher.crash.java_internal_error=Hello Minecraft! Launcher 由于当前 Java 损坏而无法继续运行。请卸载当前 Java,点击 此处 安装合适的 Java 版本。 launcher.crash.hmcl_out_dated=Hello Minecraft! Launcher 遇到了无法处理的错误。已检测到你的启动器不是最新版本,请更新后再试。 -launcher.update_java=请更新你的 Java。\n你可以访问 https://docs.hmcl.net/help.html 页面寻求帮助。 - libraries.download=下载依赖库 login.enter_password=请输入你的密码