From fadd9580a29d46278f3051d0a5fd759cd2df764b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=9E=E5=BA=90?= <109708109+CiiLu@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:13:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=89=93=E5=8C=85=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E9=80=BB=E8=BE=91=20(#5108)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #4587 --- .../org/jackhuang/hmcl/game/LogExporter.java | 27 ++++++++--------- .../jackhuang/hmcl/ui/GameCrashWindow.java | 29 +++++++++++++++++-- 2 files changed, 39 insertions(+), 17 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 3cb59219e..c21b7cb7e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java @@ -17,21 +17,19 @@ */ package org.jackhuang.hmcl.game; -import org.jackhuang.hmcl.util.io.IOUtils; -import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.StringUtils; +import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.Zipper; +import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.io.BufferedReader; import java.io.IOException; import java.io.UncheckedIOException; -import java.lang.management.ManagementFactory; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; +import java.nio.file.PathMatcher; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -43,7 +41,9 @@ 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, + PathMatcher logMatcher) { Path runDirectory = gameRepository.getRunDirectory(versionId); Path baseDirectory = gameRepository.getBaseDirectory(); List versions = new ArrayList<>(); @@ -65,10 +65,10 @@ public final class LogExporter { return CompletableFuture.runAsync(() -> { try (Zipper zipper = new Zipper(zipFile)) { - processLogs(runDirectory.resolve("liteconfig"), "*.log", "liteconfig", zipper); - processLogs(runDirectory.resolve("logs"), "*.log", "logs", zipper); - processLogs(runDirectory, "*.log", "runDirectory", zipper); - processLogs(runDirectory.resolve("crash-reports"), "*.txt", "crash-reports", zipper); + processLogs(runDirectory.resolve("liteconfig"), "*.log", "liteconfig", zipper, logMatcher); + processLogs(runDirectory.resolve("logs"), "*.log", "logs", zipper, logMatcher); + processLogs(runDirectory, "*.log", "runDirectory", zipper, logMatcher); + processLogs(runDirectory.resolve("crash-reports"), "*.txt", "crash-reports", zipper, logMatcher); zipper.putTextFile(LOG.getLogs(), "hmcl.log"); zipper.putTextFile(logs, "minecraft.log"); @@ -86,14 +86,11 @@ public final class LogExporter { }); } - private static void processLogs(Path directory, String fileExtension, String logDirectory, Zipper zipper) { + private static void processLogs(Path directory, String fileExtension, String logDirectory, Zipper zipper, PathMatcher logMatcher) { try (DirectoryStream stream = Files.newDirectoryStream(directory, fileExtension)) { - long processStartTime = ManagementFactory.getRuntimeMXBean().getStartTime(); - for (Path file : stream) { if (Files.isRegularFile(file)) { - FileTime time = Files.readAttributes(file, BasicFileAttributes.class).lastModifiedTime(); - if (time.toMillis() >= processStartTime) { + if (logMatcher == null || logMatcher.matches(file)) { try (BufferedReader reader = IOUtils.newBufferedReaderMaybeNativeEncoding(file)) { zipper.putLines(reader.lines().map(Logger::filterForbiddenToken), file.getFileName().toString()); } catch (IOException e) { 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 4eec10c7d..c0050bc2e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/GameCrashWindow.java @@ -50,9 +50,12 @@ import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.platform.*; import java.io.IOException; +import java.lang.management.ManagementFactory; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.time.Instant; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -269,8 +272,30 @@ public class GameCrashWindow extends Stage { CompletableFuture.supplyAsync(() -> logs.stream().map(Log::getLog).collect(Collectors.joining("\n"))) - .thenComposeAsync(logs -> - LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, new CommandBuilder().addAll(managedProcess.getCommands()).toString())) + .thenComposeAsync(logs -> { + long processStartTime = managedProcess.getProcess().info() + .startInstant() + .map(Instant::toEpochMilli).orElseGet(() -> { + try { + return ManagementFactory.getRuntimeMXBean().getStartTime(); + } catch (Throwable e) { + LOG.warning("Failed to get process start time", e); + return 0L; + } + }); + + return LogExporter.exportLogs(logFile, repository, launchOptions.getVersionName(), logs, + new CommandBuilder().addAll(managedProcess.getCommands()).toString(), + path -> { + try { + FileTime lastModifiedTime = Files.getLastModifiedTime(path); + return lastModifiedTime.toMillis() >= processStartTime; + } catch (Throwable e) { + LOG.warning("Failed to read file attributes", e); + return false; + } + }); + }) .handleAsync((result, exception) -> { Alert alert;