From 43391c009cb769020ee53f7c93e43ca64cf67f53 Mon Sep 17 00:00:00 2001 From: cpw Date: Tue, 8 Sep 2020 20:05:45 -0400 Subject: [PATCH] More crash report tweaks. Put a button to open the generated crash report on the error screen, tweak formatting of crash report, and add the enhanced stack trace data (transformers et al) Signed-off-by: cpw --- .../minecraft/crash/CrashReport.java.patch | 19 ++++++++++++++- .../crash/CrashReportCategory.java.patch | 15 +++++++++++- .../fml/CrashReportExtender.java | 24 ++++++++++++++----- .../fml/client/ClientModLoader.java | 5 ++-- .../client/gui/screen/LoadingErrorScreen.java | 9 +++++-- 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/patches/minecraft/net/minecraft/crash/CrashReport.java.patch b/patches/minecraft/net/minecraft/crash/CrashReport.java.patch index ddb7179f2..ba7fb810a 100644 --- a/patches/minecraft/net/minecraft/crash/CrashReport.java.patch +++ b/patches/minecraft/net/minecraft/crash/CrashReport.java.patch @@ -8,7 +8,24 @@ } public String func_71501_a() { -@@ -121,23 +122,13 @@ +@@ -87,14 +88,8 @@ + if (this.field_85060_g != null && this.field_85060_g.length > 0) { + p_71506_1_.append("-- Head --\n"); + p_71506_1_.append("Thread: ").append(Thread.currentThread().getName()).append("\n"); +- p_71506_1_.append("Stacktrace:\n"); +- +- for(StackTraceElement stacktraceelement : this.field_85060_g) { +- p_71506_1_.append("\t").append("at ").append((Object)stacktraceelement); +- p_71506_1_.append("\n"); +- } +- +- p_71506_1_.append("\n"); ++ p_71506_1_.append("Stacktrace:"); ++ p_71506_1_.append(net.minecraftforge.fml.CrashReportExtender.generateEnhancedStackTrace(this.field_85060_g)); + } + + for(CrashReportCategory crashreportcategory : this.field_71512_c) { +@@ -121,23 +116,13 @@ throwable.setStackTrace(this.field_71511_b.getStackTrace()); } diff --git a/patches/minecraft/net/minecraft/crash/CrashReportCategory.java.patch b/patches/minecraft/net/minecraft/crash/CrashReportCategory.java.patch index 1f9144e5d..3347d576f 100644 --- a/patches/minecraft/net/minecraft/crash/CrashReportCategory.java.patch +++ b/patches/minecraft/net/minecraft/crash/CrashReportCategory.java.patch @@ -13,7 +13,20 @@ return this.field_85075_d.length; } } -@@ -158,6 +160,10 @@ +@@ -145,11 +147,7 @@ + + if (this.field_85075_d != null && this.field_85075_d.length > 0) { + p_85072_1_.append("\nStacktrace:"); +- +- for(StackTraceElement stacktraceelement : this.field_85075_d) { +- p_85072_1_.append("\n\tat "); +- p_85072_1_.append((Object)stacktraceelement); +- } ++ p_85072_1_.append(net.minecraftforge.fml.CrashReportExtender.generateEnhancedStackTrace(this.field_85075_d)); + } + + } +@@ -158,6 +156,10 @@ return this.field_85075_d; } diff --git a/src/main/java/net/minecraftforge/fml/CrashReportExtender.java b/src/main/java/net/minecraftforge/fml/CrashReportExtender.java index df159ae1e..af722a52e 100644 --- a/src/main/java/net/minecraftforge/fml/CrashReportExtender.java +++ b/src/main/java/net/minecraftforge/fml/CrashReportExtender.java @@ -20,6 +20,7 @@ package net.minecraftforge.fml; import cpw.mods.modlauncher.log.TransformingThrowablePatternConverter; +import joptsimple.internal.Strings; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraftforge.fml.common.ICrashCallable; @@ -67,13 +68,23 @@ public class CrashReportExtender public static void addCrashReportHeader(StringBuilder stringbuilder, CrashReport crashReport) { } - public static String generateEnhancedStackTrace(final Throwable throwable) { - return TransformingThrowablePatternConverter.generateEnhancedStackTrace(throwable); + return generateEnhancedStackTrace(throwable, true); + } + + public static String generateEnhancedStackTrace(final StackTraceElement[] stacktrace) { + final Throwable t = new Throwable(); + t.setStackTrace(stacktrace); + return generateEnhancedStackTrace(t, false); + } + + public static String generateEnhancedStackTrace(final Throwable throwable, boolean header) { + final String s = TransformingThrowablePatternConverter.generateEnhancedStackTrace(throwable); + return header ? s : s.substring(s.indexOf(Strings.LINE_SEPARATOR)); } - public static void dumpModLoadingCrashReport(final Logger logger, final LoadingFailedException error, final File topLevelDir) { + public static File dumpModLoadingCrashReport(final Logger logger, final LoadingFailedException error, final File topLevelDir) { final CrashReport crashReport = CrashReport.makeCrashReport(new Exception("Mod Loading has failed"), "Mod loading error has occurred"); error.getErrors().forEach(mle -> { final Optional modInfo = Optional.ofNullable(mle.getModInfo()); @@ -81,16 +92,16 @@ public class CrashReportExtender Throwable cause = mle.getCause(); int depth = 0; while (cause != null && cause.getCause() != null && cause.getCause()!=cause) { - category.addDetail("Caused by "+(depth++), cause +"\n\t\t"+ Arrays.stream(cause.getStackTrace()).map(Objects::toString).collect(Collectors.joining("\n\t\t"))); + category.addDetail("Caused by "+(depth++), cause + generateEnhancedStackTrace(cause.getStackTrace()).replaceAll(Strings.LINE_SEPARATOR+"\t", "\n\t\t")); cause = cause.getCause(); } if (cause != null) category.applyStackTrace(cause); category.addDetail("Mod File", () -> modInfo.map(IModInfo::getOwningFile).map(t->((ModFileInfo)t).getFile().getFileName()).orElse("NO FILE INFO")); category.addDetail("Failure message", () -> mle.getCleanMessage().replace("\n", "\n\t\t")); - category.addDetail("Exception message", Objects.toString(cause, "MISSING EXCEPTION MESSAGE")); category.addDetail("Mod Version", () -> modInfo.map(IModInfo::getVersion).map(Object::toString).orElse("NO MOD INFO AVAILABLE")); - category.addDetail("Mod Issue URL", () -> modInfo.map(IModInfo::getOwningFile).map(ModFileInfo.class::cast).flatMap(mfi->mfi.getConfigElement("issueTrackerURL")).orElse("NOT PROVIDED").toString()); + category.addDetail("Mod Issue URL", () -> modInfo.map(IModInfo::getOwningFile).map(ModFileInfo.class::cast).flatMap(mfi->mfi.getConfigElement("issueTrackerURL")).orElse("NOT PROVIDED")); + category.addDetail("Exception message", Objects.toString(cause, "MISSING EXCEPTION MESSAGE")); }); final File file1 = new File(topLevelDir, "crash-reports"); final File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-fml.txt"); @@ -100,5 +111,6 @@ public class CrashReportExtender logger.fatal("Failed to save crash report"); } System.out.print(crashReport.getCompleteReport()); + return file2; } } diff --git a/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java b/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java index 9d00040ab..b45304308 100644 --- a/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java +++ b/src/main/java/net/minecraftforge/fml/client/ClientModLoader.java @@ -182,16 +182,17 @@ public class ClientModLoader } warnings = Collections.emptyList(); //Clear warnings, as the user does not want to see them } + File dumpedLocation = null; if (error == null) { // We can finally start the forge eventbus up MinecraftForge.EVENT_BUS.start(); } else { // Double check we have the langs loaded for forge LanguageHook.loadForgeAndMCLangs(); - CrashReportExtender.dumpModLoadingCrashReport(LOGGER, error, mc.gameDir); + dumpedLocation = CrashReportExtender.dumpModLoadingCrashReport(LOGGER, error, mc.gameDir); } if (error != null || !warnings.isEmpty()) { - mc.displayGuiScreen(new LoadingErrorScreen(error, warnings)); + mc.displayGuiScreen(new LoadingErrorScreen(error, warnings, dumpedLocation)); return true; } else { ClientHooks.logMissingTextureErrors(); diff --git a/src/main/java/net/minecraftforge/fml/client/gui/screen/LoadingErrorScreen.java b/src/main/java/net/minecraftforge/fml/client/gui/screen/LoadingErrorScreen.java index ecd2f1cec..65de73982 100644 --- a/src/main/java/net/minecraftforge/fml/client/gui/screen/LoadingErrorScreen.java +++ b/src/main/java/net/minecraftforge/fml/client/gui/screen/LoadingErrorScreen.java @@ -41,6 +41,7 @@ import net.minecraftforge.fml.loading.FMLPaths; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; @@ -53,17 +54,19 @@ public class LoadingErrorScreen extends ErrorScreen { private final Path logFile; private final List modLoadErrors; private final List modLoadWarnings; + private final Path dumpedLocation; private LoadingEntryList entryList; private ITextComponent errorHeader; private ITextComponent warningHeader; - public LoadingErrorScreen(LoadingFailedException loadingException, List warnings) + public LoadingErrorScreen(LoadingFailedException loadingException, List warnings, final File dumpedLocation) { super(new StringTextComponent("Loading Error"), null); this.modLoadWarnings = warnings; this.modLoadErrors = loadingException == null ? Collections.emptyList() : loadingException.getErrors(); this.modsDir = FMLPaths.MODSDIR.get(); this.logFile = FMLPaths.GAMEDIR.get().resolve(Paths.get("logs","latest.log")); + this.dumpedLocation = dumpedLocation.toPath(); } @Override @@ -76,7 +79,7 @@ public class LoadingErrorScreen extends ErrorScreen { this.errorHeader = new StringTextComponent(TextFormatting.RED + ForgeI18n.parseMessage("fml.loadingerrorscreen.errorheader", this.modLoadErrors.size()) + TextFormatting.RESET); this.warningHeader = new StringTextComponent(TextFormatting.YELLOW + ForgeI18n.parseMessage("fml.loadingerrorscreen.warningheader", this.modLoadErrors.size()) + TextFormatting.RESET); - int yOffset = this.modLoadErrors.isEmpty() ? 46 : 38; + int yOffset = 46; this.func_230480_a_(new ExtendedButton(50, this.field_230709_l_ - yOffset, this.field_230708_k_ / 2 - 55, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.mods.folder")), b -> Util.getOSType().openFile(modsDir.toFile()))); this.func_230480_a_(new ExtendedButton(this.field_230708_k_ / 2 + 5, this.field_230709_l_ - yOffset, this.field_230708_k_ / 2 - 55, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.file", logFile.getFileName())), b -> Util.getOSType().openFile(logFile.toFile()))); if (this.modLoadErrors.isEmpty()) { @@ -84,6 +87,8 @@ public class LoadingErrorScreen extends ErrorScreen { ClientHooks.logMissingTextureErrors(); this.field_230706_i_.displayGuiScreen(null); })); + } else { + this.func_230480_a_(new ExtendedButton(this.field_230708_k_ / 4, this.field_230709_l_ - 24, this.field_230708_k_ / 2, 20, new StringTextComponent(ForgeI18n.parseMessage("fml.button.open.file", dumpedLocation.getFileName())), b -> Util.getOSType().openFile(dumpedLocation.toFile()))); } this.entryList = new LoadingEntryList(this, this.modLoadErrors, this.modLoadWarnings);