Skip to content

Tutorial (1.17 to 1.20.4)

ThisTestUser edited this page Sep 9, 2024 · 35 revisions

Note: VERSION refers to the version you want to decompile, like 1.17.

Starting Up

This guide is for versions 1.17-1.20.4.

The first thing you want to do is to download mcp940.zip (https://minecraft.wiki/w/Tutorials/Programs_and_editors/Mod_Coder_Pack#Downloads). Extract the zip file to a folder and open up mcp940/conf/version.cfg. Replace 9.40 with something else (e.g. 9.41) and set the client and server version to the version you want to decompile. This will serve as a starting point for our custom fixes.

Then, clone MCPConfig (https://github.com/MinecraftForge/MCPConfig) and run "gradlew :VERSION:makeObfToIntermediate" and "gradlew :VERSION:fernflowerLibrariesJoined" on the command line. This will create a txt file of the list of libraries required, as well as a mapping file in tsrg format. Do not delete MCPConfig until you've finished this entire tutorial, because the decompiler process will reference libraries from there. Go to MCPConfig/build/versions/VERSION/ and copy obf_to_intermediate.tsrg, as well as joined.fernflower.libs.txt to mcp940/conf.

Runtime JARs

In order to decompile properly, you'll need to update the JARs used to process the class files. Go to MCPConfig/versions/release/VERSION/config.json to find the versions of the JARs you need to download. The JARs you need are ForgeFlower and vignette (or ForgeAutoRenamingTool for 1.18 and up), the latter of which will replace SpecialSource. Use the below links to download the files, ensuring that you replace the version number with your version (you MUST use the correct version).

https://maven.minecraftforge.net/net/minecraftforge/forgeflower/1.5.498.12/forgeflower-1.5.498.12.jar

https://maven.minecraftforge.net/net/minecraftforge/lex/vignette/0.2.0.10/vignette-0.2.0.10.jar

For 1.18 and up, vignette.jar is replaced by ForgeAutoRenamingTool. Copy the below link, replace the version number with your version, and download the JAR. This JAR file still replaces SpecialSource.

https://maven.minecraftforge.net/net/minecraftforge/ForgeAutoRenamingTool/0.1.17/ForgeAutoRenamingTool-0.1.17-all.jar

Once you've downloaded them, go to mcp940/runtime/bin and delete mcinjector.jar, fernflower.jar, and specialsource.jar. Rename the ForgeFlower JAR to fernflower.jar, vignette to vignette.jar if on the 1.17 versions, and if on 1.18+, rename ForgeAutoRenamingTool to ForgeAutoRenamingTool.jar. Then drag them inside the bin bolder.

For 1.17.x, find the resources folder of this repository and download ParameterAnnotationFixer$Visitor.class. Go to net/minecraftforge/lex inside vignette.jar and replace the ParameterAnnotationFixer$Visitor.class that exists inside. This will fix a crash when processing a library class file with the server JAR.

Downloading Libraries

To download libraries, run this command with my fixer tool: java -jar fixer.jar -v "MINECRAFT_VERSION" -w "YOUR_PATH/mcp940" -mode download. This will eliminate the need for MCP to copy libraries. Note that the server JAR will also be downloaded to mcp940/jars and be decompiled by MCP. If you don't want that, rename or delete the server JAR.

For 1.18 and up, the fixer tool will automatically handle the bundled server JAR by extracting its libraries and actual server JAR. You don't need to worry about this, but if you are going to manually download the server JAR just know that extra steps are needed here.

Now run the library adder: java -jar fixer.jar -w "YOUR_PATH/mcp940" -mode adder. This will fetch additional libraries from MCPConfig that are required in the classpath. Look in joined.fernflower.libs.txt for the updated libraries list. You will see that the required libraries have been redirected to the MCP folder. Do not delete MCPConfig, though, as some libraries will still be referenced from there.

MCP Mappings and Patches

The next part is to get the MCP mappings for your version. Go to mcp940/conf, and delete the entire patches folder, exceptor.json, joined.exc, joined.srg, STATIC_METHODS.txt, as well as fields.csv, methods.csv, and params.csv. You should already have the obf_to_intermediate.tsrg and the libraries text file from earlier.

The new CSV files can be derived from the official mappings with my fixer tool. You will need to download the client and server obfuscation maps, which you can find at the Minecraft wiki (https://minecraft.wiki/w/Java_Edition_VERSION) by looking for the "Obfuscation Maps" section. Download them to the conf folder in MCP as client.txt and server.txt.

The obfuscation maps will not contain parameter names, nor will they contain javadocs (comments). If you would like to include community-sourced names and comments, head to the ParchmentMC maven repository at https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/ and download the mappings for your version. The ZIP file you download must contain the word checked, do not use any other versions or the code will not recompile correctly. Extract the JSON file inside to the conf folder in MCP.

Now, run java -jar fixer.jar -c "YOUR_PATH/mcp940/conf" -mode csv. This will generate all 3 CSV files. If you included the ParchmentMC JSON you will see that params.csv has entries inside.

For the patches, you will need the fixer tool again to reformat them to the MCP format. Run java -jar fixer.jar -i "YOUR_PATH/MCPConfig/versions/release/VERSION" -o "YOUR_PATH/mcp940/conf" -mode patch.

The following steps involve patching the code and config used to run MCP. This is necessary since the JARs used for decompiling and remapping now accept tsrgs instead of srgs. It is highly recommended to use Notepad++.

mcp.cfg

This file is located at mcp940/conf/mcp.cfg.

Find [EXCEPTOR]. Add the following below:

XClientMappings = %(DirConf)s/obf_to_intermediate.tsrg
XServerMappings = %(DirConf)s/obf_to_intermediate.tsrg
XClientLibPath  = %(DirConf)s/joined.fernflower.libs.txt
XServerLibPath  = %(DirConf)s/joined.fernflower.libs.txt

Find jsr305/. There should be 2 results. Add ,%(DirJars)s/libraries/ca/weblite/java-objc-bridge/1.0.0/java-objc-bridge-1.0.0.jar to the end of the first line (ClassPathClient). If on 1.18+, also append ,%(DirJars)s/libraries/org/jetbrains/annotations/23.0.0/annotations-23.0.0.jar to the end of both lines. Now, check joined.fernflower.libs.txt for the specific version of java-objc-bridge and annotations, and replace the version strings if they are different from what is on here. Also check the version of jsr305 and modify the version as needed.

Search for IgnorePkg. Add ,joptsimple,META-INF to the end of that line. This is only to deal with extra library class files in the server JAR.

Delete the line starting with UpdateUrl.

Find SpecialSource, below the section that starts with [COMMANDS]. Currently it links to specialsource.jar, so change it to vignette.jar if on 1.17.x, otherwise change it to ForgeAutoRenamingTool.jar for 1.18+. MCInjector has no replacement, so it isn't necessary to change the line above.

Find CmdSS. For 1.17.x only, replace everything after the equals sign with %s -jar %s --jar-in {input} --jar-out {output} --mapping-format tsrg2 --mappings {mappings} --fernflower-meta --cfg {libraries} --create-inits --fix-param-annotations.

If your version is 1.18+, replace everything after the equals sign (in CmdSS) with %s -jar %s --input {input} --output {output} --map {mappings} --cfg {libraries} --ann-fix --ids-fix --src-fix --record-fix.

CmdSSReobf doesn't need to be modified, as reobfuscating isn't possible anyways.

Find CmdFernFlower. For 1.17.x only, replace after the equals sign with %s -jar %s -din=1 -rbr=1 -dgs=1 -asc=1 -rsy=1 -iec=1 -jvn=1 -isl=0 -iib=1 -log=TRACE -cfg {libraries} {input} {output}. For 1.18+, replace after the equals sign with %s -jar %s -din=1 -rbr=1 -dgs=1 -asc=1 -rsy=1 -iec=1 -jvn=1 -isl=0 -iib=1 -bsm=1 -dcl=1 -log=TRACE -cfg {libraries} {input} {output}.

Find CmdRecomp. Look for two instances of 1.8, and replace both with 16 for 1.17.x, or 17 if on 1.18+. This indicates that the resulting class files will require the correct version of Java to use.

Even though 1.8 also appears in CmdRecompScala, you don't need to change it, as it isn't used anyways.

commands.py

This file is located at mcp940/runtime/commands.py. Remember that indentations are important in Python, so do not mess them up!

Find self.checkcommand('mcinjector', '%s --version' % self.exceptor, java=True). Delete this line and the if statement above.

For 1.18+, find self.checkcommand('specialsource', '%s --version' % self.specialsource, java=True), and also delete that line and the line above.

Find self.has_srg = False. Change False to True.

For 1.18+, delete the line jarslwjgl.append(os.path.join(self.dirjars,self.mcLibraries['jinput']['filename'])).

Find and delete jarslwjgl.append(os.path.join(self.dirjars,self.mcLibraries['lwjgl_util']['filename'])).

Find # HINT: We read keys relevant to exceptor. Add the following lines below:

self.xclientmappings = os.path.normpath(config.get('EXCEPTOR', 'XClientMappings'))
self.xservermappings = os.path.normpath(config.get('EXCEPTOR', 'XServerMappings'))
self.xclientlibpath = os.path.normpath(config.get('EXCEPTOR', 'XClientLibPath'))
self.xserverlibpath = os.path.normpath(config.get('EXCEPTOR', 'XServerLibPath'))

Find self.has_exc = False. Change False to True.

Find def applyss(. A couple of changes are needed in this function for this to work:

Start by pasting the below lines right below def applyss(.

mapping = {CLIENT: self.xclientmappings, SERVER: self.xservermappings}
libpath = {CLIENT: self.xclientlibpath, SERVER: self.xserverlibpath}

Find out_jar = {CLIENT: self.rgclient. Replace the entire line with out_jar = {CLIENT: self.xclientout, SERVER: self.xserverout}[side]. Normally, MCP would apply SpecialSource and then pass the output to MCInjector, but here we are directly passing the output to FernFlower.

Scroll down to if srg_names: a few lines below (do not use find, there are multiple results). Delete the entire if statement and the else that is after it. You should have deleted 6 lines.

Then delete the 2 lines where identifier and srg are set below. This is right below the line cmd = self.cmdss.

Right below are 2 lines that start with sscp =. Delete both.

The line right below should start with forkcmd = cmd.format(classpath=sscp,. Replace the entire line with forkcmd = cmd.format(input=in_jar, output=out_jar, mappings=mapping[side], libraries=libpath[side]).

Delete the 4 lines under the forkcmd line you just modified.

Scroll down to self.runcmd(forkcmd) (once again, do not search), and delete 3 lines below, starting from the if statement. Do not delete the runcmd line.

Find def applyff(self, side):. Make the following changes:

Below the line pathsrclk =, add libpath = {CLIENT: self.xclientlibpath, SERVER: self.xserverlibpath}.

Scroll down to forkcmd = a few lines below. Replace the entire line with forkcmd = self.cmdfernflower.format(input=ffinput[side], output=pathsrclk[side], libraries=libpath[side]).

Now search for if pkglk[side]:. This is where package-info.class is added, which we don't need anymore. Change the line to if False:.

Search for def process_rename(self, side):. Scroll down a bit until you see regexps = {. The mapping format has changed since the switch to Mojang mappings, so replace the 3 lines below with the following (make sure the indents are correct):

'methods': re.compile(r'm_[0-9]+_'),
'fields': re.compile(r'f_[0-9]+_'),
'params': re.compile(r'p_[0-9]+_'),

Scroll down a bit more until you find # HINT: update reobf srg. Delete the two updatefile lines that are below the comment, which should contain reoblk and excmeta, respectively.

Find if i.filename.startswith(p):. Replace with if i.filename.startswith(p) and side == SERVER and not i.filename.startswith("com/mojang/math"):. This will prevent IgnorePkg from triggering on the client side and allow for com/mojang/math to be included as source on the server side.

Find wrapper = TextWrapper(width=120). Replace the contents inside regexps = { with the following (check indents). This will allow comments to be placed above fields and methods when the ParchmentMC mappings are used.

'field': re.compile(r'^(?P<indent> {4}|\t)(?:[\w$.[\]]+ )*(?P<name>f_[0-9]+_) *(?:=|;)'),
'method': re.compile(r'^(?P<indent> {4}|\t)(?:[\w$.[\]]+ )*(?P<name>m_[0-9]+_)\('),

Find ignore_dirs = [os.path.normpath(p) for p in self.ignorepkg] (2 instances) and replace both with ignore_dirs = [].

Find configpathserver.extend(configpathserver). This is a typo in the MCP code. Change it to cpathserver.extend(configpathserver).

If in 1.18 and above, you need to load libraries for the server into the classpath, as they are now separate from the server JAR. Add addserverlibs('jars/serverLibraries', cpathserver) above self.cpathserver = [os.path.normpath(p) for p in cpathserver].

Then, above def reallyrmtree(path):, paste in this definition of addserverlibs:

def addserverlibs(folder, liblist):
    for root, dirs, files in os.walk(folder):
        for file in files:
            if file.endswith(".jar"):
                liblist.append(os.path.join(root, file))
    return liblist

If your default Java installation is too old, you'll need to point the Java path to a new version of Java. Download the latest JDK 17 compressed archive and extract it a folder. Now search for self.cmdjavac =, replacing that with self.cmdjavac = r'"YOUR_JDK_PATH\bin\javac"', where YOUR_JDK_PATH is the path to Java 17. Now go to self.cmdjava = and replace that with self.cmdjava = r'"YOUR_JDK_PATH\bin\java"', also setting YOUR_JDK_PATH.

For 1.18+, the JAR signature needs to be removed before decompilation. Search for c = zip_in.read(i.filename) and add the following four lines below (be sure the indentation is correct):

if i.filename == 'META-INF/MANIFEST.MF':
    c = 'Manifest-Version: 1.0\nMain-Class: net.minecraft.client.Main\n\n'
if i.filename.startswith('META-INF/MOJANGCS'):
    continue

For 1.19 and above, find if not os.path.exists(self.dirnatives): and delete that line and two lines below.

mcp.py

This file is located at mcp940/runtime/mcp.py.

Find Creating SRGs. Delete that line and the line below.

Find Applying MCInjector. Delete that line and the line below.

Find Creating renamed srg. Delete that line and the line below.

decompile.py

Find commands.setupjsr305() and delete it. Moving extra libraries is already handled by the fixer tool.

Conclusion

At this point, you should run decompile.bat and everything should work properly. If it didn't, that means that you probably messed up somewhere. Be sure to use the latest version of JDK 17, as earlier versions have some compilation issues in 1.18.x.

Since the official mappings were used, there should be no issues with the resulting code, provided you configured your IDE to use the correct Java version.

Remember that the decompiled Minecraft code may not be distributed. If you wish to make mods for Minecraft that require being able to edit the base code whenever you want, I highly recommend you use Fabric. It is much less burdensome and you can easily update to a newer version when needed.