diff --git a/Locator/src/main/java/me/xfl03/morecrashinfo/fml/ModLocator.java b/Locator/src/main/java/me/xfl03/morecrashinfo/fml/ModLocator.java index 408d0ba..501f14e 100644 --- a/Locator/src/main/java/me/xfl03/morecrashinfo/fml/ModLocator.java +++ b/Locator/src/main/java/me/xfl03/morecrashinfo/fml/ModLocator.java @@ -163,7 +163,7 @@ public List scanModsLegacy() { //1.17+ @Override public Stream scanCandidates() { - logger.info("We are now at MoreCrashInfo ModLocator"); + logger.debug("We are now at MoreCrashInfo ModLocator"); Path gameFolder = FMLPaths.GAMEDIR.get(); logger.debug("Game folder {}", gameFolder); Path modFolder = FMLPaths.MODSDIR.get(); diff --git a/LocatorLoader/src/main/java/me/xfl03/morecrashinfo/modlauncher/TransformerService.java b/LocatorLoader/src/main/java/me/xfl03/morecrashinfo/modlauncher/TransformerService.java index 6a04e28..5ec5ad9 100644 --- a/LocatorLoader/src/main/java/me/xfl03/morecrashinfo/modlauncher/TransformerService.java +++ b/LocatorLoader/src/main/java/me/xfl03/morecrashinfo/modlauncher/TransformerService.java @@ -33,7 +33,7 @@ public class TransformerService implements ITransformationService { @Override public void onLoad(IEnvironment env, Set otherServices) throws IncompatibleEnvironmentException { logger = LogManager.getLogger("MoreCrashInfoTransformerService"); - logger.info("We are now at MoreCrashInfo TransformationService"); + logger.debug("We are now at MoreCrashInfo TransformationService"); } public static Path corePath; diff --git a/README.md b/README.md index 382745b..376e818 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,30 @@ Mod List: MoreCrashInfo-1.0.2.jar MoreCrashInfo {morecrashinfo@1.0.2 DONE} forge-1.14.4-28.0.23-universal.jar Forge {forge@28.0.23 DONE} ``` + +From Forge 1.15.2, mods can use Mixin to operate class file, which could cause crash, but it's not shown in crash report. ## What added? -This mod is designed to take mod list and coremod list back with pretty printing. +This mod is designed to show mod list, coremod list and mixin list in crash report with pretty printing. Feel free to open an issue if other info needed. What added in crash report: ``` Forge Mods: - | ID | Name | Version | Source | Status | - | ---------------- | ---------------- | ----------------- | -------------------------------------------- | ------ | - | minecraft | Minecraft | 1.14.4 | Not Found | NONE | - | customskinloader | CustomSkinLoader | 14.11-SNAPSHOT-89 | CustomSkinLoader_Forge-14.11-SNAPSHOT-89.jar | DONE | - | morecrashinfo | MoreCrashInfo | 1.0.2 | MoreCrashInfo-1.0.2.jar | DONE | - | forge | Forge | 28.0.23 | forge-1.14.4-28.0.23-universal.jar | DONE | -Forge CoreMods: - | ID | Name | Source | Status | - | ---------------- | ------------------------- | ---------------------------- | ------ | - | customskinloader | transformers | transformers.js | Loaded | - | forge | fieldtomethodtransformers | fieldtomethodtransformers.js | Loaded | + | ID | Name | Version | Source | Status | + | ---------------- | ---------------- | ----------------- | ------------------------------------- | ------ | + | minecraft | Minecraft | 1.19.3 | client-1.19.3-20221207.122022-srg.jar | DONE | + | morecrashinfo | MoreCrashInfo | 2.2.0 | MoreCrashInfo-Core.jar | DONE | + | forge | Forge | 44.1.2 | forge-1.19.3-44.1.2-universal.jar | DONE | + | rubidium | Rubidium | 0.6.3 | rubidium-0.6.3.jar | DONE | +Forge CoreMods: + | ID | Name | Source | Status | + | ----- | ------------------- | ---------------------- | ------ | + | forge | field_to_method | field_to_method.js | Loaded | + | forge | field_to_instanceof | field_to_instanceof.js | Loaded | + | forge | add_bouncer_method | add_bouncer_method.js | Loaded | +Mixin Configs: + | Name | Mixin Package | Priority | Required | Targets | + | -------------------- | -------------------------------- | -------- | -------- | ------- | + | rubidium.mixins.json | me.jellysquid.mods.sodium.mixin. | 1000 | true | 41 | ``` ## What's more? We are trying to analyze some crash automaticly. @@ -47,11 +54,9 @@ Error Info: ``` ## Compatibility -- Minecraft 1.15+ with Forge +- Minecraft 1.13+ with Forge - Java 8+ -In addition, this mod can be loaded in 1.13.2-1.14.4, but not work. We are trying to find out the reason. - ### Tested Environment - Minecraft 1.16.5, Forge 36.2.39 and Java 8 - Minecraft 1.19.3, Forge 44.1.2 and Java 17 diff --git a/build.gradle b/build.gradle index 894f7de..e1cfef3 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { id 'net.minecraftforge.gradle' version '5.1.+' } -version = "2.1.0" +version = "2.2.0" group = 'me.xfl03' archivesBaseName = 'MoreCrashInfo_Core' diff --git a/src/main/java/me/xfl03/morecrashinfo/crash/CallableManager.java b/src/main/java/me/xfl03/morecrashinfo/crash/CallableManager.java new file mode 100644 index 0000000..a246d05 --- /dev/null +++ b/src/main/java/me/xfl03/morecrashinfo/crash/CallableManager.java @@ -0,0 +1,59 @@ +package me.xfl03.morecrashinfo.crash; + +import me.xfl03.morecrashinfo.MoreCrashInfo; +import me.xfl03.morecrashinfo.util.ReflectionHelper; +import me.xfl03.morecrashinfo.util.VersionUtil; +import net.minecraftforge.fml.ISystemReportExtender; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class CallableManager { + private static final List callables = new ArrayList<>(); + + public static void initCallables() { + try { + MoreCrashInfo.logger.debug("CrashHandler.initCallables"); + int majorVersion = VersionUtil.getMinecraftMajorVersion(); + + //From 1.16, Forge formatted mod list + if (majorVersion <= 15) { + callables.add(new ModList()); + } + callables.add(new CoreModList()); + //Mixin added in 1.15.2-31.2.44 and 1.16.1-32.0.72 + if (majorVersion >= 16 || VersionUtil.getMinecraftVersion().equals("1.15.2")) { + callables.add(new MixinList()); + } + MoreCrashInfo.logger.debug("Callable list size {}", callables.size()); + MoreCrashInfo.logger.debug("Callable list member {}", callables.stream() + .map(ISystemReportExtender::getLabel).collect(Collectors.joining(", "))); + MoreCrashInfo.logger.info(getCallableMessages()); + + //1.13-1.14, we added these message behind stacktrace + if (majorVersion >= 15) { + //register callables to Forge + List callables0 = ReflectionHelper.getCallables(); + callables0.addAll(callables); + ReflectionHelper.printCallables(); +// ReflectionHelper.testCallables(); + } + } catch (Exception e) { + MoreCrashInfo.logger.warn("Error register callable"); + MoreCrashInfo.logger.warn(e); + } + } + + public static String getCallableMessages() { + StringBuilder sb = new StringBuilder("\n"); + for (CommonCallable callable : callables) { + sb.append("\t"); + sb.append(callable.getLabel()); + sb.append(":"); + sb.append(callable.get()); + sb.append("\n"); + } + return sb.toString(); + } +} diff --git a/src/main/java/me/xfl03/morecrashinfo/crash/CommonCrash.java b/src/main/java/me/xfl03/morecrashinfo/crash/CommonCallable.java similarity index 87% rename from src/main/java/me/xfl03/morecrashinfo/crash/CommonCrash.java rename to src/main/java/me/xfl03/morecrashinfo/crash/CommonCallable.java index f145a92..d2aab67 100644 --- a/src/main/java/me/xfl03/morecrashinfo/crash/CommonCrash.java +++ b/src/main/java/me/xfl03/morecrashinfo/crash/CommonCallable.java @@ -2,7 +2,7 @@ import net.minecraftforge.fml.ISystemReportExtender; -public abstract class CommonCrash implements ISystemReportExtender { +public abstract class CommonCallable implements ISystemReportExtender { abstract String innerCall() throws Exception; public Object call() throws Exception { diff --git a/src/main/java/me/xfl03/morecrashinfo/crash/CoreModList.java b/src/main/java/me/xfl03/morecrashinfo/crash/CoreModList.java index 160e91e..1b188cc 100644 --- a/src/main/java/me/xfl03/morecrashinfo/crash/CoreModList.java +++ b/src/main/java/me/xfl03/morecrashinfo/crash/CoreModList.java @@ -8,7 +8,7 @@ import java.util.ArrayList; import java.util.List; -public class CoreModList extends CommonCrash { +public class CoreModList extends CommonCallable { @Override public String getLabel() { return "Forge CoreMods"; diff --git a/src/main/java/me/xfl03/morecrashinfo/crash/MixinList.java b/src/main/java/me/xfl03/morecrashinfo/crash/MixinList.java new file mode 100644 index 0000000..5235724 --- /dev/null +++ b/src/main/java/me/xfl03/morecrashinfo/crash/MixinList.java @@ -0,0 +1,58 @@ +package me.xfl03.morecrashinfo.crash; + +import me.xfl03.morecrashinfo.util.PrintHelper; +import me.xfl03.morecrashinfo.util.Reflection; +import org.spongepowered.asm.mixin.extensibility.IMixinConfig; +import org.spongepowered.asm.service.MixinService; + +import java.util.ArrayList; +import java.util.List; + +public class MixinList extends CommonCallable { + @Override + String innerCall() throws Exception { + //Avoid mixin not found + try { + Class.forName("org.spongepowered.asm.mixin.Mixins"); + } catch (Exception e) { + return "Mixin class not found"; + } + List configs; + try { + configs = (List) Reflection.clazz(MixinService.class) + .get("getService()") + .get("transformationHandler") + .get("transformer") + .get("processor") + .get("configs") + .get(); + } catch (Exception e) { + return "Error getting mixin config: " + e; + } + + List> datas = new ArrayList<>(); + datas.add(PrintHelper.createLine("Name", "Mixin Package", "Priority", "Required", "Targets")); + for (Object config : configs) { + if (config instanceof IMixinConfig) { + IMixinConfig cfg = (IMixinConfig) config; + datas.add(PrintHelper.createLine( + cfg.getName(), + cfg.getMixinPackage(), + Integer.toString(cfg.getPriority()), + Boolean.toString(cfg.isRequired()), + Integer.toString(cfg.getTargets().size()) + )); + } else { + System.err.println(config + " is not instance of IMixinConfig"); + } + } + + return PrintHelper.printLine("\n\t\t", datas); +// return Mixins.getConfigs().stream().map(Config::getName).collect(Collectors.joining(", ")); + } + + @Override + public String getLabel() { + return "Mixin Configs"; + } +} diff --git a/src/main/java/me/xfl03/morecrashinfo/crash/ModList.java b/src/main/java/me/xfl03/morecrashinfo/crash/ModList.java index 819e3f7..d5fba37 100644 --- a/src/main/java/me/xfl03/morecrashinfo/crash/ModList.java +++ b/src/main/java/me/xfl03/morecrashinfo/crash/ModList.java @@ -8,7 +8,7 @@ import java.util.ArrayList; import java.util.List; -public class ModList extends CommonCrash { +public class ModList extends CommonCallable { @Override public String getLabel() { return "Forge Mods"; diff --git a/src/main/java/me/xfl03/morecrashinfo/handler/CrashHandler.java b/src/main/java/me/xfl03/morecrashinfo/handler/CrashHandler.java index 4915371..507a0de 100644 --- a/src/main/java/me/xfl03/morecrashinfo/handler/CrashHandler.java +++ b/src/main/java/me/xfl03/morecrashinfo/handler/CrashHandler.java @@ -2,37 +2,24 @@ import cpw.mods.modlauncher.log.TransformingThrowablePatternConverter; import me.xfl03.morecrashinfo.MoreCrashInfo; -import me.xfl03.morecrashinfo.crash.CoreModList; -import me.xfl03.morecrashinfo.crash.ModList; +import me.xfl03.morecrashinfo.crash.*; import me.xfl03.morecrashinfo.handler.exception.*; import me.xfl03.morecrashinfo.util.ReflectionHelper; -import net.minecraftforge.fml.ISystemReportExtender; +import me.xfl03.morecrashinfo.util.VersionUtil; import java.util.*; import java.util.function.Function; -import java.util.stream.Collectors; public class CrashHandler { private static final Map, Function> handlers = new HashMap<>(); - static { - try { - MoreCrashInfo.logger.info("CrashHandler.static"); - CrashHandler.registerHandler(VerifyError.class, VerifyErrorHandler::new); - - List callables = ReflectionHelper.getCallables(); - callables.add(new ModList()); - callables.add(new CoreModList()); - MoreCrashInfo.logger.debug("Callable list size {}", callables.size()); - MoreCrashInfo.logger.debug("Callable list member {}", callables.stream() - .map(ISystemReportExtender::getLabel).collect(Collectors.joining(", "))); + private static void initHandlers() { + registerHandler(VerifyError.class, VerifyErrorHandler::new); + } - ReflectionHelper.printCallables(); -// ReflectionHelper.testCallables(); - } catch (Exception e) { - MoreCrashInfo.logger.warn("Error register callable"); - MoreCrashInfo.logger.warn(e); - } + static { + initHandlers(); + CallableManager.initCallables(); } private static ExceptionHandler handler; @@ -60,6 +47,10 @@ public static String generateEnhancedStackTrace(final Throwable throwable) { StringBuilder stringbuilder = new StringBuilder(); handler.handleException(stringbuilder); stringbuilder.append(TransformingThrowablePatternConverter.generateEnhancedStackTrace(throwable)); + //In 1.13-1.14, add callables message here + if (VersionUtil.getMinecraftMajorVersion() <= 14) { + stringbuilder.append(CallableManager.getCallableMessages()); + } return stringbuilder.toString(); } } diff --git a/src/main/java/me/xfl03/morecrashinfo/util/Reflection.java b/src/main/java/me/xfl03/morecrashinfo/util/Reflection.java new file mode 100644 index 0000000..a4529ff --- /dev/null +++ b/src/main/java/me/xfl03/morecrashinfo/util/Reflection.java @@ -0,0 +1,65 @@ +package me.xfl03.morecrashinfo.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Reflection { + private final Class clazz; + private Object instance; + + public Reflection(Class clazz) { + this.clazz = clazz; + } + + public Reflection(Object instance) { + if (instance == null) { + throw new IllegalArgumentException("Instance cannot be null"); + } + this.clazz = instance.getClass(); + this.instance = instance; + } + + public static Reflection clazz(String className) throws ClassNotFoundException { + return new Reflection(Class.forName(className)); + } + + public static Reflection clazz(Class clazz) { + return new Reflection(clazz); + } + + public static Reflection clazz(Object instance) { + return new Reflection(instance); + } + + private Reflection getField(String field) throws Exception { + Field field0 = clazz.getDeclaredField(field); + field0.setAccessible(true); + return new Reflection(field0.get(instance)); + } + + private Reflection invokeMethod(String method) throws Exception { + Method method1 = clazz.getDeclaredMethod(method); + method1.setAccessible(true); + return new Reflection(method1.invoke(instance)); + } + + /** + * Get field or invoke method + * + * @param fieldOrMethod fieldName or methodName() + * @return result + * @throws Exception + */ + public Reflection get(String fieldOrMethod) throws Exception { +// System.out.println("Getting " + fieldOrMethod); + if (fieldOrMethod.endsWith(")")) { + return invokeMethod(fieldOrMethod.replace("()", "")); + } else { + return getField(fieldOrMethod); + } + } + + public Object get() { + return instance; + } +} diff --git a/src/main/java/me/xfl03/morecrashinfo/util/VersionUtil.java b/src/main/java/me/xfl03/morecrashinfo/util/VersionUtil.java new file mode 100644 index 0000000..028466d --- /dev/null +++ b/src/main/java/me/xfl03/morecrashinfo/util/VersionUtil.java @@ -0,0 +1,30 @@ +package me.xfl03.morecrashinfo.util; + +import me.xfl03.morecrashinfo.MoreCrashInfo; +import net.minecraftforge.fml.loading.FMLLoader; + +import java.lang.reflect.Field; + +public class VersionUtil { + public static String getMinecraftVersion() { + Class fmlLoaderClass = FMLLoader.class; + try { + //1.13-1.16 + Field mcVersionField = fmlLoaderClass.getDeclaredField("mcVersion"); + mcVersionField.setAccessible(true); + return (String) mcVersionField.get(null); + } catch (NoSuchFieldException e) { + //1.16-1.19 + return FMLLoader.versionInfo().mcVersion(); + } catch (IllegalAccessException e) { + MoreCrashInfo.logger.warn("Error getting mcVersion"); + MoreCrashInfo.logger.warn(e); + return "1.16.5"; + } + } + + public static int getMinecraftMajorVersion() { + String[] s = getMinecraftVersion().split("\\."); + return Integer.parseInt(s[1]); + } +}