# How to use almost any Forge mod as a dependency

asanetargoss, 2021-11-02

!!! : Disclaimer
    I mostly mod on 1.10, which uses Forge Gradle 2. Any statements for later versions are an educated guess. YMMV. Also, I use Eclipse.

!!! Warning: A friendly reminder
    Please respect the wishes of mod authors, and comply with the licenses and legal requirements of any mods you use (copyright, author's rights, moral rights, etc).

If you want the code of your Minecraft Forge mod to interact directly with the code of another Minecraft Forge mod, you will need to add it as a dependency. I generally refer to mod code that interacts with another mod as "cross-mod compatibility," unless the other mod is a general-purpose library or utility mod.

Hardcore Alchemy has quite a bit of cross-mod compat. Version 0.6.1 of the Hardcore Alchemy capstone mod has 18 compile-time dependencies, not taking into account library mods and other testing mods. For comparison: the record holder for most mod dependencies in a single mod probably goes to either the GTNewHorizons team, or Reika. By one account, Reika at one point used a whopping 142 mods for mod testing and development! Phew! Suffice to say, the sky's the limit as far as mod dependencies go, provided you have enough RAM to run the mods in the first place. That being said, version 0.7.0 of the Hardcore Alchemy capstone mod will be split into smaller mods each with a fewer number of compile-time dependencies, so it's unlikely to break any records.

If you're a Java developer or have interacted with any programming language-specific package manager, and you're not too familiar with modding, you'd probably guess that the best way to add a mod as a dependency is by adding a few lines to your build script or packages list to download the dependency from a remote repository. However, many mods aren't so easy to set up with a few lines of gradle: they may be closed source, don't have a dev jar that's compatible with your dev workspace, or their Maven repositories or Curseforge pages may disappear at any time. Perhaps the mod is open source, but the mod may be nontrivial to compile.

For these reasons, my main method for adding mod dependencies is by adding the mod jar to a local folder and have build.gradle depend on that. I'll go over that and other methods below.

## Gradle / IDE setup

### Forge Gradle setup - Open source method

If a mod has up-to-date instructions for how to add the mod as a dependency to your mod's build.gradle, you should just use that.

Then, run Forge gradle setup tasks.

### Forge Gradle setup - General method

My primary method for using mods in a Forge mod dev environment for Eclipse goes something like this:

- Create `folder_of_your_choice`
- Add to said folder [CodeChicken Core](https://www.curseforge.com/minecraft/mc-mods/codechicken-core-1-8) + [CodeChickenLib](https://www.curseforge.com/minecraft/mc-mods/codechicken-lib-1-8)
    - In 1.11+, try adding only CodeChicken Lib
    - The intent is to allow non-dev mods to be used in a mod dev environment, by adding a coremod which converts the mod's Searge names to dev names
    - A fair warning: On rare occasions, in a development environment only, the CodeChicken mod(s) will sometimes not run mappings on mods correctly when the game is loading, leading to NoClassDefFoundError or NoSuchMethodError. I have found that re-running gradle setup scripts fixes the problem.
- Add the regular, non-dev mod jar to the same folder
- Add to build.gradle to allow including mod jars: `dependencies  { compileOnly fileTree(dir: "folder_of_your_choice", include: "**/*.jar") }`
    - In Forge Gradle 2, which 1.10 uses, the `libs/` folder next to build.gradle is automatically added by Forge as a place you can add mod jars, so if `folder_of_your_choice` is `libs/` then you can skip this step
- Run Forge gradle setup tasks

### Setting up Eclipse to work with mods without source code

To easily view mods as if they have source code, I use plugins.

- The [JD Java Decompiler Plugin for Eclipse](https://java-decompiler.github.io/) lets me view a mod as if I have its source code
- If/when the decompiler doesn't work on a .class file, I close all tabs with that .class file and then re-open the .class file
- For when JD flat-out doesn't work, or if I need to do coremodding, I use [Andrei Deloskutov's bytecode outline for Eclipse](https://marketplace.eclipse.org/content/bytecode-outline). This adds a new window view type called "Bytecode" which lets you see the Java bytecode of the currently active .class or .java file.

This particular combination of plugins is important. Not all Eclipse decompiler and bytecode plugins are compatible with each other. If the newest version of a plugin doesn't work, I try an older version.

When I need to understand a Searge name in a mod, I use [MCP Mapping Viewer](https://github.com/bspkrs/MCPMappingViewer/).

### Generating source attachments for closed source mods

I do not use this method often because decompiled source code produced by fernflower does not match up with the line number annotations in a mod jar, which causes issues when debugging. However, the resulted decompiled source may be formatted better. This method involves roughly the following steps:

- Decompile the mod
- Deobfuscate the mod
    - Here, I'm using the term "deobfuscate" rather loosely. Mods typically aren't truly obfuscated. Instead, any references to functions and fields in vanilla classes are obfuscated-looking Searge names, which need to be converted to human-readable dev names
    - The dev names in the "deobfuscated" mod must match the mappings version defined in your build.gradle file, or your development test runs may crash
- If needed, put the mod's deobfuscated source code back into a .jar file suitable for use as a source attachment
- Some Gradle stuff, or alternatively IDE stuff, to use the source attachment alongside the respective mod jar

Some resources to consider:

- Official Forge documentation
- fernflower (consider instead the fork ForgeFlower, which may produce more consistent source code output)
- My python3 script [MCP Mapping Viewer Mapper](https://github.com/asanetargoss/mmvmap) and its accompanying README
    - Yes, it indeed says "not recommended for add-on development". This is due to the various caveats I've described in this article.
- [Bearded Octo Nemesis](https://github.com/immibis/bearded-octo-nemesis) - Deobfuscator, possibly suitable for very old versions only; I haven't tested it. Because it doesn't decompile the mod, it avoids creating debugging discrepancies, but you will still need to create a source attachment or use a decompiler plugin

Keep in mind that, unless you are deobfuscating the mod jar itself, rather than just the source attachment, you will still need something like CodeChicken to make the mod work in a dev environment.

### Compiling third-party mods from source for use in a development environment

If a mod is free and open source, and doesn't look too intimidating to compile, you can create dev jars and source attachments for the mod from source. On 1.10 (Forge Gradle 2), that means gradle tasks like these should be in build.gradle, and then the gradle build task will create dev and source jars for you:

task deobfJar(type: Jar) {
    from sourceSets.main.output
    classifier = 'dev'

task sourcesJar(type: Jar) {
    from sourceSets.main.allJava
    classifier = 'sources'

artifacts {
    archives deobfJar
    archives sourcesJar

The resulting dev jar can be used as a mod dependency, even when CodeChicken Core and/or CodeChicken Lib are not present. Dev and source jars are usually the types of artifacts that are downloaded when a mod developer provides a gradle dependency snippet.

## Other tips

- Declare dependencies within your mod as needed, for example to make a mod required or limit the accepted version of a mod. If Forge detects a mismatch with your mod's dependencies while the game is loading, it will display an error to the player informing them of the missing or incompatible mod(s).
- Think about how to avoid crashes caused by missing mods (classloading errors)
    - Understanding Java bytecode will greatly improve your ability to prevent classloading errors.
    - [My summarized understanding of Java classloading](./mc_classloading_primer.md.html) may help you avoid some common classloading pitfalls.
- Almost no code is off-limits with the help of advanced techniques such as access transformers, reflection, and coremodding. That being said, there are caveats:
    - These techniques are difficult to use correctly.
    - Access transformers only work on vanilla classes.

^ Jump to top