Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.17] Minecraft exits without a crash report when mod dependencies are missing #7993

Closed
SuperMartijn642 opened this issue Aug 8, 2021 · 1 comment · Fixed by #8043
Closed

Comments

@SuperMartijn642
Copy link
Contributor

Minecraft Version: 1.17.1

Forge Version: 1.17.1-37.0.27

Logs:
Latest.log: https://gist.github.com/SuperMartijn642/71f4e0a7c69b58831723deb6ff58de0c

Steps to Reproduce:

  1. Download and open the MDK for 1.17.1 - 37.0.27
  2. Add the following dependency to mods.toml:
[[dependencies.examplemod]]
   modId="somemode"
   mandatory=true
   versionRange="[1,2)"
   ordering="NONE"
   side="BOTH"
  1. Build the mod using the gradle build task
  2. Start Minecraft in the vanilla launcher with the generated jar in the mods folder

Description of issue:
Outside of the dev environment, when a mod dependency is not installed the game exits without showing the mod loading error screen or generating a crash report.
Inside the dev environment the game shows the mod loading error screen as expected.

@SuperMartijn642 SuperMartijn642 added the Triage This request requires the active attention of the Triage Team. Requires labelling or reviews. label Aug 8, 2021
@SuperMartijn642 SuperMartijn642 changed the title [1.17] Minecraft exits without a crash report when dependencies are missing [1.17] Minecraft exits without a crash report when mod dependencies are missing Aug 22, 2021
@sciwhiz12
Copy link
Contributor

I've confirmed that this issue happens, and found the root cause for the issue.

What's All This About

The problem is what happens when ModSorter, the class in FML responsible for sorting mods based on dependency information, encounters a situation wherein there are unsatisfied mod requirements, such as missing mandatory dependencies or installed but incompatible optional dependencies.

For this situation, it stores a small list internally in a field called forgeAndMC. As you may surmise from the name of the field, this list should contain two mod files: the one containing the minecraft mod (which is the client JAR), and the one containing the forge mod (the Forge universal JAR).

This list is passed on as the "full mods list" in three situations:

  • There are errors during scanning of mod files;
  • There are unsatisfied dependencies; or
  • A cyclic dependency order is detected.

So theoretically, if any of the above were to happen, this would be fine: Forge and Minecraft are the only 'mods' in the mod list (from that forgeAndMC field), mod loading continues, the access transformer configurations are loaded, and it should just continue until it reaches the point where FML can display the mod loading errors screen.

UH OH

Now, did you notice how I emphasized "this list should contain two mod files" above? You may be able to surmise what I'm getting at here: the problem here is that that forgeAndMC list doesn't contain both Forge and Minecraft 'mods'. If you look at the ModSorter class, specifically a snippet from the top of buildUniqueList:

// Capture forge and MC here, so we can keep them for later
forgeAndMC = new ArrayList<>();
var mc = modFilesByFirstId.get("minecraft");
if (mc != null && !mc.isEmpty())
forgeAndMC.add((ModFile) mc.get(0));
else
throw new IllegalStateException("Failed to find minecraft somehow?");

Do you see the problem? That's right: only minecraft is captured in the list, and not forge. This essentially means that the forgeAndMC list only contains the Minecraft 'mod', and so when one of the exceptional situations above happens, that's the only mod that gets passed on to the rest of mod loading.

It All Comes Crashing Down

The problem with that mod list only containing the minecraft mod file is that it means the rest of the mod loading continues with the assumption that there is only one mod installed. In this case, we care about one specific subsystem that's affected here: access transformers.

The access transformer configuration files are stored in the mod file (in this case, the JAR file). When progressing through mod loading, it comes to a stage where it takes the list of mod files as dictated above, and loads the access transformer configuration files to the AccessTransformers subsystem.

However, if the situations above occur, then the only mod in that list is minecraft. This means that the forge mod, the one from the Forge universal JAR, is missing. Which also means that the access transformer configuration shipped with Forge, which is also from the Forge universal JAR, will not be loaded.

That leads to none of the expected access transformations expected by Forge to actually happen, which then causes a crash as soon as the first Forge class tries to access an AT'd field or method. In production, the first thing that does that is net.minecraftforge.registries.GameData$ClearableObjectIntIdentityMap, which accesses net.minecraft.core.IdMapper#tToId, a normally private field. That leads to the JVM throwing IllegalAccessError, which immediately traverses all the way up the chain and makes Minecraft (or at that point, FML) stop immediately. This is why the mod warning/errors screen is never reached, as this error makes FML quit well before that point in the game.

Why Aren't Developers Affected

The root issue as described, namely the absence of the forge mod in the forgeAndMC mod list, also affects the developer's environment, both userdev and forgedev. It leads to the same issue of the AccessTransformer subsystem not being configured, which leads to the runtime access transformation service not doing anything.

However, the key difference that's significant between the production and the development environments is when access transformers are applied. In the production environment, it's done at runtime by the AccessTransformers service. Meanwhile, in the developement environment, it's done at setup time by ForgeGradle.

This means that even if the runtime AT service doesn't do anything in the development environment, it has no need to: the access transformers are pre-applied before runtime, which means that the AT'd fields and methods are as expected, and no IllegalAccessError occurs.

How To Fix?

I can think of two solutions for this problem:

  1. Patch ModSorter to also include the forge mod, if present.
    This is the simplest solution to implement. However, this breaks the conceptual boundary between FML and Forge, as it hardcodes forge into FML's mod sorting code.

  2. Implement a way for FML to be made aware of "game-required" mods.
    I'm making up the term "game-required" here to mean a mod which is conceptually 'part' of the game and therefore passed into that forgeAndMC list. However, this would be more difficult to implement, as it possibly means refactoring parts of FML, which would need to go through cpw.

My preference is to go with option 1 first to quickly solve the problem at hand, while waiting for cpw to crop up again to truly tackle the issue and find a long-term solution. I'll probably make a PR to that effect very soon, so the option is on the table and ready to merge.

sciwhiz12 added a commit to sciwhiz12/MinecraftForge that referenced this issue Aug 31, 2021
@autoforge autoforge bot removed the Triage This request requires the active attention of the Triage Team. Requires labelling or reviews. label Feb 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants