diff --git a/fmlcore/src/main/java/net/minecraftforge/fml/CrashReportCallables.java b/fmlcore/src/main/java/net/minecraftforge/fml/CrashReportCallables.java index 44de403bf1..18bc69f54f 100644 --- a/fmlcore/src/main/java/net/minecraftforge/fml/CrashReportCallables.java +++ b/fmlcore/src/main/java/net/minecraftforge/fml/CrashReportCallables.java @@ -5,33 +5,93 @@ package net.minecraftforge.fml; +import com.mojang.logging.LogUtils; +import org.slf4j.Logger; + import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.BooleanSupplier; import java.util.function.Supplier; -public class CrashReportCallables { +public class CrashReportCallables +{ + private static final Logger LOGGER = LogUtils.getLogger(); private static final List crashCallables = Collections.synchronizedList(new ArrayList<>()); + /** + * Register a custom {@link ISystemReportExtender} + */ public static void registerCrashCallable(ISystemReportExtender callable) { crashCallables.add(callable); } - public static void registerCrashCallable(String headerName, Supplier reportGenerator) { - registerCrashCallable(new ISystemReportExtender() { + /** + * Register a {@link ISystemReportExtender system report extender} with the given header name and content + * generator, which will always be appended to the system report + * @param headerName The name of the system report entry + * @param reportGenerator The report generator to be called when a crash report is built + */ + public static void registerCrashCallable(String headerName, Supplier reportGenerator) + { + registerCrashCallable(new ISystemReportExtender() + { @Override - public String getLabel() { + public String getLabel() + { return headerName; } + @Override - public String get() { + public String get() + { return reportGenerator.get(); } }); } - public static List allCrashCallables() { + /** + * Register a {@link ISystemReportExtender system report extender} with the given header name and content + * generator, which will only be appended to the system report when the given {@link BooleanSupplier} returns true + * @param headerName The name of the system report entry + * @param reportGenerator The report generator to be called when a crash report is built + * @param active The supplier of the flag to be checked when a crash report is built + */ + public static void registerCrashCallable(String headerName, Supplier reportGenerator, BooleanSupplier active) + { + registerCrashCallable(new ISystemReportExtender() + { + @Override + public String getLabel() + { + return headerName; + } + + @Override + public String get() + { + return reportGenerator.get(); + } + + @Override + public boolean isActive() + { + try + { + return active.getAsBoolean(); + } + catch (Throwable t) + { + LOGGER.warn("CrashCallable '{}' threw an exception while checking the active flag, disabling", headerName, t); + return false; + } + } + }); + } + + public static List allCrashCallables() + { return List.copyOf(crashCallables); } } diff --git a/fmlcore/src/main/java/net/minecraftforge/fml/ISystemReportExtender.java b/fmlcore/src/main/java/net/minecraftforge/fml/ISystemReportExtender.java index 8c74db970a..e533be752b 100644 --- a/fmlcore/src/main/java/net/minecraftforge/fml/ISystemReportExtender.java +++ b/fmlcore/src/main/java/net/minecraftforge/fml/ISystemReportExtender.java @@ -10,4 +10,9 @@ import java.util.function.Supplier; public interface ISystemReportExtender extends Supplier { String getLabel(); + + default boolean isActive() + { + return true; + } } diff --git a/src/main/java/net/minecraftforge/logging/CrashReportExtender.java b/src/main/java/net/minecraftforge/logging/CrashReportExtender.java index 736896112c..8b1be79157 100644 --- a/src/main/java/net/minecraftforge/logging/CrashReportExtender.java +++ b/src/main/java/net/minecraftforge/logging/CrashReportExtender.java @@ -26,9 +26,12 @@ public class CrashReportExtender public static void extendSystemReport(final SystemReport systemReport) { - for (final ISystemReportExtender call: CrashReportCallables.allCrashCallables()) + for (final ISystemReportExtender call : CrashReportCallables.allCrashCallables()) { - systemReport.setDetail(call.getLabel(), call); + if (call.isActive()) + { + systemReport.setDetail(call.getLabel(), call); + } } } diff --git a/src/test/java/net/minecraftforge/debug/CrashCallableTest.java b/src/test/java/net/minecraftforge/debug/CrashCallableTest.java new file mode 100644 index 0000000000..5164eab71a --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/CrashCallableTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug; + +import net.minecraftforge.fml.CrashReportCallables; +import net.minecraftforge.fml.common.Mod; + +/** + * Test features and guards of crash-callables. + *
    + *
  • The "AlwaysActiveCrashCallable" must always be printed to the crash report
  • + *
  • The "ToggleableCrashCallable" must only be printed to the crash report when the {@code ENABLED} flag is {@code true}
  • + *
  • The "BadContentCrashCallable" must always print "BadContentCrashCallable: ERR" to the crash report and + * print an exception to the log (relies on a try-catch in vanilla code)
  • + *
  • The "BadFlagCrashCallable" must never print to the crash report and must print an exception to the log
  • + *
+ * To initiate a debug crash to test this, hold F3 + C for 10 seconds. + */ +@Mod("crash_callable_test") +public class CrashCallableTest +{ + private static final boolean ENABLED = true; + + public CrashCallableTest() + { + CrashReportCallables.registerCrashCallable("AlwaysActiveCrashCallable", () -> "test"); + CrashReportCallables.registerCrashCallable("ToggleableCrashCallable", () -> "active", () -> ENABLED); + CrashReportCallables.registerCrashCallable("BadContentCrashCallable", () -> + { + throw new UnsupportedOperationException(); + }); + CrashReportCallables.registerCrashCallable("BadFlagCrashCallable", () -> "why am I here?!", () -> + { + throw new UnsupportedOperationException(); + }); + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index 1cb879d01d..968e05ad23 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -21,6 +21,8 @@ license="LGPL v2.1" modId="advancement_event_test" [[mods]] modId="shader_resources_test" +[[mods]] + modId="crash_callable_test" # LEGACY TEST CASES ###### The mods below are from the old test framework and need to be yeeted later again.