|Back to Business (or Minecraft)|
Back to Business (or Minecraft)
Posted on May 4th, 2014 23:56
It sure seems like my yearly site anniversary curse is being accompanied by a horrible, younger sibling a month earlier. I somehow lost all of the Reality's End git tree -- including almost a year of unpushed changes.
So back to Minecraft.
You may have noticed that my server was either saddled with an old version (1.6.x) or was a head-of-line version without my fun changes. This is because the Mod Coder Pack had fallen woefully behind, and I had been using MCP to do my decompiling.
I've managed to forward port all of my changes without MCP, and so (since this was supposed to be the point of this log section) here is how I done'd it, you Googlers you.
What You'll Need
Now, you might be a little confused as to why the MCP was listed when this entire write-up is about modding Minecraft without MCP. Well, although it is behind (and through no fault of that crew's own -- deobfuscating is hard work), it provides two big advantages.
First, it has the Fernflower Java decompiler bundled in it. So that'll save you a trip.
Second, the structure of Minecraft's code doesn't completely change with every release, so although obfuscation will make the class objects completely incompatible, it will give you a good place to look when trying to determine which method is what in the cryptic code. And if you use the same decompiler as MCP, the decompiled bytecode will have the same structure, which will make matching up class source easier.
If you are wondering "What is obfuscation?", it is the intentional muddling of something (in this case, code) in order to make it harder to understand. Because Java's bytecode has plain strings for all of its classes and methods, one could very potentially reverse-engineer the binaries and make a modified Minecraft. (Hey, that's what we're trying to do~!) Mojang, of course, doesn't want that happening, as some scrupleless and rather smelly individuals could use this to bypass the whole pay aspect. (We don't want to do this.)
Thus, before a release, the legible code is obfuscated into a series of short, confusing, and unrecognizable strings so that a casual reader would have no clue what the code is attempting to accomplish. Computers are much less picky than you -- I mean, we -- humans, so they'll have no problem with it.
In fact, the obfuscation is so clever that it takes full advantage of polymorphism just to mess with you. It will name entirely different methods the same thing but still differentiate them by their return type and parameter lists. (Compare this to naming related functions the same thing but using different parameter lists to increase the code's writeability.) So in order to understand things from a human perspective, you'll have to track down the classes of the parameters -- which could very well be a subclass of what the method is calling for -- all of which are indeciperable strings of jibberish which give you no hint as to their proper usage. You may end delve down quite a few paths before you even find the one that is relevant.
The following example assumes the path of Fernflower in MCP. You can have Fernflower anywhere, really. I am using Linux, but the Java SDK's commandline syntax is the same across operating systems.
It should be obvious that you have to change the paths to reflect your own set-up. I am working out of minecraft in my home directory.
Fernflower generates a .jar file of sources. You will have to unpack this for viewing and modification. As a bonus, git init/git add -A the decompiled source directory to track your changes more easily. (If you don't use Git, then start now, dag-nabbit! Then you can share patches and mix 'em with others' patches!)
Modifying the Code
Few of the decompiled sources are named anything meaningful. You'll have to do a lot of grepping for relevant strings. Although class and method names are obfuscated, string literals for resources are not. So, you can track down anything that uses a sound or image asset, such as items, blocks, or mobs.
Look for a meaningful string literal (or, failing that, an interesting looking number) in a MCP source file, and then grep for it in the decompiled source. Although the MCP source is older, you'll probably be able to find the same literal in both source trees; if it appears in multiple files, use the context in which the literal appears to determine which file actually matches the MCP file.
Most of the objects in Minecraft occupy the default package, which is to say no package (the files lack the "package" declaration at the top). This wreaks havoc on scoping. In one file, I had to change:
just to get it to compile. This is because the obfuscated class name a was clashing with a member variable a. (Method a, also pictured, did not factor into the problem.) Since there is no way to fully qualify something in the default package, I resorted to using reflection to address the class by name by string. Since a (well, one of them) is an enum, I then grabbed element o by doing some char math, since each element is obfuscated as a single letter. In most situations, you would have to do a getMethod or getField call -- whatever is appropriate. (For the record, this is just to set the chat color to yellow.)
As long as you don't change the API, you'll be able to recompile only the classes you have modified. You can use the normal Minecraft class files to build against, and this requires a lot less work, too.
First, unpack the Minecraft binary archive (not the source archive generated by Fernflower, but rather the one you fed into it):
If you are accustomed to tar, it is notable that the -C option doesn't work when extracting with jar, although the syntax is otherwise similar. So you'll have to change into whichever target directory you are extracting. Of course, a .jar is just a .zip with a meta information folder, so any program that can handle zips can also unpack jars. You'll need the Java SDK to do the rest of this, so I guess you just don't want to use it right now?
Add the directory into which you unpacked the binaries to your compile line as a classpath (-classpath or -cp -- the path where classes can be found):
You can compile more than one file at a time, and you don't have to compile all of your sources at the same time. If you make one change, you can make a change to a different class and only recompile the new one.
You may encounter problems (like I did) which will require you to recompile files you did not modify, especially if you see the comment $FF: synthetic method in a code file. This is because, according to the bytecode, a particular method does not exist, but for whatever reason, the Fernflower decompiler created it and used it in the decompiled source. The method still does not exist in the original binary, however, so you will have to rebuild the class to create it so that the file you did modify can use it.
In order to use your new files, they must be added to the appropriate .jar file. The easiest way to do this is just to use the jar command to update it:
A .jar file is just a .zip file with meta information, so you will often see it recommended online to use regular zip archiving software. This requires an additional step deleting the META-INF folder to prevent things from going horribly, horribly wrong. If you just use the jar command as is intended, you keep the META-INF folder, too, which is there for more than no reason (thus the whole "horribly wrong" thing).
Too many modders are not also proper coders, so this sort of misinformation spread across the internet and was never cured.
With your archive updated, you can now fire up Minecraft or your server and point it to your new .jar to see your changes in action! If you ever make more changes, you can just continue adding them to your .jar file.
When a new version of Minecraft is released, all of the class and method names will be different. You'll have to go through the steps of finding string literals and racking your brain over obfuscated code all over again to get your changes in a newer version. But if you have all of your changes in nice little patches (even if they won't apply), you'll at least have a nice, focused set of changes to look for.
No discussions exist yet for this. You can start one if you would like.
|Copyright © 1999-2021|