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);