I'll try to do that later on today ( have some things to do + paperwork to get ready for tomorrow )
Also, i'll include further useful informations in the first post, including the list of already referenced
obfuscated code.
I shall look into creating a little application to make the modding easier ( not an API as suggested above, it's out of my skill range but some sort of remove obfuscated code by replacing it with community provided code using a pattern that would adapt itself to updates )
Much appreciated! No super rush, just wanting to dig around in the code and see what pops up.
i think an intermediate layer might work to help describe the API. Set up a list of common functions that modders would like to use, (get block, set block, set spawn, etc) and have a version-based table (classic, alpha, smp, etc) of which obfuscated class and method relate to that function. That way when someone goes to look at the API, they see what the function does and what parameters it needs.
This would also allow the modder community to keep a semi-tight leash on what gets exposed to the community as a whole to help Notch keep a lot of the code obfusticated while allowing modders to tinker with exactly what they want. This also would give Notch an idea of what types of code hooks we'd want in an official API.
Quick question, as I've been running into the same problems a lot of people have been with trying to recompile the .java source back into the compiled class files.
Can one of you wonderful devs that have this working do a quick video walk-through (from scratch) in eclipse/netbeans/commandline showing how to recompile the java back into a class file?
I'd assume start from the extraction of the minecraft.jar, decompile something like a.class using JD, show us what you're editing in the file to get it to work, then recompile using whichever IDE/commandline you prefer. That should help those of us that are having problems and we might be able to catch something simple we're forgetting,
This seems to be the only real step that's stopping a few people from messing around with mods and getting comfortable with the obfuscated source.
On page 2 of this thread, I posted an extremely in-depth step-by-step with rationale including how to decompile, repair, recompile, lots of code snippets, what to change, how to insert back in to the jar and more. It's not a video because this kind of information is not particularly video-friendly, but it should have everything you need to get started.
Yeah, I've been re-reading a lot of it. For some reason netbeans refused to recompile anything I threw at it. I've gotten a few basic classes to recompile in the last few minutes using the javac technique. Not sure why Netbeans kept throwing errors repeatedly. Time to play around with a few files and see what i can do!
One thing I noted, if you are trying to recompile the net.minecraft.server.MinecraftServer class, I have no idea how to get that to work. I managed to get all the decompilation errors in it fixed but I could never get past packaging and linking issues.
I eventually got things to work for the simpler classes in the default package with Netbeans but it wasn't worth the effort, since the command line technique worked without all the project setup and fiddly "add this jar" oh wait, you added it in the wrong place add it here, or wait, that's not right etc, etc. Maybe for huge Java projects, Netbeans and Eclipse make the complexity manageable, I have always loathed both both of them for making what should be simple endlessly complex.
Yes, an API would be nice. The trick is finding the best places for extension points. I recommend a simple IPC system instead of making people implement a bunch of Java interfaces though.
So, I just ran into an issue trying to recompile the main menu (no edits), and am wondering if someone can help me figure out what's going wrong with it.
The main menu is set up in cx.class. I'm able to compile it and place it in to the jar just fine. When it gets around to doing the title menu, it's crashing because of a bad call in kc.class. The exact error is there is no method for cx.j() .
The offending line triggering the error in kc.java:
cx.j is a variable reference whereas cx.j() is calling a method. Also note that there may be a variable called cx in scope. It gets really fun when you come across things like "a.a.b()".
Recompilation guide using JavaC
Step 1: Locate javac and add it to your %PATH% variable (there are many guides out there if you're not sure how).
Step 2: Set up your development environment by creating a folder somewhere (example: c:\minecraft_dev).
Step 3: Copy all .jar's from the .minecraft/bin/ folder over to c:\minecraft_dev\bin folder. These should include: minecraft.jar, lwjgl.jar, lwjgl_util.jar, jinput.jar
Step 4: Follow the other guides in this thread to decompile whichever file you'd like into .java source code.
Step 5: Make whatever changes you would like to the .java file and save it into the base c:\minecraft_dev folder.
Step 6: Pop open a command prompt / terminal window and change to the folder >cd c:\minecraft_dev
Step 7: Compile the .java file into a class using the following line: C:\minecraft_dev\> javac -cp bin/minecraft.jar;bin/lwjgl.jar;bin/lwjgl_util.jar;bin/jinput.jar your.java
Step 8: After you've compiled the files you want to edit, add the updated classes to the minecraft.jar in your c:\minecraft_dev\bin folder. If you do not update this file with your new changes, the java linker will ignore any changes you've made when compiling classes.
Step 9: After inserting your class, copy your c:\minecraft_dev\bin\minecraft.jar into your .minecraft/bin folder to update the client with your new code.
An alternative is to put the full path for each of the .jar's listed above in the command line and do all your edits live on the ./minecraft/bin/minecraft.jar.
This should at least compile most of the simple class files provided in the minecraft.jar, although there will still be a good number of files that need manual edits to work.
This method could easily be converted into a batch file or shell script using a console version of zip / winrar to inject compiled class files directly into the jar.
So, I just ran into an issue trying to recompile the main menu (no edits), and am wondering if someone can help me figure out what's going wrong with it.
The main menu is set up in cx.class. I'm able to compile it and place it in to the jar just fine. When it gets around to doing the title menu, it's crashing because of a bad call in kc.class. The exact error is there is no method for cx.j() .
The offending line triggering the error in kc.java:
Heh, I had it as just h when I tested but then when I went to post, I thought it should be this.h just to satisfy convention. I had no idea it would make a difference!
(not an API as suggested above, it's out of my skill range but some sort of remove obfuscated code by replacing it with community provided code using a pattern that would adapt itself to updates )
I don't think it's above your skill level at all if you can manage to decompile and understand obfuscated code.
Quote from SpongeBob »
Yes, an API would be nice. The trick is finding the best places for extension points. I recommend a simple IPC system instead of making people implement a bunch of Java interfaces though.
I wasn't thinking of making the modder implement the interfaces, that would suck. Instead:
1. Develop a series of interfaces or abstract classes with no defined functionality.
2. Create a new assembly that inherits from those abstract classes or implements those interfaces
3. Modders code against the interfaces or abstract classes, in whatever fashion they like. It's an API.
4. When implementing the code, the modder throws their custom classes into the .JAR, the classes containing the interfaces, AND picks out the correct implementation for the version of minecraft.jar.
This diagram should help articulate what I'm talking about.
1. Develop a series of interfaces or abstract classes with no defined functionality.
2. Create a new assembly that inherits from those abstract classes or implements those interfaces
3. Modders code against the interfaces or abstract classes, in whatever fashion they like. It's an API.
4. When implementing the code, the modder throws their custom classes into the .JAR, the classes containing the interfaces, AND picks out the correct implementation for the version of minecraft.jar.
This diagram should help articulate what I'm talking about.
That would be awesome. So instead of 50 or 100 people reverse-engineering everything on every patch and developing separately, the API update could be handled by a few people, or even one person. Even though it's obfuscated, there shouldn't be so much changed that the code is completely unrecognizable between minor updates. Major updates like the Boo update coming at the end of the month will obviously require more work.
This tool, combined with the java decompiler will make you a very happy coder!
To use, extract out minecraft.jar to a folder, pop open one of the classes in JD, File->Save All Sources and save the .zip somewhere. Extract the .zip to a new folder and remember where it's at. This will be the working directory for Doxygen.
The Doxygen Wizard is pretty self explanatory but i'll walk through a few options:
The Projects section of the wizard:
The working directory is the folder you extracted the sources .zip file to. This is also the folder you put in for the source code location. Make sure you check the Scan Recursively box
Put the html files location wherever you want it to save the output to for later viewings.
Hit next
Mode Section of the wizard:
Select the desired extraction mode: All Entities and check the box by Include Cross-Referenced source code in the output.
Select the programming language to optimize the results for: Optimize for Java or C# output.
Output Formats:
Html for sure, with your choice of output for that. You can also do XML or latex or several others or processing in other programs.
Hit next
You can use the built-in class diagram generator or change the options here to suit your tastes.
That should be all you really need to set up the first time around.
click the run tab and hit "Run Doxygen".
After it's done, hit "Show Output" to open up whatever your default browser is with the generated code sitting there.
When it's all said and done, you should have something similar to:
Where you can look at the obfuscated class relationships and such. This should help greatly when the new code gets released. Using this you can go back and compare the code chains and parameters and quickly rematch up code fragments even after they've been reobfuscated.
If someone needs a more in depth version of this guide, I can do it step by step with screenshots, etc. but it really should be pretty self explanatory.
Search for the glowing redstone torch's ID number 76. You'll find a bunch of lines that set up the different properties of each block, like hardness, brightness, and opacity. Change them to your liking.
Anyone know where the new food code is stored? Ive searched them all twice
Do you mean the food item type? If so, so my post on Page 2.
Edit: Shameless in-thread piggy-back bump of findings:
Minecraft Alpha v1.1.2_01
oj.class - Generic superclass for Food Methods public oj(int paramInt1, int paramInt2)
paramInt1 - Passed to di superclass. Appears to be the Item ID.
paramInt2 - Sets attribute 'a'. Unsure of purpose; Does not appear to be stack-size. Requires further testing. Hearts Restored * 2.
Analysis / Findings:
Debugging has revealed this class is instantiated at login. Initial analysis appears to indicate paramInt2 determines how much health the item heals:
Debug: Item<4> - paramInt2: 4 // Apples heals 2.
Debug: Item<26> - paramInt2: 10 // Mushroom soup heals 5.
Debug: Item<41> - paramInt2: 5 // Bread heals 10
Debug: Item<63> - paramInt2: 3 // Pork heals 1.5
Debug: Item<64> - paramInt2: 8 // Grilled pork heals 4.
Debug: Item<66> - paramInt2: 42 // Surprisingly, the Golden Apple restores 21 hearts. (Instead of 10 - the current maximum)
public ev a(ev paramev, cn paramcn, dm paramdm)
paramev - Stack related - Used to decrement stack count. (paramev.a)
paramcn - Not used; nor is it used by di generic item-class. Likely used elsewhere.
paramdm - Damage related. Determines how much health to restore.
Analysis / Findings:
Method b of paramdm restores health. Suggests that dm represents an entity - likely as it extends kh dynamic-object generic (Possibly main player. Method will only restore health to a living player i.e. >0 health). It will not restore above maximum. Also appears to do something related to maximum health. (Related to attributed 'j' and 'aW' in dm - warrants further investigation.)
Noteworthy is the fact that the parameter is signed and no validation is done on 'negative' healing. This means that damaging foods (Poisons) should work. This has been tested and confirmed.
Attributes
aT (Inherited) - Max Stack Size.
a - Hearts Healed by Item * 2.
dw.class - Crafting Class Methods public dw()
To Test: Instantiated at start-up
Analysis / Findings:
Makes a number of calls, passing itself as parameter - requires further investigation.
Following this is a list of calls to a (see below).
public ev avoid a(ev paramev, Object[] paramArrayOfObject)
paramev - New item "stack" to create (Constructor takes a block-generic or item-generic and a number (init. stack size).
paramArrayOfObject - Name-Value pair for recipe - organisation as follows (Untested)
Analysis / Findings:
The first index is the top row of the recipe. Second is (optionally) the middle row. Third is (optionally) the bottom row.
The next index is the first character used to represent the top row.
The next index is the item or block represented by that character.
First parameter: Make a new stack of minecart tracks (16 in size).
Second parameter: Recipe - lets examine in detail:
"X X", "X#X", "X X", ---> Let's re-arrange into a more familiar format:
X X
X#X
X X
Next, lets look at the parameters that follow in the object array:
Character.valueOf('X'), di.m, Character.valueOf('#'), di.B
So:
'X' maps to di.m
'#' maps to di.B
di is the generic item class.
Attribute m: public static di m = new di(9).a(23);
To shorten the analysis: The constructor for di takes an integer, which represents the decimal data value of the item - 256.
256 + 9 = 265 = Iron Ingot (http://www.minecraftwiki.net/wiki/Data_values)
So X is iron ingot.
Attribute B public static di B = new di(24).a(53).d();
256 + 24 = 280 = Stick
Substitute "Iron Ingot" for X and "Stick" for # and we end up with:
Which is indeed the recipe for iron ingot.
Further information:
The size of the "Recipe box" appears to be dynamic - this seems to indicate a somewhat easily extensible crafting area.
The "item" and "block" substitution function appears to function for arbitrary length. This means there should be no upper bound on the items that can be used.
Take the above with a grain of salt; need to test.
Also, i'll include further useful informations in the first post, including the list of already referenced
obfuscated code.
I shall look into creating a little application to make the modding easier ( not an API as suggested above, it's out of my skill range but some sort of remove obfuscated code by replacing it with community provided code using a pattern that would adapt itself to updates )
i think an intermediate layer might work to help describe the API. Set up a list of common functions that modders would like to use, (get block, set block, set spawn, etc) and have a version-based table (classic, alpha, smp, etc) of which obfuscated class and method relate to that function. That way when someone goes to look at the API, they see what the function does and what parameters it needs.
This would also allow the modder community to keep a semi-tight leash on what gets exposed to the community as a whole to help Notch keep a lot of the code obfusticated while allowing modders to tinker with exactly what they want. This also would give Notch an idea of what types of code hooks we'd want in an official API.
On page 2 of this thread, I posted an extremely in-depth step-by-step with rationale including how to decompile, repair, recompile, lots of code snippets, what to change, how to insert back in to the jar and more. It's not a video because this kind of information is not particularly video-friendly, but it should have everything you need to get started.
I eventually got things to work for the simpler classes in the default package with Netbeans but it wasn't worth the effort, since the command line technique worked without all the project setup and fiddly "add this jar" oh wait, you added it in the wrong place add it here, or wait, that's not right etc, etc. Maybe for huge Java projects, Netbeans and Eclipse make the complexity manageable, I have always loathed both both of them for making what should be simple endlessly complex.
The main menu is set up in cx.class. I'm able to compile it and place it in to the jar just fine. When it gets around to doing the title menu, it's crashing because of a bad call in kc.class. The exact error is there is no method for cx.j() .
The offending line triggering the error in kc.java:
Declaration of j in cx.java
Any ideas what's causing this to not line up? I haven't found another reference in the parent classes for cx that reimplement j as a function.
cx.j is a variable reference whereas cx.j() is calling a method. Also note that there may be a variable called cx in scope. It gets really fun when you come across things like "a.a.b()".
Make sure you have the Java SDK installed on your system
http://www.oracle.com/technetwork/java/javase/downloads/index.html
Recompilation guide using JavaC
Step 1: Locate javac and add it to your %PATH% variable (there are many guides out there if you're not sure how).
Step 2: Set up your development environment by creating a folder somewhere (example: c:\minecraft_dev).
Step 3: Copy all .jar's from the .minecraft/bin/ folder over to c:\minecraft_dev\bin folder. These should include: minecraft.jar, lwjgl.jar, lwjgl_util.jar, jinput.jar
Step 4: Follow the other guides in this thread to decompile whichever file you'd like into .java source code.
Step 5: Make whatever changes you would like to the .java file and save it into the base c:\minecraft_dev folder.
Step 6: Pop open a command prompt / terminal window and change to the folder >cd c:\minecraft_dev
Step 7: Compile the .java file into a class using the following line:
C:\minecraft_dev\> javac -cp bin/minecraft.jar;bin/lwjgl.jar;bin/lwjgl_util.jar;bin/jinput.jar your.java
Step 8: After you've compiled the files you want to edit, add the updated classes to the minecraft.jar in your c:\minecraft_dev\bin folder. If you do not update this file with your new changes, the java linker will ignore any changes you've made when compiling classes.
Step 9: After inserting your class, copy your c:\minecraft_dev\bin\minecraft.jar into your .minecraft/bin folder to update the client with your new code.
An alternative is to put the full path for each of the .jar's listed above in the command line and do all your edits live on the ./minecraft/bin/minecraft.jar.
This should at least compile most of the simple class files provided in the minecraft.jar, although there will still be a good number of files that need manual edits to work.
This method could easily be converted into a batch file or shell script using a console version of zip / winrar to inject compiled class files directly into the jar.
Hope this helps a little.
I've reproduced this and I'm looking into it.
cx.j() as called by kc's constructor is looking for something that fits in like this:
I looked up nextDouble and that belongs to the Java Random class. So I looked in cx and noticed it had this:
That was the only random object in there. So I did what seemed obvious. I made a getter for it.
If you insert that method into cx.java, everything works again.
--Edit--
Had an error with this.h and statc vs nonstatic variables, replaced it with just h and it worked. Much appreciated for the help! =)
I don't think it's above your skill level at all if you can manage to decompile and understand obfuscated code.
I wasn't thinking of making the modder implement the interfaces, that would suck. Instead:
1. Develop a series of interfaces or abstract classes with no defined functionality.
2. Create a new assembly that inherits from those abstract classes or implements those interfaces
3. Modders code against the interfaces or abstract classes, in whatever fashion they like. It's an API.
4. When implementing the code, the modder throws their custom classes into the .JAR, the classes containing the interfaces, AND picks out the correct implementation for the version of minecraft.jar.
This diagram should help articulate what I'm talking about.
That would be awesome. So instead of 50 or 100 people reverse-engineering everything on every patch and developing separately, the API update could be handled by a few people, or even one person. Even though it's obfuscated, there shouldn't be so much changed that the code is completely unrecognizable between minor updates. Major updates like the Boo update coming at the end of the month will obviously require more work.
http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc
This tool, combined with the java decompiler will make you a very happy coder!
To use, extract out minecraft.jar to a folder, pop open one of the classes in JD, File->Save All Sources and save the .zip somewhere. Extract the .zip to a new folder and remember where it's at. This will be the working directory for Doxygen.
The Doxygen Wizard is pretty self explanatory but i'll walk through a few options:
The Projects section of the wizard:
The working directory is the folder you extracted the sources .zip file to. This is also the folder you put in for the source code location. Make sure you check the Scan Recursively box
Put the html files location wherever you want it to save the output to for later viewings.
Hit next
Mode Section of the wizard:
Select the desired extraction mode: All Entities and check the box by Include Cross-Referenced source code in the output.
Select the programming language to optimize the results for: Optimize for Java or C# output.
Output Formats:
Html for sure, with your choice of output for that. You can also do XML or latex or several others or processing in other programs.
Hit next
You can use the built-in class diagram generator or change the options here to suit your tastes.
That should be all you really need to set up the first time around.
click the run tab and hit "Run Doxygen".
After it's done, hit "Show Output" to open up whatever your default browser is with the generated code sitting there.
When it's all said and done, you should have something similar to:
Where you can look at the obfuscated class relationships and such. This should help greatly when the new code gets released. Using this you can go back and compare the code chains and parameters and quickly rematch up code fragments even after they've been reobfuscated.
If someone needs a more in depth version of this guide, I can do it step by step with screenshots, etc. but it really should be pretty self explanatory.
Damn you forum only allowing two lines in the signature.
- Thank you slimes.
"We will absolutely not keep in mind what external mapeditors will have to do to read data from the disk, that makes no sense whatsoever." - Grum
Do you mean the food item type? If so, so my post on Page 2.
Edit: Shameless in-thread piggy-back bump of findings:
oj.class - Generic superclass for Food
Methods
public oj(int paramInt1, int paramInt2)
paramInt1 - Passed to di superclass. Appears to be the Item ID.
paramInt2 - Sets attribute 'a'.
Unsure of purpose; Does not appear to be stack-size. Requires further testing.Hearts Restored * 2.Analysis / Findings:
Debugging has revealed this class is instantiated at login. Initial analysis appears to indicate paramInt2 determines how much health the item heals:
public ev a(ev paramev, cn paramcn, dm paramdm)
paramev - Stack related - Used to decrement stack count. (paramev.a)
paramcn - Not used; nor is it used by di generic item-class. Likely used elsewhere.
paramdm - Damage related. Determines how much health to restore.
Analysis / Findings:
Method b of paramdm restores health. Suggests that dm represents an entity - likely as it extends kh dynamic-object generic (Possibly main player. Method will only restore health to a living player i.e. >0 health). It will not restore above maximum. Also appears to do something related to maximum health. (Related to attributed 'j' and 'aW' in dm - warrants further investigation.)
Noteworthy is the fact that the parameter is signed and no validation is done on 'negative' healing. This means that damaging foods (Poisons) should work. This has been tested and confirmed.
Attributes
aT (Inherited) - Max Stack Size.
a - Hearts Healed by Item * 2.
dw.class - Crafting Class
Methods
public dw()
To Test: Instantiated at start-up
Analysis / Findings:
Makes a number of calls, passing itself as parameter - requires further investigation.
Following this is a list of calls to a (see below).
public ev avoid a(ev paramev, Object[] paramArrayOfObject)
paramev - New item "stack" to create (Constructor takes a block-generic or item-generic and a number (init. stack size).
paramArrayOfObject - Name-Value pair for recipe - organisation as follows (Untested)
Analysis / Findings:
The first index is the top row of the recipe. Second is (optionally) the middle row. Third is (optionally) the bottom row.
The next index is the first character used to represent the top row.
The next index is the item or block represented by that character.
Example:
a(new ev(ly.aH, 16), new Object[] { "X X", "X#X", "X X", Character.valueOf('X'), di.m, Character.valueOf('#'), di.B });
First parameter: Make a new stack of minecart tracks (16 in size).
Second parameter: Recipe - lets examine in detail:
"X X", "X#X", "X X", ---> Let's re-arrange into a more familiar format:
X X
X#X
X X
Next, lets look at the parameters that follow in the object array:
Character.valueOf('X'), di.m, Character.valueOf('#'), di.B
So:
'X' maps to di.m
'#' maps to di.B
di is the generic item class.
Attribute m: public static di m = new di(9).a(23);
To shorten the analysis: The constructor for di takes an integer, which represents the decimal data value of the item - 256.
256 + 9 = 265 = Iron Ingot (http://www.minecraftwiki.net/wiki/Data_values)
So X is iron ingot.
Attribute B public static di B = new di(24).a(53).d();
256 + 24 = 280 = Stick
Substitute "Iron Ingot" for X and "Stick" for # and we end up with:
Which is indeed the recipe for iron ingot.
Further information:
The size of the "Recipe box" appears to be dynamic - this seems to indicate a somewhat easily extensible crafting area.
The "item" and "block" substitution function appears to function for arbitrary length. This means there should be no upper bound on the items that can be used.
Take the above with a grain of salt; need to test.