From 80c0390edac28413b9135b6c5308c11837503cfc Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:07:35 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=B4=A9=E6=BA=83?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=97=B6=E9=99=84=E5=B8=A6=E5=B4=A9=E6=BA=83?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jackhuang/hmcl/game/LogExporter.java | 10 +- .../jackhuang/hmcl/ui/GameCrashWindow.java | 125 +++++++++++++++++- 2 files changed, 129 insertions(+), 6 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java index 9aed6454f..76ca68ef9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java @@ -43,7 +43,7 @@ public final class LogExporter { private LogExporter() { } - public static CompletableFuture exportLogs(Path zipFile, DefaultGameRepository gameRepository, String versionId, String logs, String launchScript) { + public static CompletableFuture exportLogs(Path zipFile, DefaultGameRepository gameRepository, String versionId, String logs, String launchScript, Path crashReportFile) { Path runDirectory = gameRepository.getRunDirectory(versionId).toPath(); Path baseDirectory = gameRepository.getBaseDirectory().toPath(); List versions = new ArrayList<>(); @@ -65,6 +65,14 @@ public final class LogExporter { return CompletableFuture.runAsync(() -> { try (Zipper zipper = new Zipper(zipFile)) { + if (Files.exists(crashReportFile)) { + try { + zipper.putFile(crashReportFile, "hmcl-game-crash-report.log"); + } catch (IOException e) { + LOG.warning("Failed to add crash report file to zip", e); + } + } + processLogs(runDirectory.resolve("liteconfig"), "*.log", "liteconfig", zipper); processLogs(runDirectory.resolve("logs"), "*.log", "logs", zipper); processLogs(runDirectory, "*.log", "runDirectory", zipper); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index c522620c3..fd1639486 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -42,11 +42,16 @@ import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.util.*; -import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.io.JarUtils; +import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.platform.*; +import org.jackhuang.hmcl.util.platform.hardware.CentralProcessor; +import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -59,9 +64,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES; -import static org.jackhuang.hmcl.util.logging.Logger.LOG; 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; public class GameCrashWindow extends Stage { private final Version version; @@ -263,11 +268,121 @@ public class GameCrashWindow extends Stage { private void exportGameCrashInfo() { Path logFile = Paths.get("minecraft-exported-crash-info-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")) + ".zip").toAbsolutePath(); + Path crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.log"); - CompletableFuture.supplyAsync(() -> - logs.stream().map(Log::getLog).collect(Collectors.joining("\n"))) + CompletableFuture.supplyAsync(() -> { + try { + StringBuilder report = new StringBuilder(); + report.append("=== HMCL Game Crash Report ===\n"); + report.append("HMCL Version: ").append(Metadata.VERSION).append("\n"); + report.append("Current Directory: ").append(Metadata.CURRENT_DIRECTORY).append("\n"); + report.append("HMCL Global Directory: ").append(Metadata.HMCL_GLOBAL_DIRECTORY).append("\n"); + report.append("HMCL Current Directory: ").append(Metadata.HMCL_CURRENT_DIRECTORY).append("\n"); + report.append("HMCL Jar Path: ").append(Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found")).append("\n"); + report.append("HMCL Log File: ").append(Lang.requireNonNullElse(LOG.getLogFile(), "In Memory")).append("\n\n"); + + report.append("== System Information ==\n"); + report.append("Operating System: ").append(OperatingSystem.OS_RELEASE_PRETTY_NAME == null + ? OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + : OperatingSystem.OS_RELEASE_PRETTY_NAME + " (" + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + ')').append("\n"); + + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + report.append("Processor Identifier: ").append(System.getenv("PROCESSOR_IDENTIFIER")).append("\n"); + } + + report.append("System Architecture: ").append(Architecture.SYSTEM_ARCH.getDisplayName()).append("\n"); + report.append("Native Encoding: ").append(OperatingSystem.NATIVE_CHARSET).append("\n"); + report.append("JNU Encoding: ").append(System.getProperty("sun.jnu.encoding")).append("\n"); + + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + report.append("Code Page: ").append(OperatingSystem.CODE_PAGE).append("\n"); + } + + if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { + report.append("XDG Session Type: ").append(System.getenv("XDG_SESSION_TYPE")).append("\n"); + report.append("XDG Current Desktop: ").append(System.getenv("XDG_CURRENT_DESKTOP")).append("\n"); + } + + report.append("Total Memory: ").append(total_memory).append("\n\n"); + + report.append("== Hardware Information ==\n"); + + CentralProcessor cpu = SystemInfo.getCentralProcessor(); + if (cpu != null) { + report.append("CPU: ").append(cpu.toString().replace("\n", " ")).append("\n"); + } + + List graphicsCards = SystemInfo.getGraphicsCards(); + if (graphicsCards != null) { + if (graphicsCards.isEmpty()) { + report.append("GPU: Not Found\n"); + } else if (graphicsCards.size() == 1) { + report.append("GPU: ").append(graphicsCards.get(0).toString().replace("\n", " ")).append("\n"); + } else { + int index = 1; + for (GraphicsCard graphicsCard : graphicsCards) { + report.append("GPU ").append(index++).append(": ") + .append(graphicsCard.toString().replace("\n", " ")).append("\n"); + } + } + } + + long totalMemorySize = SystemInfo.getTotalMemorySize(); + long usedMemorySize = SystemInfo.getUsedMemorySize(); + report.append("Memory: ") + .append(DataSizeUnit.format(usedMemorySize)) + .append(" / ") + .append(DataSizeUnit.format(totalMemorySize)); + if (totalMemorySize > 0 && usedMemorySize > 0) { + report.append(" (").append((int) (((double) usedMemorySize / totalMemorySize) * 100)).append("%)\n"); + } else { + report.append("\n"); + } + + report.append("\n"); + + report.append("== Java Information ==\n"); + report.append("Java Architecture: ").append(Architecture.CURRENT_ARCH.getDisplayName()).append("\n"); + report.append("Java Version: ").append(System.getProperty("java.version")).append(", ").append(System.getProperty("java.vendor")).append("\n"); + report.append("Java VM Version: ").append(System.getProperty("java.vm.name")).append(" (").append(System.getProperty("java.vm.info")).append("), ").append(System.getProperty("java.vm.vendor")).append("\n"); + report.append("Java Home: ").append(System.getProperty("java.home")).append("\n"); + report.append("Game Java Version: ").append(java).append("\n"); + report.append("Game Java Path: ").append(launchOptions.getJava().getBinary().toAbsolutePath()).append("\n"); + report.append("JVM Max Memory: ").append(MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory())).append("\n"); + report.append("Allocated Memory: ").append(memory).append("\n"); + + report.append("== Game Information ==\n"); + report.append("Game Version: ").append(version.getId()).append("\n"); + report.append("Game Directory: ").append(launchOptions.getGameDir().getAbsolutePath()).append("\n"); + + report.append("\n== Mod Loader Information ==\n"); + for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) { + if (!type.getPatchId().isEmpty()) { + analyzer.getVersion(type).ifPresent(ver -> { + report.append(type.getPatchId()).append(": ").append(ver).append("\n"); + }); + } + } + + report.append("\n== Crash Analysis ==\n"); + for (Node node : reasonTextFlow.getChildren()) { + if (node instanceof Text) { + report.append(((Text) node).getText()); + } + } + + // Structure of game mod directory + report.append(FileUtils.printFileStructure(repository.getModManager(version.getId()).getModsDirectory(), 10)); + + Files.write(crashReportFile, report.toString().getBytes()); + } catch (IOException e) { + LOG.warning("Failed to write crash report file", e); + } + return logs.stream().map(Log::getLog).collect(Collectors.joining("\n")); + }) .thenComposeAsync(logs -> - LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString())) + LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString(), crashReportFile) + ) .handleAsync((result, exception) -> { Alert alert; From 9a35756f66e0755640018bc988ff55b6690043b8 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:04:18 +0800 Subject: [PATCH 2/6] fix --- .../org/jackhuang/hmcl/ui/GameCrashWindow.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index fd1639486..56ef5e154 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -279,9 +279,9 @@ public class GameCrashWindow extends Stage { report.append("HMCL Global Directory: ").append(Metadata.HMCL_GLOBAL_DIRECTORY).append("\n"); report.append("HMCL Current Directory: ").append(Metadata.HMCL_CURRENT_DIRECTORY).append("\n"); report.append("HMCL Jar Path: ").append(Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found")).append("\n"); - report.append("HMCL Log File: ").append(Lang.requireNonNullElse(LOG.getLogFile(), "In Memory")).append("\n\n"); + report.append("HMCL Log File: ").append(Lang.requireNonNullElse(LOG.getLogFile(), "In Memory")).append("\n"); - report.append("== System Information ==\n"); + report.append("\n== System Information ==\n"); report.append("Operating System: ").append(OperatingSystem.OS_RELEASE_PRETTY_NAME == null ? OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION : OperatingSystem.OS_RELEASE_PRETTY_NAME + " (" + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + ')').append("\n"); @@ -303,9 +303,9 @@ public class GameCrashWindow extends Stage { report.append("XDG Current Desktop: ").append(System.getenv("XDG_CURRENT_DESKTOP")).append("\n"); } - report.append("Total Memory: ").append(total_memory).append("\n\n"); + report.append("Total Memory: ").append(total_memory).append("\n"); - report.append("== Hardware Information ==\n"); + report.append("\n== Hardware Information ==\n"); CentralProcessor cpu = SystemInfo.getCentralProcessor(); if (cpu != null) { @@ -339,9 +339,7 @@ public class GameCrashWindow extends Stage { report.append("\n"); } - report.append("\n"); - - report.append("== Java Information ==\n"); + report.append("\n== Java Information ==\n"); report.append("Java Architecture: ").append(Architecture.CURRENT_ARCH.getDisplayName()).append("\n"); report.append("Java Version: ").append(System.getProperty("java.version")).append(", ").append(System.getProperty("java.vendor")).append("\n"); report.append("Java VM Version: ").append(System.getProperty("java.vm.name")).append(" (").append(System.getProperty("java.vm.info")).append("), ").append(System.getProperty("java.vm.vendor")).append("\n"); @@ -351,7 +349,7 @@ public class GameCrashWindow extends Stage { report.append("JVM Max Memory: ").append(MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory())).append("\n"); report.append("Allocated Memory: ").append(memory).append("\n"); - report.append("== Game Information ==\n"); + report.append("\n== Game Information ==\n"); report.append("Game Version: ").append(version.getId()).append("\n"); report.append("Game Directory: ").append(launchOptions.getGameDir().getAbsolutePath()).append("\n"); From f4114a33390ac0fc095a4f72bd0590c4a2b1595c Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Tue, 22 Jul 2025 20:44:19 +0800 Subject: [PATCH 3/6] StringBuilder -> BufferedWriter --- .../jackhuang/hmcl/ui/GameCrashWindow.java | 101 +++++++++--------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index 56ef5e154..268eb95f5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -49,12 +49,13 @@ import org.jackhuang.hmcl.util.platform.*; import org.jackhuang.hmcl.util.platform.hardware.CentralProcessor; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; +import java.io.BufferedWriter; import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryPoolMXBean; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -271,108 +272,106 @@ public class GameCrashWindow extends Stage { Path crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.log"); CompletableFuture.supplyAsync(() -> { - try { - StringBuilder report = new StringBuilder(); - report.append("=== HMCL Game Crash Report ===\n"); - report.append("HMCL Version: ").append(Metadata.VERSION).append("\n"); - report.append("Current Directory: ").append(Metadata.CURRENT_DIRECTORY).append("\n"); - report.append("HMCL Global Directory: ").append(Metadata.HMCL_GLOBAL_DIRECTORY).append("\n"); - report.append("HMCL Current Directory: ").append(Metadata.HMCL_CURRENT_DIRECTORY).append("\n"); - report.append("HMCL Jar Path: ").append(Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found")).append("\n"); - report.append("HMCL Log File: ").append(Lang.requireNonNullElse(LOG.getLogFile(), "In Memory")).append("\n"); + try (BufferedWriter report = Files.newBufferedWriter(crashReportFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + report.write("=== HMCL Game Crash Report ===\n"); + report.write("HMCL Version: " + Metadata.VERSION + "\n"); + report.write("Current Directory: " + Metadata.CURRENT_DIRECTORY + "\n"); + report.write("HMCL Global Directory: " + Metadata.HMCL_GLOBAL_DIRECTORY + "\n"); + report.write("HMCL Current Directory: " + Metadata.HMCL_CURRENT_DIRECTORY + "\n"); + report.write("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found") + "\n"); + report.write("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory") + "\n"); - report.append("\n== System Information ==\n"); - report.append("Operating System: ").append(OperatingSystem.OS_RELEASE_PRETTY_NAME == null + report.write("\n== System Information ==\n"); + report.write("Operating System: " + (OperatingSystem.OS_RELEASE_PRETTY_NAME == null ? OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION - : OperatingSystem.OS_RELEASE_PRETTY_NAME + " (" + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + ')').append("\n"); + : OperatingSystem.OS_RELEASE_PRETTY_NAME + " (" + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + ')') + "\n"); if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - report.append("Processor Identifier: ").append(System.getenv("PROCESSOR_IDENTIFIER")).append("\n"); + report.write("Processor Identifier: " + System.getenv("PROCESSOR_IDENTIFIER") + "\n"); } - report.append("System Architecture: ").append(Architecture.SYSTEM_ARCH.getDisplayName()).append("\n"); - report.append("Native Encoding: ").append(OperatingSystem.NATIVE_CHARSET).append("\n"); - report.append("JNU Encoding: ").append(System.getProperty("sun.jnu.encoding")).append("\n"); + report.write("System Architecture: " + Architecture.SYSTEM_ARCH.getDisplayName() + "\n"); + report.write("Native Encoding: " + OperatingSystem.NATIVE_CHARSET + "\n"); + report.write("JNU Encoding: " + System.getProperty("sun.jnu.encoding") + "\n"); if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - report.append("Code Page: ").append(OperatingSystem.CODE_PAGE).append("\n"); + report.write("Code Page: " + OperatingSystem.CODE_PAGE + "\n"); } if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { - report.append("XDG Session Type: ").append(System.getenv("XDG_SESSION_TYPE")).append("\n"); - report.append("XDG Current Desktop: ").append(System.getenv("XDG_CURRENT_DESKTOP")).append("\n"); + report.write("XDG Session Type: " + System.getenv("XDG_SESSION_TYPE") + "\n"); + report.write("XDG Current Desktop: " + System.getenv("XDG_CURRENT_DESKTOP") + "\n"); } - report.append("Total Memory: ").append(total_memory).append("\n"); + report.write("Total Memory: " + total_memory + "\n"); - report.append("\n== Hardware Information ==\n"); + report.write("\n== Hardware Information ==\n"); CentralProcessor cpu = SystemInfo.getCentralProcessor(); if (cpu != null) { - report.append("CPU: ").append(cpu.toString().replace("\n", " ")).append("\n"); + report.write("CPU: " + cpu.toString().replace("\n", " ") + "\n"); } List graphicsCards = SystemInfo.getGraphicsCards(); if (graphicsCards != null) { if (graphicsCards.isEmpty()) { - report.append("GPU: Not Found\n"); + report.write("GPU: Not Found\n"); } else if (graphicsCards.size() == 1) { - report.append("GPU: ").append(graphicsCards.get(0).toString().replace("\n", " ")).append("\n"); + report.write("GPU: " + graphicsCards.get(0).toString().replace("\n", " ") + "\n"); } else { int index = 1; for (GraphicsCard graphicsCard : graphicsCards) { - report.append("GPU ").append(index++).append(": ") - .append(graphicsCard.toString().replace("\n", " ")).append("\n"); + report.write("GPU " + (index++) + ": " + graphicsCard.toString().replace("\n", " ") + "\n"); } } } long totalMemorySize = SystemInfo.getTotalMemorySize(); long usedMemorySize = SystemInfo.getUsedMemorySize(); - report.append("Memory: ") - .append(DataSizeUnit.format(usedMemorySize)) - .append(" / ") - .append(DataSizeUnit.format(totalMemorySize)); + report.append("Memory: " + DataSizeUnit.format(usedMemorySize) + " / " + DataSizeUnit.format(totalMemorySize)); if (totalMemorySize > 0 && usedMemorySize > 0) { - report.append(" (").append((int) (((double) usedMemorySize / totalMemorySize) * 100)).append("%)\n"); + report.append(" (" + (int) (((double) usedMemorySize / totalMemorySize) * 100) + "%)\n"); } else { report.append("\n"); } - report.append("\n== Java Information ==\n"); - report.append("Java Architecture: ").append(Architecture.CURRENT_ARCH.getDisplayName()).append("\n"); - report.append("Java Version: ").append(System.getProperty("java.version")).append(", ").append(System.getProperty("java.vendor")).append("\n"); - report.append("Java VM Version: ").append(System.getProperty("java.vm.name")).append(" (").append(System.getProperty("java.vm.info")).append("), ").append(System.getProperty("java.vm.vendor")).append("\n"); - report.append("Java Home: ").append(System.getProperty("java.home")).append("\n"); - report.append("Game Java Version: ").append(java).append("\n"); - report.append("Game Java Path: ").append(launchOptions.getJava().getBinary().toAbsolutePath()).append("\n"); - report.append("JVM Max Memory: ").append(MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory())).append("\n"); - report.append("Allocated Memory: ").append(memory).append("\n"); + report.write("\n== Java Information ==\n"); + report.write("Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n"); + report.write("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n"); + report.write("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n"); + report.write("Java Home: " + System.getProperty("java.home") + "\n"); + report.write("Game Java Version: " + java + "\n"); + report.write("Game Java Path: " + launchOptions.getJava().getBinary().toAbsolutePath() + "\n"); + report.write("JVM Max Memory: " + MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory()) + "\n"); + report.write("Allocated Memory: " + memory + "\n"); - report.append("\n== Game Information ==\n"); - report.append("Game Version: ").append(version.getId()).append("\n"); - report.append("Game Directory: ").append(launchOptions.getGameDir().getAbsolutePath()).append("\n"); + report.write("\n== Game Information ==\n"); + report.write("Game Version: " + version.getId() + "\n"); + report.write("Game Directory: " + launchOptions.getGameDir().getAbsolutePath() + "\n"); - report.append("\n== Mod Loader Information ==\n"); + report.write("\n== Mod Loader Information ==\n"); for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) { if (!type.getPatchId().isEmpty()) { analyzer.getVersion(type).ifPresent(ver -> { - report.append(type.getPatchId()).append(": ").append(ver).append("\n"); + try { + report.write(type.getPatchId() + ": " + ver + "\n"); + } catch (IOException ignored) { + } }); } } - report.append("\n== Crash Analysis ==\n"); + report.write("\n== Crash Analysis ==\n"); for (Node node : reasonTextFlow.getChildren()) { if (node instanceof Text) { - report.append(((Text) node).getText()); + report.write(((Text) node).getText()); } } // Structure of game mod directory - report.append(FileUtils.printFileStructure(repository.getModManager(version.getId()).getModsDirectory(), 10)); + report.write(FileUtils.printFileStructure(repository.getModManager(version.getId()).getModsDirectory(), 10)); - Files.write(crashReportFile, report.toString().getBytes()); + report.flush(); } catch (IOException e) { LOG.warning("Failed to write crash report file", e); } From 35f191412b0518f618668fd33b5763f845a66bd6 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:01:49 +0800 Subject: [PATCH 4/6] fix checkstyle --- .../jackhuang/hmcl/ui/GameCrashWindow.java | 218 +++++++++--------- 1 file changed, 107 insertions(+), 111 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index 268eb95f5..e18527012 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -272,130 +272,126 @@ public class GameCrashWindow extends Stage { Path crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.log"); CompletableFuture.supplyAsync(() -> { - try (BufferedWriter report = Files.newBufferedWriter(crashReportFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - report.write("=== HMCL Game Crash Report ===\n"); - report.write("HMCL Version: " + Metadata.VERSION + "\n"); - report.write("Current Directory: " + Metadata.CURRENT_DIRECTORY + "\n"); - report.write("HMCL Global Directory: " + Metadata.HMCL_GLOBAL_DIRECTORY + "\n"); - report.write("HMCL Current Directory: " + Metadata.HMCL_CURRENT_DIRECTORY + "\n"); - report.write("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found") + "\n"); - report.write("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory") + "\n"); + try (BufferedWriter report = Files.newBufferedWriter(crashReportFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + report.write("=== HMCL Game Crash Report ===\n"); + report.write("HMCL Version: " + Metadata.VERSION + "\n"); + report.write("Current Directory: " + Metadata.CURRENT_DIRECTORY + "\n"); + report.write("HMCL Global Directory: " + Metadata.HMCL_GLOBAL_DIRECTORY + "\n"); + report.write("HMCL Current Directory: " + Metadata.HMCL_CURRENT_DIRECTORY + "\n"); + report.write("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found") + "\n"); + report.write("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory") + "\n"); - report.write("\n== System Information ==\n"); - report.write("Operating System: " + (OperatingSystem.OS_RELEASE_PRETTY_NAME == null - ? OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION - : OperatingSystem.OS_RELEASE_PRETTY_NAME + " (" + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + ')') + "\n"); + report.write("\n== System Information ==\n"); + report.write("Operating System: " + (OperatingSystem.OS_RELEASE_PRETTY_NAME == null + ? OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + : OperatingSystem.OS_RELEASE_PRETTY_NAME + " (" + OperatingSystem.SYSTEM_NAME + ' ' + OperatingSystem.SYSTEM_VERSION + ')') + "\n"); - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - report.write("Processor Identifier: " + System.getenv("PROCESSOR_IDENTIFIER") + "\n"); - } + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + report.write("Processor Identifier: " + System.getenv("PROCESSOR_IDENTIFIER") + "\n"); + } - report.write("System Architecture: " + Architecture.SYSTEM_ARCH.getDisplayName() + "\n"); - report.write("Native Encoding: " + OperatingSystem.NATIVE_CHARSET + "\n"); - report.write("JNU Encoding: " + System.getProperty("sun.jnu.encoding") + "\n"); + report.write("System Architecture: " + Architecture.SYSTEM_ARCH.getDisplayName() + "\n"); + report.write("Native Encoding: " + OperatingSystem.NATIVE_CHARSET + "\n"); + report.write("JNU Encoding: " + System.getProperty("sun.jnu.encoding") + "\n"); - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - report.write("Code Page: " + OperatingSystem.CODE_PAGE + "\n"); - } + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + report.write("Code Page: " + OperatingSystem.CODE_PAGE + "\n"); + } - if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { - report.write("XDG Session Type: " + System.getenv("XDG_SESSION_TYPE") + "\n"); - report.write("XDG Current Desktop: " + System.getenv("XDG_CURRENT_DESKTOP") + "\n"); - } + if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { + report.write("XDG Session Type: " + System.getenv("XDG_SESSION_TYPE") + "\n"); + report.write("XDG Current Desktop: " + System.getenv("XDG_CURRENT_DESKTOP") + "\n"); + } - report.write("Total Memory: " + total_memory + "\n"); + report.write("Total Memory: " + total_memory + "\n"); - report.write("\n== Hardware Information ==\n"); + report.write("\n== Hardware Information ==\n"); - CentralProcessor cpu = SystemInfo.getCentralProcessor(); - if (cpu != null) { - report.write("CPU: " + cpu.toString().replace("\n", " ") + "\n"); - } + CentralProcessor cpu = SystemInfo.getCentralProcessor(); + if (cpu != null) { + report.write("CPU: " + cpu.toString().replace("\n", " ") + "\n"); + } - List graphicsCards = SystemInfo.getGraphicsCards(); - if (graphicsCards != null) { - if (graphicsCards.isEmpty()) { - report.write("GPU: Not Found\n"); - } else if (graphicsCards.size() == 1) { - report.write("GPU: " + graphicsCards.get(0).toString().replace("\n", " ") + "\n"); - } else { - int index = 1; - for (GraphicsCard graphicsCard : graphicsCards) { - report.write("GPU " + (index++) + ": " + graphicsCard.toString().replace("\n", " ") + "\n"); - } - } - } - - long totalMemorySize = SystemInfo.getTotalMemorySize(); - long usedMemorySize = SystemInfo.getUsedMemorySize(); - report.append("Memory: " + DataSizeUnit.format(usedMemorySize) + " / " + DataSizeUnit.format(totalMemorySize)); - if (totalMemorySize > 0 && usedMemorySize > 0) { - report.append(" (" + (int) (((double) usedMemorySize / totalMemorySize) * 100) + "%)\n"); - } else { - report.append("\n"); - } - - report.write("\n== Java Information ==\n"); - report.write("Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n"); - report.write("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n"); - report.write("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n"); - report.write("Java Home: " + System.getProperty("java.home") + "\n"); - report.write("Game Java Version: " + java + "\n"); - report.write("Game Java Path: " + launchOptions.getJava().getBinary().toAbsolutePath() + "\n"); - report.write("JVM Max Memory: " + MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory()) + "\n"); - report.write("Allocated Memory: " + memory + "\n"); - - report.write("\n== Game Information ==\n"); - report.write("Game Version: " + version.getId() + "\n"); - report.write("Game Directory: " + launchOptions.getGameDir().getAbsolutePath() + "\n"); - - report.write("\n== Mod Loader Information ==\n"); - for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) { - if (!type.getPatchId().isEmpty()) { - analyzer.getVersion(type).ifPresent(ver -> { - try { - report.write(type.getPatchId() + ": " + ver + "\n"); - } catch (IOException ignored) { - } - }); - } - } - - report.write("\n== Crash Analysis ==\n"); - for (Node node : reasonTextFlow.getChildren()) { - if (node instanceof Text) { - report.write(((Text) node).getText()); - } - } - - // Structure of game mod directory - report.write(FileUtils.printFileStructure(repository.getModManager(version.getId()).getModsDirectory(), 10)); - - report.flush(); - } catch (IOException e) { - LOG.warning("Failed to write crash report file", e); - } - return logs.stream().map(Log::getLog).collect(Collectors.joining("\n")); - }) - .thenComposeAsync(logs -> - LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString(), crashReportFile) - ) - .handleAsync((result, exception) -> { - Alert alert; - - if (exception == null) { - FXUtils.showFileInExplorer(logFile); - alert = new Alert(Alert.AlertType.INFORMATION, i18n("settings.launcher.launcher_log.export.success", logFile)); + List graphicsCards = SystemInfo.getGraphicsCards(); + if (graphicsCards != null) { + if (graphicsCards.isEmpty()) { + report.write("GPU: Not Found\n"); + } else if (graphicsCards.size() == 1) { + report.write("GPU: " + graphicsCards.get(0).toString().replace("\n", " ") + "\n"); } else { - LOG.warning("Failed to export game crash info", exception); - alert = new Alert(Alert.AlertType.WARNING, i18n("settings.launcher.launcher_log.export.failed") + "\n" + StringUtils.getStackTrace(exception)); + int index = 1; + for (GraphicsCard graphicsCard : graphicsCards) { + report.write("GPU " + (index++) + ": " + graphicsCard.toString().replace("\n", " ") + "\n"); + } } + } - alert.setTitle(i18n("settings.launcher.launcher_log.export")); - alert.showAndWait(); + long totalMemorySize = SystemInfo.getTotalMemorySize(); + long usedMemorySize = SystemInfo.getUsedMemorySize(); + report.append("Memory: " + DataSizeUnit.format(usedMemorySize) + " / " + DataSizeUnit.format(totalMemorySize)); + if (totalMemorySize > 0 && usedMemorySize > 0) { + report.append(" (" + (int) (((double) usedMemorySize / totalMemorySize) * 100) + "%)\n"); + } else { + report.append("\n"); + } - return null; - }); + report.write("\n== Java Information ==\n"); + report.write("Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n"); + report.write("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n"); + report.write("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n"); + report.write("Java Home: " + System.getProperty("java.home") + "\n"); + report.write("Game Java Version: " + java + "\n"); + report.write("Game Java Path: " + launchOptions.getJava().getBinary().toAbsolutePath() + "\n"); + report.write("JVM Max Memory: " + MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory()) + "\n"); + report.write("Allocated Memory: " + memory + "\n"); + + report.write("\n== Game Information ==\n"); + report.write("Game Version: " + version.getId() + "\n"); + report.write("Game Directory: " + launchOptions.getGameDir().getAbsolutePath() + "\n"); + + report.write("\n== Mod Loader Information ==\n"); + for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) { + if (!type.getPatchId().isEmpty()) { + analyzer.getVersion(type).ifPresent(ver -> { + try { + report.write(type.getPatchId() + ": " + ver + "\n"); + } catch (IOException ignored) { + } + }); + } + } + + report.write("\n== Crash Analysis ==\n"); + for (Node node : reasonTextFlow.getChildren()) { + if (node instanceof Text) { + report.write(((Text) node).getText()); + } + } + + // Structure of game mod directory + report.write(FileUtils.printFileStructure(repository.getModManager(version.getId()).getModsDirectory(), 10)); + + report.flush(); + } catch (IOException e) { + LOG.warning("Failed to write crash report file", e); + } + return logs.stream().map(Log::getLog).collect(Collectors.joining("\n")); + }).thenComposeAsync(logs -> LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString(), crashReportFile)).handleAsync((result, exception) -> { + Alert alert; + + if (exception == null) { + FXUtils.showFileInExplorer(logFile); + alert = new Alert(Alert.AlertType.INFORMATION, i18n("settings.launcher.launcher_log.export.success", logFile)); + } else { + LOG.warning("Failed to export game crash info", exception); + alert = new Alert(Alert.AlertType.WARNING, i18n("settings.launcher.launcher_log.export.failed") + "\n" + StringUtils.getStackTrace(exception)); + } + + alert.setTitle(i18n("settings.launcher.launcher_log.export")); + alert.showAndWait(); + + return null; + }); } private final class View extends VBox { From 925eebcb25b4c19e8c81b74ec2ffaa32de9940d9 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Tue, 22 Jul 2025 21:42:45 +0800 Subject: [PATCH 5/6] Update GameCrashWindow.java --- .../java/org/jackhuang/hmcl/ui/GameCrashWindow.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index e18527012..f693aec79 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -269,10 +269,17 @@ public class GameCrashWindow extends Stage { private void exportGameCrashInfo() { Path logFile = Paths.get("minecraft-exported-crash-info-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")) + ".zip").toAbsolutePath(); - Path crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.log"); + Path crashReportFile; + try { + crashReportFile = Files.createTempFile("hmcl-game-crash-report-", ".log"); + } catch (IOException e) { + LOG.warning("Failed to create temporary crash report file, using run directory instead", e); + crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.log"); + } + Path finalCrashReportFile = crashReportFile; CompletableFuture.supplyAsync(() -> { - try (BufferedWriter report = Files.newBufferedWriter(crashReportFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + try (BufferedWriter report = Files.newBufferedWriter(finalCrashReportFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { report.write("=== HMCL Game Crash Report ===\n"); report.write("HMCL Version: " + Metadata.VERSION + "\n"); report.write("Current Directory: " + Metadata.CURRENT_DIRECTORY + "\n"); @@ -376,7 +383,7 @@ public class GameCrashWindow extends Stage { LOG.warning("Failed to write crash report file", e); } return logs.stream().map(Log::getLog).collect(Collectors.joining("\n")); - }).thenComposeAsync(logs -> LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString(), crashReportFile)).handleAsync((result, exception) -> { + }).thenComposeAsync(logs -> LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString(), finalCrashReportFile)).handleAsync((result, exception) -> { Alert alert; if (exception == null) { From c2a97a5317293bb5113aa2c7ca16de6ce93c1663 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Fri, 25 Jul 2025 02:02:47 +0800 Subject: [PATCH 6/6] update --- .../jackhuang/hmcl/ui/GameCrashWindow.java | 86 ++++++++++++++++--- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java index f693aec79..2c9a8387d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -36,6 +36,8 @@ import javafx.stage.Stage; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.game.*; +import org.jackhuang.hmcl.java.JavaManager; +import org.jackhuang.hmcl.java.JavaRuntime; import org.jackhuang.hmcl.launch.ProcessListener; import org.jackhuang.hmcl.setting.StyleSheets; import org.jackhuang.hmcl.task.Schedulers; @@ -268,25 +270,35 @@ public class GameCrashWindow extends Stage { } private void exportGameCrashInfo() { - Path logFile = Paths.get("minecraft-exported-crash-info-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")) + ".zip").toAbsolutePath(); + String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH-mm-ss")); + Path logFile = Paths.get("minecraft-exported-crash-info-" + time + ".zip").toAbsolutePath(); Path crashReportFile; try { crashReportFile = Files.createTempFile("hmcl-game-crash-report-", ".log"); } catch (IOException e) { LOG.warning("Failed to create temporary crash report file, using run directory instead", e); - crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.log"); + crashReportFile = repository.getRunDirectory(version.getId()).toPath().resolve("hmcl-game-crash-report.txt"); } Path finalCrashReportFile = crashReportFile; CompletableFuture.supplyAsync(() -> { try (BufferedWriter report = Files.newBufferedWriter(finalCrashReportFile, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { report.write("=== HMCL Game Crash Report ===\n"); + report.write("Generation Time: " + time + "\n"); + report.write("Exit Type: " + exitType + "\n"); + + report.write("\n== HMCL Information ==\n"); report.write("HMCL Version: " + Metadata.VERSION + "\n"); report.write("Current Directory: " + Metadata.CURRENT_DIRECTORY + "\n"); report.write("HMCL Global Directory: " + Metadata.HMCL_GLOBAL_DIRECTORY + "\n"); report.write("HMCL Current Directory: " + Metadata.HMCL_CURRENT_DIRECTORY + "\n"); report.write("HMCL Jar Path: " + Lang.requireNonNullElse(JarUtils.thisJarPath(), "Not Found") + "\n"); report.write("HMCL Log File: " + Lang.requireNonNullElse(LOG.getLogFile(), "In Memory") + "\n"); + report.write("JVM Max Memory: " + MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory()) + "\n"); + report.write("Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n"); + report.write("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n"); + report.write("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n"); + report.write("Java Home: " + System.getProperty("java.home") + "\n"); report.write("\n== System Information ==\n"); report.write("Operating System: " + (OperatingSystem.OS_RELEASE_PRETTY_NAME == null @@ -314,11 +326,13 @@ public class GameCrashWindow extends Stage { report.write("\n== Hardware Information ==\n"); + // CPU information CentralProcessor cpu = SystemInfo.getCentralProcessor(); if (cpu != null) { report.write("CPU: " + cpu.toString().replace("\n", " ") + "\n"); } + // Graphics cards information List graphicsCards = SystemInfo.getGraphicsCards(); if (graphicsCards != null) { if (graphicsCards.isEmpty()) { @@ -333,6 +347,7 @@ public class GameCrashWindow extends Stage { } } + // Memory information long totalMemorySize = SystemInfo.getTotalMemorySize(); long usedMemorySize = SystemInfo.getUsedMemorySize(); report.append("Memory: " + DataSizeUnit.format(usedMemorySize) + " / " + DataSizeUnit.format(totalMemorySize)); @@ -343,18 +358,51 @@ public class GameCrashWindow extends Stage { } report.write("\n== Java Information ==\n"); - report.write("Java Architecture: " + Architecture.CURRENT_ARCH.getDisplayName() + "\n"); - report.write("Java Version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + "\n"); - report.write("Java VM Version: " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.info") + "), " + System.getProperty("java.vm.vendor") + "\n"); - report.write("Java Home: " + System.getProperty("java.home") + "\n"); report.write("Game Java Version: " + java + "\n"); report.write("Game Java Path: " + launchOptions.getJava().getBinary().toAbsolutePath() + "\n"); - report.write("JVM Max Memory: " + MEGABYTES.formatBytes(Runtime.getRuntime().maxMemory()) + "\n"); - report.write("Allocated Memory: " + memory + "\n"); + report.write("Game Min Memory: " + launchOptions.getMinMemory() + "\n"); + report.write("Game Max Memory: " + launchOptions.getMaxMemory() + "\n"); report.write("\n== Game Information ==\n"); report.write("Game Version: " + version.getId() + "\n"); - report.write("Game Directory: " + launchOptions.getGameDir().getAbsolutePath() + "\n"); + report.write("IsModpack: " + repository.isModpack(version.getId()) + "\n"); + report.write("Game RunDirectory: " + repository.getRunDirectory(version.getId()) + "\n"); + report.write("Game VersionJson: " + repository.getVersionJson(version.getId()) + "\n"); + report.write("Game VersionJar: " + repository.getVersionJar(version.getId()) + "\n"); + report.write("Game AssetDirectory: " + repository.getActualAssetDirectory(version.getId(), version.getAssetIndex().getId()) + "\n"); + report.write("Game AssetIndexUrl: " + version.getAssetIndex().getUrl() + "\n"); + report.write("Game MainClass: " + version.getMainClass() + "\n"); + report.write("ServerIP: " + launchOptions.getServerIp() + "\n"); + report.write("EnvironmentVariables: " + launchOptions.getEnvironmentVariables() + "\n"); + report.write("Fullscreen: " + launchOptions.isFullscreen() + "\n"); + report.write("WindowWidth: " + launchOptions.getWidth() + "\n"); + report.write("WindowHeight: " + launchOptions.getHeight() + "\n"); + report.write("PreLaunchCommand: " + launchOptions.getPreLaunchCommand() + "\n"); + report.write("PostExitCommand: " + launchOptions.getPostExitCommand() + "\n"); + report.write("isUseNativeOpenAL: " + launchOptions.isUseNativeOpenAL() + "\n"); + report.write("isUseNativeGLFW: " + launchOptions.isUseNativeGLFW() + "\n"); + if (managedProcess.getClasspath() != null) + report.write("ClassPath: " + managedProcess.getClasspath()); + + report.write("\n== Available Java Runtimes ==\n"); + try { + Collection allJavaRuntimes = JavaManager.getAllJava(); + if (allJavaRuntimes.isEmpty()) { + report.write("No Java runtimes found\n"); + } else { + for (JavaRuntime runtime : allJavaRuntimes) { + report.write(String.format("%s %s (%s, %s): %s\n", + runtime.isJDK() ? "JDK" : "JRE", + runtime.getVersion(), + runtime.getPlatform().getArchitecture().getDisplayName(), + Lang.requireNonNullElse(runtime.getVendor(), "Unknown"), + runtime.getBinary())); + } + } + } catch (InterruptedException e) { + report.write("Failed to get Java runtime information.\n"); + LOG.warning("Failed to get Java runtime information.", e); + } report.write("\n== Mod Loader Information ==\n"); for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) { @@ -368,16 +416,32 @@ public class GameCrashWindow extends Stage { } } - report.write("\n== Crash Analysis ==\n"); + report.write("\n== HMCL Crash Analysis ==\n"); for (Node node : reasonTextFlow.getChildren()) { if (node instanceof Text) { report.write(((Text) node).getText()); } } + report.write("\n\n"); - // Structure of game mod directory + report.write("\n== Game Mod Directory Structure ==\n"); report.write(FileUtils.printFileStructure(repository.getModManager(version.getId()).getModsDirectory(), 10)); + report.write("\n\n"); + + report.write("\n== Game Resourcepacks Directory Structure ==\n"); + report.write(FileUtils.printFileStructure(Paths.get(repository.getRunDirectory(version.getId()).getAbsolutePath()).resolve("resourcepacks"), 10)); + + report.write("\n\n"); + + report.write("\n== Game Shaderpacks Directory Structure ==\n"); + report.write(FileUtils.printFileStructure(Paths.get(repository.getRunDirectory(version.getId()).getAbsolutePath()).resolve("shaderpacks"), 10)); + + report.write("\n\n"); + + report.write("\n== Game Config Directory Structure ==\n"); + report.write(FileUtils.printFileStructure(Paths.get(repository.getRunDirectory(version.getId()).getAbsolutePath()).resolve("config"), 10)); + report.flush(); } catch (IOException e) { LOG.warning("Failed to write crash report file", e);