Hello, and welcome to my tutorial. This tutorial will cover the basics of modding, as well as some advanced techniques that I learned from some of the best modders. By the end of this tutorial you will be able to add blocks, items, and mobs to Minecraft. Once you have learned the basics, we will move on to the ModLoader tutorials. Who knows, you may even just learn something along the way :wink.gif:
I recommend that you read every section, because you will miss something otherwise. And, remember, just because something is optional doesn't mean you shouldn't do it. In fact, I highly recommend you do everything labeled as optional. These provide useful tools and tips for you to work with later. They will also help you learn faster, and help you mod faster in the future. Now, lets jump right in and start with the requirements for modding.
Requirements for Modding:
The JDK (Java Development Kit):
The JDK is the most important tool here. It allows you to compile Java code into class files. The JDK can be downloaded here. Follow the directions here to add the JDK to your PATH variable. The PATH variable is very important!! Without adding it to your PATH you will not be able to compile or decompile code!
Learning Java (Optional, but recommended):
Learning Java is not essential to learning modding, but it is highly recommended. I learned Java from Oracle themselves at this website. Along with this website (if you're absolutely serious about learning code) I recommend you buy a book about Java. One that starts from the beginning, when you have no knowledge of programming whatsoever. I'm not going to give a full length tutorial on Java here, but I will explain things as we move along.
Setting up MCP:
MCP is a decompiler and deobfuscator for the Minecraft client and server. "Compiling" is the process done to source code to change it from "human-readable" to "computer-readable". "Obfuscation" is the process used to block the names of methods and fields (or, "functions" and "describers", respectively) to make the code harder to read. MCP helps us decompile and deobfuscate the code into a language humans can read (with proper training, of course). You can get MCP from their home website here. Go to the "Releases" section and download the latest version. For Minecraft Beta 1.7.3 the most current version is 4.3. Extract everything in the .zip anywhere to your computer (preferably in a folder labeled "MCP"), this will be your workstation.
A warning: MCP only works for the version it is made for. If you use MCP 4.1 with Minecraft 1.7 it will mix up obfuscated names and will not make the right code.
After you have extracted the .zip, you have to tell MCP what to decompile. For this, we have to locate the .minecraft folder. If you are on Windows, press the Windows key+R. This will open Run. In the box, type "%appdata%" without the quotes. This will take you to a folder called "Application Data". If you're on WindowsXP you should see a folder called ".minecraft". This is what we need. In Windows 7 and Vista this will take you to a folder called "Roaming". This is where the .minecraft folder is located.
Once you have located the .minecraft folder, copy the "bin" and "resources" folders, and paste them to the folder "jars" in your MCP workstation. Once you've done this, run "updatemcp.bat" from your workstation. This will update MCP to make sure you have the latest version. Afterwards, run "decompile.bat". This will open cmd, and the script will begin to decompile and deobfuscate the code.
Congratulations, you have finished setting up MCP!
Editing Programs: (Optional)
There are many (too many, almost :tongue.gif: ) programs out there for editing code. While Notepad will work just fine, Eclipse is recommended. Eclipse is made specifically for Java coding, and has many useful tools for editing and creating code. Eclipse can be downloaded here. Download "Eclipse for Java Developers" (not "Eclipse for Java EE Developers"!). Again, extract the folder anywhere to your computer (preferably in a folder named "Eclipse"). If you want, you can make a shortcut to your desktop. Eclipse is now ready to use!
Setting up Eclipse with MCP: (Optional)
With MCP 4.1 you can now set up Eclipse to work with it as a project. To do this, we have to open Eclipse. In Eclipse, go to 'File->Switch Workspace'. If there is nothing there, press 'Other' and browse for your MCP folder, and find a folder called 'eclipse'. Switch your workspace to this folder. Eclipse will now restart, and will have the workspace switched.
Now that everything is setup correctly, we can finally start modding. It can be a little overwhelming at first, but bare with me and we'll get through it.
Creating a Basic Block:
Okay, for our first mod we're going to make a basic block. It will take the same texture as a gold block, but will have a glowing effect. And now, the moment we've all been waiting for...
Actual coding!!!
But, before we get started, let's go over some of the rules of Java syntax:
Java is case-sensitive! (Meaning "superAwesomeFunctionName" is different than "superawesomefunctionname")
Every line of code must end in a ; (semicolon)! (Unless you are declaring a method or class!)
It is conventional in Java to capitalize every word in a class file. (Meaning, "SuperCoolBlockClass" is correct, while "supercoolblockclass" is not!)
It is conventional in Java to capitalize every word in a method or field except the first one. (So, "thisFieldIsFalse" is correct, while "thisfieldisfalse" is not!)
Anything behind two slashes (//) will be ignored by the compiler. I will be using this often in example code to explain the syntax used.
Anything between "/*" and "*/" will be ignored by the compiler. Again, I will be using this often.
Okay, now that that's over with, let's get started!
Let's open up Block.java. If you're in Eclipse setup with MCP, it should be in the box on the left. Open 'Client->src->net.minecraft.src' and you should see a whole bunch of files that end with '.java'. Were looking for Block.java, so scroll down until you see it. When you open it, you probably won't understand anything that it says. I'll teach you a lot of these things as we go.
Scroll down (almost to the bottom) until you see a long list of lines that start with "public static final Block". These are our Block declarations, and we'll be adding one. Scroll to the bottom of this list, and add this line:
public static final Block glowingGold;
Now, let's go over what each of these words means:
public - This means that any file can access this declaration. static - This means that the block will not be changed final - This means that the block can not be changed by anything Block - This tells the compiler and the JVM (Java Virtual Machine) that this is a Block. glowingGold - The Block we are creating (notice the capitalization, only the first word isn't capitalized!)
Now, scroll down until you see the word "static" on a line by itself. You'll see another list, but this time it starts with Block names. We have to add our glowingGold here as well. At the bottom of the list, add this line:
glowingGold = new BlockOreStorage(100, 32).setHardness(3F).setResistance(10F).setLightValue(1.0F).setBlockName("glowingGold");
Okay, once again we'll go over everything in this line.
glowingGold - The Block we declared in the first line we added new BlockOreStorage - This means that the block is the type of BlockOreStorage (look for BlockOreStorage.java if you so care!) (100, 32) - 100 is the blockID, and 32 is the texture location in the terrain.png. In this case, it's the same as the gold block. The ID can be any number that isn't used already and is less than 256. .setHardness(3F) - This tells how long the block will take to break. In this case, the same as the gold block. (We'll go over this more later) .setResistance(10F) - This tells how resistant the block is to TNT. In this case, the same as the gold block. (For added fun look at this function for obsidian and bedrock!) .setLightValue(1.0F) - This tells how much light this block gives off. This is the highest lightValue a block can give, anything higher will appear the same. To get a smaller light value, experiment with any number from 0.0F to 1.0F. .setBlockName("glowingGold"); - This tells what the programming name for this block is. This will not appear in game.
Now you may be wondering, "What do all of these F's mean?". The F stands for "float", a number used in Java to represent decimal numbers. More on floats and other primitive data types here.
Our block is now in the code. Now we run "recompile.bat" from our MCP workstation. If you're in Eclipse you can just press the play button at the top, and the game will start. If there are no errors you have done everything succesfully. If you do get errors, don't worry about it and don't make a post about it. Try again, if after three tries you don't get it right you can make a post.
Well, our block is in the code, but we have no way to create it!
This recipe is lightstone dust surrounded by gold ingots. Now, this may look very confusing, so let's go over every new term: addRecipe - This is the function that registers the recipe. new ItemStack - A new ItemStack (Open ItemStack.java if you so care!) (Block.glowingGold, 1) - The item or block that the recipe makes, and the quantity. If the quantity is above 64, weird things start happening. The "Block." tells the compiler that we're calling from Block.java. new Object[] - An array of objects. If you read the Java tutorial you know what an array is. "GGG", "GDG", "GGG" - The actual recipe. I'll explain more next. Character.valueOf('G'), Item.ingotGold - Don't worry about the exact meaning of this yet. This basically means that the "G" in our recipe is a gold ingot. The "Item." tells the compiler that we're calling from Item.java. Character.valueOf('D'), Item.lightStoneDust - This says that the "D" in our recipe is lightstone dust.
Now we recompile and test. If you like you can create recipes with dirt or sand to make the items you need easier to obtain. You just have to be sure to remove them before you publish the mod. Here's an example of a test recipe:
addRecipe(new ItemStack(Block.glowingGold, 64), new Object[] {
"D", Character.valueOf('D'), Block.dirt
});
This creates a recipe that is only one dirt, and gives you 64 glowingGold blocks. Be sure to remove it when you're done testing!
Adding items is very much like adding blocks, but with more coding. This is because items are a little more complex than blocks, as they often have special functions.
For this tutorial we're going to make an item that, when right-clicked, sets a block of fire. Similar to flint-and-steel, but as an itemstack rather than a single item.
To start, we'll open up Item.java. This defines all of our items, as well as functions like applying textures, and defining what some of them do. This file is very similar to Block.java, in the sense that there is a giant list at the bottom.
Scroll down almost to the bottom of the file. We'll see another big list, this time it says "public static Item" in each declaration. These are all of the items in the game.
Lets add our item to the bottom of this list using this code:
public static Item fireRock = new ItemFireRock(400).setIconCoord(15, 15).setItemName("fireRock");
Let's go over what each of these words means: public - I hope you remember what this means, it was in the Block tutorial! static - Again, this was in our block tutorial! Item - This means that what we are declaring is an Item, as defined in Item.java. fireRock - The Item we're creating. new ItemFireRock(400) - This creates a new instance of the class "ItemFireRock.class" (which we'll create in a second) with an item ID of 400. .setIconCoord(15, 15) - This sets the location of the texture in the items.png. We'll go over this more in-depth in a moment. .setItemName("fireRock"); - The programming name of our item. This does not appear in game.
Now, we have to create a file called "ItemFireRock.java". It's good to stick to the same names already used, instead of using some different name.
This file will tell what our fireRock does. Let's start with a basic item file:
package net.minecraft.src;
public class ItemFireRock extends Item
{
public ItemFireRock(int i)
{
super(i);
}
}
Before going any further, let's go over these new terms: package net.minecraft.src; - This tells the compiler to package the file with other files that have the same package declaration. public class ItemFireRock extends Item - This is our class declaration. This class inherits functions from Item.java, which we looked at (but didn't put too much though into) earlier. super(i); - This sends int i to this class' super class. In this case, Item.java. int i is the ID we set for our fireRock in Item.java.
Now, let's open ItemFlintAndSteel.java to see what code it uses to do what it does. The first function that might catch your eye is this:
It's time to learn even more terminology! (Which I know you all enjoy! [/sarcasm]) int i1 = world.getBlockId(i, j, k); - This function gets the blockID of the block we are selecting in-game, and assigns it to the int variable "i1". if(i1 == 0) - If the blockID we retrieved is air, the function continues. world.playSoundEffect(...) - This tells what sound effect to play and from where. This function is a little advanced, so let's skip ahead. world.setBlockWithNotify(i, j, k, Block.fire.blockID); - This sets the block that we specify, and notifies all surrounding blocks to update. In this case, it will set fire. We could set anything we want, like obsidian or snow, but we'll get to that later. itemstack.damageItem(1, entityplayer) - Since flint-and-steel has a "health bar", we have this function. It damages the flint-and-steel until it breaks. We're going to change this to "itemstack.stackSize--;", which decreases the amount we have in our ItemStack of fireRock by one. return true; - Since this function's return type is a boolean, we have to return a true or false value.
So, let's copy and paste this function into our ItemFireRock.java, like so (of course, remembering to change our function name!):
package net.minecraft.src;
public class ItemFireRock extends Item
{
public ItemFireRock(int i)
{
super(i);
}
public boolean onItemUse(ItemStack itemstack, EntityPlayer entityplayer, World world, int i, int j, int k, int l)
{
if(l == 0)
{
j--;
}
if(l == 1)
{
j++;
}
if(l == 2)
{
k--;
}
if(l == 3)
{
k++;
}
if(l == 4)
{
i--;
}
if(l == 5)
{
i++;
}
int i1 = world.getBlockId(i, j, k);
if(i1 == 0)
{
world.playSoundEffect((double)i + 0.5D, (double)j + 0.5D, (double)k + 0.5D, "fire.ignite", 1.0F, itemRand.nextFloat() * 0.4F + 0.8F);
world.setBlockWithNotify(i, j, k, Block.fire.blockID);
itemstack.stackSize--;
}
return true;
}
}
itemstack.stacksize--; has been moved into our if statement, so that it only decreases the itemstack if the boolean is true and the block is set.
Now we have to add a recipe for our item. We'll make it a flint on top of a lava bucket. Remember that this goes in CraftingManager.java:
Ores can always be a fun new addition to the game, whether they are real or made-up or fantasy. This tutorial is very basic, but will still teach you a lot about ore generation.
First, let's open up ChunkProviderGenerate.java. This contains all of the little things that generate in the world, like trees, flowers, ores, and lava/water falls. The function we're focused on right now is the function "populate" near the bottom of the file.
Let's break down the code for iron:
for(int j3 = 0; j3 < 20; j3++)
{
int k6 = k + rand.nextInt(16);
int l9 = rand.nextInt(64);
int k12 = l + rand.nextInt(16);
(new WorldGenMinable(Block.oreIron.blockID, 8)).generate(worldObj, rand, k6, l9, k12);
}
for(int j3 = 0; j3 < 20; j3++) - This is what we call a for-loop. It is used when we want to do something multiple times. This for-loop is executed twenty times. (Meaning, there are 20 veins of iron per chunk.) int k6 = k + rand.nextInt(16); - This creates a random number that is <= 16, then adds k (a random number generated elsewhere) and assigns it to the variable int k6. This defines the x-value of where our ore will generate in each chunk. In this case, anywhere. int l9 = rand.nextInt(64); - This creates a random number that is <= 64 and assigns it to variable int l9. This defines the y-value of our ore, or, the height at which it generates. In this case, anywhere below level 64. int k12 = l + rand.nextInt(16) - This is the same thing as int k6, but this time it's assigning the z-value. (new WorldGenMinable(Block.oreIron.blockID, 8)).generate(worldObj, rand, k6, l9, k12); - This creates a new instance of WorldGenMinable.class, and sends the constructors (ints k6, l9, and k12) to it to generate the block we specify randomly. In this case, it will generate iron. The int after Block.oreIron.blockID is how big the veins of the ore can be (In this case, 8).
Now that we know this, let's look at the code for diamond:
for(int i4 = 0; i4 < 1; i4++)
{
int j7 = k + rand.nextInt(16);
int k10 = rand.nextInt(16);
int j13 = l + rand.nextInt(16);
(new WorldGenMinable(Block.oreDiamond.blockID, 7)).generate(worldObj, rand, j7, k10, j13);
}
This code generates 1 vein per chunk, at layers <= 16. The max vein size is 7.
For us to make our own ore, we have to first make the block:
public static final Block oreTutorial = new BlockOre(101, 224).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
Remember that this goes in Block.java. The texture for this block goes under sandstone and to the left of light gray wool in the terrain.png. Here's a recolored ore texture you can use:
Now, we go back to ChunkProviderGenerate.java and add our code to generate our ore. Where you put the code matters, because it will generate the one on top first, and the one on bottom last. This goes in the populate() function in ChunkProviderGenerate.java:
for(int oreFrequency = 0; oreFrequency < 12; oreFrequency++)
{
int xCoord = k + rand.nextInt(16);
int yCoord = rand.nextInt(128);
int zCoord = l + rand.nextInt(16);
(new WorldGenMinable(Block.oreTutorial.blockID, 10)).generate(worldObj, rand, xCoord, yCoord, zCoord);
}
This code generates our ore 12 times per chunk, at levels <= 128, and in veins with a maximum of 10. What you call your int declarations doesn't matter, because they are local variables and are only used in this function.
Recompile and test (or press play in Eclipse).
Congratulations, you've added a new ore to the Minecraft world!
Some blocks like ice, soulsand, sand/gravel, and netherrack have special properties like gravity and slipperiness. This tutorial will teach you how to make a slippery block that has a light level equal to that of a torch. I'll also teach you how to set different textures for different sides of the block.
Let's start by adding our block to Block.java:
public static final Block advancedBlock = new BlockAdvanced(102).setLightValue(0.9375F).setBlockName("advancedBlock");
This is our basic block line, but with one extra function. The "setLightValue" function allows us to set the amount of light the block gives off. 1.0F is the max you can have, anything higher than this will not be noticeable, and may make strange things happen. 0.9735F is the same level as a regular torch, at it's more well-known level of 14.
If you tried to recompile this now the compiler would go crazy and say, "What are you thinking, the class 'BlockAdvanced' doesn't exist!". Well, that's why we have to write it :wink.gif:
Let's start with our basic block class:
package net.minecraft.src;
public class BlockAdvanced extends Block {
public BlockAdvanced(int i) {
super(i, Material.rock);
}
}
This is our basic block class, it sends the int "i" to its super class along with its Material, which we'll go over later.
The only block in the game with slipperiness is ice. Let's open BlockIce.java. You should notice this right away, in the BlockIce function:
slipperiness = 0.98F;
This is the line that adds slipperiness to the block. This is a float value, so it has to be a decimal. Let's copy and paste this into our BlockAdvanced.java:
package net.minecraft.src;
public class BlockAdvanced extends Block {
public BlockAdvanced(int i) {
super(i, Material.rock);
slipperiness = 0.98F;
}
}
Now, let's look for a funtion that adds multiple textures to a block. The block that is the easiest to understand is sandstone. Here's the function that does that from BlockSandStone.java:
A new question arises now, "What is blockIndexInTexture?". Well, that is the location in the terrain.png to start with. We'll go more into this later.
For now, let's just add this to our BlockAdvanced.java:
package net.minecraft.src;
public class BlockAdvanced extends Block {
public BlockAdvanced(int i) {
super(i, Material.rock);
slipperiness = 0.98F;
}
public int getBlockTextureFromSide(int i) {
if(i == 1) {
return blockIndexInTexture - 16;
}
if(i == 0) {
return blockIndexInTexture + 16;
} else {
return blockIndexInTexture;
}
}
}
Now, we have to tell the compiler what blockIndexInTexture is. We have to add a line to our BlockAdvanced.java:
blockIndexInTexture = 196;
This defines the location of our base texture in the terrain.png. This line goes in our BlockAdvanced function. For this we'll be using the spot next to the detector rail, and the two spots under that spot. We'll keep things simple, and just copy and paste some textures there. ([/laziness] :tongue.gif: )
Now, paste whatever textures you like in the three spots mentioned earlier and your block will be complete. It takes the same format as sandstone; the top slot is the top of the block, the middle is the sides of the block, and the bottom is the bottom of the block. For our texture to function properly in the MCP test version, we have to add the modified terrain.png to the JAR we decompiled, the one in the MCP folder labeled "jars".
Adding a toolset is a somewhat advanced mod to make for a beginner. This tutorial may be a little hard to understand at first; always remember you can go over it again if you don't get it right the first time.
Let's get started. Since tools are items, we have to open Item.java to see how they are defined. We're going to make a toolset made out of our ore from earlier. We have to add 10 lines of code to Item.java; two for each tool:
public static Item swordTutorial;
public static Item pickaxeTutorial;
public static Item shovelTutorial;
public static Item axeTutorial;
public static Item hoeTutorial;
This goes in our item list found near the bottom of Item.java.
Next is the static list part. This is where we actually define our items:
swordTutorial = new ItemSword(200, EnumToolMaterial.TUTORIAL).setIconCoord(15, 15).setItemName("swordTutorial");
pickaxeTutorial = new ItemPickaxe(201, EnumToolMaterial.TUTORIAL).setIconCoord(14, 15).setItemName("pickaxeTutorial");
shovelTutorial = new ItemSpade(202, EnumToolMaterial.TUTORIAL).setIconCoord(13, 15).setItemName("shovelTutorial");
axeTutorial = new ItemAxe(203, EnumToolMaterial.TUTORIAL).setIconCoord(12, 15).setItemName("axeTutorial");
hoeTutorial = new ItemHoe(205, EnumToolMaterial.TUTORIAL).setIconCoord(11, 15).setItemName("hoeTutorial");
This goes in the static function.
There's only one term we shouldn't know here, and that's "EnumToolMaterial". Since we have the dot (.) operator right after, it means that this is a class. Let's open EnumToolMaterial.java. The first thing you'll see is a list of all the tools you can make. Notice they are all caps; this is because they are constants, and it is conventional in Java to capitalize things that are constants like enums (short for: enumerators). Let's add ours:
TUTORIAL("TUTORIAL", 5, 2, 500, 8F, 2);
Before we do anything else we have to make sure our list is correctly punctuated. To avoid making one of the most common mistakes made by amateur modders, we have to change the semicolon after GOLD to a comma. Don't forget to do this, or you will get compile-time errors. Anytime you make an addition to the enum you must change the one before to a comma instead of a semicolon. I cannot stress this enough.
Since this seems a little complicated, I'll go over this as easily as possible. Each number in our addition gives the tools a certain property. The first entry is a String, "TUTORIAL". The next number is the ID of our addition, but it doesn't really matter what you use as long as it is not already used. After that is the harvestLevel, which defines what blocks the pickaxe can and cannot harvest (more on this later). Next, we have our tools' durability; or, the number of uses it has until it breaks. After that is the speed, which is defined by all sorts of other factors (more on this later). Keep in mind, the speed of a tool is a floating-point number (float) so we have to leave that F there or the compiler will think the number is a double. And, last but not least, is the damage done to mobs (again, more on this later). So, for those who are more visual learners, here's another example with what you need between angled brackets:
<NAME OF TOOLS>("<NAME OF TOOLS AGAIN>", <ID of enumerator>, <harvestLevel>, <durability>, <speed>F, <damage to entities>);
Just replace anything between < and > with what you need and you should be good to go.
harvestLevel:
The harvestLevel of a tool defines what it can and cannot harvest when it breaks a block. This can most easily be learned from ItemPickaxe.java, so let's open that up. In this, you will see a function with a return type "boolean" called canHarvestBlock. We'll add our ore to this in a second, but let's go over this function a little more in-depth:
Because the function receives a block as a parameter, it uses the block it receives to tell the pickaxe if it can harvest it. Look at the if statement for obsidian:
This is basically saying "if the block the pickaxe is hitting is obsidian, the pickaxe can harvest the block if it's harvestLevel is equal to 3." Since we set our pickaxe's harvestLevel to three, it can harvest obsidian. Now for iron ore:
This says "if the block the pickaxe is hitting is an iron block or (|| means a logical "or") is an iron ore, the pickaxe can harvest the block if its harvestLevel is greater-than or equal to 1."
So, let's add our ore with a harvestLevel requirement of 2:
Now our ore can be harvest by a iron pickaxe or better.
Speed:
The speed of a tool is defined by many factors, such as the hardness of the block and the tool's speed in EnumToolMaterial. Because there are so many (and I haven't found them all yet :tongue.gif: ) I won't list them all here. To get a reference of what to set your speed to, look at the other entries in the enumerator.
Damage to entities:
The amount of damage your tools will do is on a half-heart basis. If you set it to 4, it will do 4 half-hearts, or 2 full hearts. Swords however, follow a different pattern. To find out how much damage swords do, we have to open ItemSword.java. Let's look at the constructor for this class:
public ItemSword(int i, EnumToolMaterial enumtoolmaterial)
{
super(i);
maxStackSize = 1;
setMaxDamage(enumtoolmaterial.getMaxUses());
weaponDamage = 4 + enumtoolmaterial.getDamageVsEntity() * 2;
}
The line "weaponDamage" is the line that finalizes the damage done to mobs. Let's go over this line. The constructor uses EnumToolMaterial as a parameter, so it gets the material the tool is made of and uses it's properties. The line we are looking at gets the damage of our tools ("enumtoolmaterial.getDamageVsEntity()" is the part that gets the data), multiplies it by 2, and adds 4. Since we set our damage to 2, our sword would do 2*2+4 damage, or 8 half-hearts to the mob we hit. Keep in mind a pickaxe only does 2 half-hearts to the mob we hit, only the sword has increased damage.
Add recipes to make your new tools (RecipesTools.java), recompile and test. Remember, if you get an error try the tutorial again. After three tries, make a post about it.
Using the ModLoader (ML) can be much easier than normal modding. It has functions for registering almost anything you could possibly need. Since the ML has a Javadoc I don't really need to go over all of the functions, but I'll go over the basic ones that are used commonly.
Well, well, well. It seems we don't have the source code for the ModLoader. What we have to do is decompile it with the vanilla game. Install the ML into the JAR you decompiled (the one in "MCP\jars"). After you've done that we have to get rid of the old source code (the mods we made earlier). For this, we have to run cleanup.bat. After cleaning up run updatemcp.bat and decompile.bat. The decompiler will complain about hunks failing. This is normal and will happen persistently, but it doesn't affect any of the code we're going to make.
Let's get started by making our first ModLoader mod!
We're going to rewrite our ore to be ML compatible. This is almost identical to the non-ML modding, but we have to make our mod_ class (and I'll show you how!).
Your basic mod_ class follows this format (it must start with mod_ !):
package net.minecraft.src; //the same package as the rest of the code
public class mod_TutorialOre extends BaseMod { //the class must extend (or inherit functions from) BaseMod.java.
//block and item declarations here:
public mod_TutorialOre() { //our constructor for this class. (more on this later)
}
public String Version() { //you MUST have this part. Since this is abstract in the superclass
//we must overwrite it with something less vague.
//What you give here is used in crash reports and stack traces
return "mod version";
}
}
This is the minimum you should have. Here's a version without comments all over the place:
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public mod_TutorialOre() {
}
public String Version() {
return "mod version";
}
}
For our block we can use the same line of code we made earlier in Block.java. Let's copy and paste that into our class:
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public static final Block oreTutorial = new BlockOre(101, 224).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
public mod_TutorialOre() {
}
public String Version() {
return "mod version";
}
}
Now we have to have ML register our Block. We have to add a line to the constructor:
ModLoader.RegisterBlock(oreTutorial);
The constructor is a neat function that is called every time you create a new instance of the class. So when you say "new Block()" it calls the constructor with the parameters that match the arguments you sent in Block.class. The ML automatically creates a new instance of any class that starts with mod_, so we don't need to worry about creating a new instance.
So, now we should have this:
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public static final Block oreTutorial = new BlockOre(101, 224).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
public mod_TutorialOre() {
ModLoader.RegisterBlock(oreTutorial);
}
public String Version() {
return "mod version";
}
}
Now all that's left is ore generation, public String Version(), and texture overrides. For our generation we use a new method in the mod_ class, "generateSurface()". It's exactly the same as ChunkProviderGenerate.java's "populate()" function. Let's add the base of our function:
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public static final Block oreTutorial = new BlockOre(101, 224).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
public mod_TutorialOre() {
ModLoader.RegisterBlock(oreTutorial);
}
public void GenerateSurface(World world, Random random, int randXCoord, int randZCoord) {
}
public String Version() {
return "mod version";
}
}
And, let's copy and paste the generation code from our ores and ore generation tutorial:
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public static final Block oreTutorial = new BlockOre(101, 224).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
public mod_TutorialOre() {
ModLoader.RegisterBlock(oreTutorial);
}
public void GenerateSurface(World world, Random random, int randXCoord, int randZCoord) {
for(int oreFrequency = 0; oreFrequency < 12; oreFrequency++) {
int xCoord = randXCoord + random.nextInt(16);
int yCoord = random.nextInt(128);
int zCoord = randZCoord + random.nextInt(16);
new WorldGenMinable(mod_TutorialOre.oreTutorial.blockID, 10).generate(worldObj, rand, xCoord, yCoord, zCoord);
}
}
public String Version() {
return "mod version";
}
}
There is one more line we have to add at this point. Because the ore generation code utilizes the Random class we have to import it:
import java.util.Random;
This line goes directly under the package declaration at the top of the file. We also have to change Block.oreTutorial.blockID to mod_TutorialOre.oreTutorial.blockID, as we have declared the Block oreTutorial in mod_TutorialOre.class instead of Block.class.
Okay, now that we have that done let's go on to texture overrides. When coding the overrides you have to make sure that everything is capitalized correctly. The first thing we have to do is set our block's blockIndexInTexture to 0. This is the texture for grass, and the ML uses it to lay other textures on top of it.
Next, we have to add the override function to our constructor. After that, we should have this:
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public static final Block oreTutorial = new BlockOre(101, 0).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
public mod_TutorialOre() {
ModLoader.RegisterBlock(oreTutorial);
oreTutorial.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/Tutorial Ore/oretutorial.png");
}
public void GenerateSurface(World world, Random random, int randXCoord, int randZCoord) {
for(int oreFrequency = 0; oreFrequency < 12; oreFrequency++) {
int xCoord = randXCoord + rand.nextInt(16);
int yCoord = rand.nextInt(128);
int zCoord = randZCoord + rand.nextInt(16);
new WorldGenMinable(mod_TutorialOre.oreTutorial.blockID, 10).generate(worldObj, rand, xCoord, yCoord, zCoord);
}
}
public String Version() {
return "mod version";
}
}
Now, we fill in our public String Version() with something that is relevant. Since our mod is complete, we'll make it version 1.0.
package net.minecraft.src;
public class mod_TutorialOre extends BaseMod {
public static final Block oreTutorial = new BlockOre(101, 0).setHardness(5F).setResistance(10F).setBlockName("oreTutorial");
public mod_TutorialOre() {
ModLoader.RegisterBlock(oreTutorial);
oreTutorial.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/Tutorial Ore/oretutorial.png");
}
public void GenerateSurface(World world, Random random, int randXCoord, int randZCoord) {
for(int oreFrequency = 0; oreFrequency < 12; oreFrequency++) {
int xCoord = randXCoord + rand.nextInt(16);
int yCoord = rand.nextInt(128);
int zCoord = randZCoord + rand.nextInt(16);
new WorldGenMinable(mod_TutorialOre.oreTutorial.blockID, 10).generate(world, rand, xCoord, yCoord, zCoord);
}
}
public String Version() {
return "1.0 for MC Beta 1.7.3";
}
}
It's best to put your mod's version and the MC version it is made for. Since some mods (even ML mods) can be outdated it is important for debuggers to know what Minecraft version the mod is made for to check if it is up-to-date.
Your first ModLoader mod is complete! Next: Adding items with ML!
Its nice your doing a tutorial thread for the many people on the forums who wish to mod but have no experience but you'll need to move to the tutorials section because the mod discussion thread is not were this should be.
Hey Chewy, I have a question, how would one be able to create a code, changing an entity's model? As in, changing the player's model. I want to be able to make the change toggle-able by an event as well.
So;
When <event>, the player will change into a different model, e.g. (Dwarf, making the body slightly smaller).
This might be a bit complex, maybe not that possible. But if you've seen the 'You are the Creeper' mod, that's what I mean. Changing the player's default body, (Not skin).
Rollback Post to RevisionRollBack
Our memories these days, just so terrible, I mean, I asked this old lady, about this magic book.. I forgot the rest but Watermelons are good.
why are u commenting reserved again and again. btw, i will look into the tutorial. looks great!
he reserved some spots so he can keep them in order and so that other people would not steal the spots, in other words makes his post look neat and clean and professional in the end.
Chewy! Great stuff! I was going to recommend last night you make your own tutorial, all the ones we've got around here are at least 2 months old :smile.gif:
Hey Chewy, I have a question, how would one be able to create a code, changing an entity's model? As in, changing the player's model. I want to be able to make the change toggle-able by an event as well.
So;
When <event>, the player will change into a different model, e.g. (Dwarf, making the body slightly smaller).
This might be a bit complex, maybe not that possible. But if you've seen the 'You are the Creeper' mod, that's what I mean. Changing the player's default body, (Not skin).
This might be a little complex.
If you wanted to make a permanent change, you would just need to replace the player model with the model you want the player to be. To make it change under certain circumstances might be harder. A boolean to tell if the player should use the alternate model might work, but that's really advanced stuff.
Chewy! Great stuff! I was going to recommend last night you make your own tutorial, all the ones we've got around here are at least 2 months old :smile.gif:
That part explaining the flint and steel is quite exceptional...
I've never glanced at that code before, but I don't think I will have to after this :smile.gif:
Hello, and welcome to my tutorial. This tutorial will cover the basics of modding, as well as some advanced techniques that I learned from some of the best modders. By the end of this tutorial you will be able to add blocks, items, and mobs to Minecraft. Once you have learned the basics, we will move on to the ModLoader tutorials. Who knows, you may even just learn something along the way :wink.gif:
I recommend that you read every section, because you will miss something otherwise. And, remember, just because something is optional doesn't mean you shouldn't do it. In fact, I highly recommend you do everything labeled as optional. These provide useful tools and tips for you to work with later. They will also help you learn faster, and help you mod faster in the future. Now, lets jump right in and start with the requirements for modding.
A warning: MCP only works for the version it is made for. If you use MCP 4.1 with Minecraft 1.7 it will mix up obfuscated names and will not make the right code.
After you have extracted the .zip, you have to tell MCP what to decompile. For this, we have to locate the .minecraft folder. If you are on Windows, press the Windows key+R. This will open Run. In the box, type "%appdata%" without the quotes. This will take you to a folder called "Application Data". If you're on WindowsXP you should see a folder called ".minecraft". This is what we need. In Windows 7 and Vista this will take you to a folder called "Roaming". This is where the .minecraft folder is located.
Once you have located the .minecraft folder, copy the "bin" and "resources" folders, and paste them to the folder "jars" in your MCP workstation. Once you've done this, run "updatemcp.bat" from your workstation. This will update MCP to make sure you have the latest version. Afterwards, run "decompile.bat". This will open cmd, and the script will begin to decompile and deobfuscate the code.
Congratulations, you have finished setting up MCP!
Finally, we are ready to start modding!
Now that everything is setup correctly, we can finally start modding. It can be a little overwhelming at first, but bare with me and we'll get through it.
But, before we get started, let's go over some of the rules of Java syntax:
Okay, now that that's over with, let's get started!
Let's open up Block.java. If you're in Eclipse setup with MCP, it should be in the box on the left. Open 'Client->src->net.minecraft.src' and you should see a whole bunch of files that end with '.java'. Were looking for Block.java, so scroll down until you see it. When you open it, you probably won't understand anything that it says. I'll teach you a lot of these things as we go.
Scroll down (almost to the bottom) until you see a long list of lines that start with "public static final Block". These are our Block declarations, and we'll be adding one. Scroll to the bottom of this list, and add this line:
Now, let's go over what each of these words means:
public - This means that any file can access this declaration.
static - This means that the block will not be changed
final - This means that the block can not be changed by anything
Block - This tells the compiler and the JVM (Java Virtual Machine) that this is a Block.
glowingGold - The Block we are creating (notice the capitalization, only the first word isn't capitalized!)
Now, scroll down until you see the word "static" on a line by itself. You'll see another list, but this time it starts with Block names. We have to add our glowingGold here as well. At the bottom of the list, add this line:
Okay, once again we'll go over everything in this line.
glowingGold - The Block we declared in the first line we added
new BlockOreStorage - This means that the block is the type of BlockOreStorage (look for BlockOreStorage.java if you so care!)
(100, 32) - 100 is the blockID, and 32 is the texture location in the terrain.png. In this case, it's the same as the gold block. The ID can be any number that isn't used already and is less than 256.
.setHardness(3F) - This tells how long the block will take to break. In this case, the same as the gold block. (We'll go over this more later)
.setResistance(10F) - This tells how resistant the block is to TNT. In this case, the same as the gold block. (For added fun look at this function for obsidian and bedrock!)
.setLightValue(1.0F) - This tells how much light this block gives off. This is the highest lightValue a block can give, anything higher will appear the same. To get a smaller light value, experiment with any number from 0.0F to 1.0F.
.setBlockName("glowingGold"); - This tells what the programming name for this block is. This will not appear in game.
Now you may be wondering, "What do all of these F's mean?". The F stands for "float", a number used in Java to represent decimal numbers. More on floats and other primitive data types here.
Our block is now in the code. Now we run "recompile.bat" from our MCP workstation. If you're in Eclipse you can just press the play button at the top, and the game will start. If there are no errors you have done everything succesfully. If you do get errors, don't worry about it and don't make a post about it. Try again, if after three tries you don't get it right you can make a post.
Well, our block is in the code, but we have no way to create it!
This is where the recipe tutorial comes in!
When you open this, you'll see more stuff you probably don't understand. Again, I'll explain it all in a bit.
So, let's make a recipe for the glowingGold:
This recipe is lightstone dust surrounded by gold ingots. Now, this may look very confusing, so let's go over every new term:
addRecipe - This is the function that registers the recipe.
new ItemStack - A new ItemStack (Open ItemStack.java if you so care!)
(Block.glowingGold, 1) - The item or block that the recipe makes, and the quantity. If the quantity is above 64, weird things start happening. The "Block." tells the compiler that we're calling from Block.java.
new Object[] - An array of objects. If you read the Java tutorial you know what an array is.
"GGG", "GDG", "GGG" - The actual recipe. I'll explain more next.
Character.valueOf('G'), Item.ingotGold - Don't worry about the exact meaning of this yet. This basically means that the "G" in our recipe is a gold ingot. The "Item." tells the compiler that we're calling from Item.java.
Character.valueOf('D'), Item.lightStoneDust - This says that the "D" in our recipe is lightstone dust.
Now we recompile and test. If you like you can create recipes with dirt or sand to make the items you need easier to obtain. You just have to be sure to remove them before you publish the mod. Here's an example of a test recipe:
This creates a recipe that is only one dirt, and gives you 64 glowingGold blocks. Be sure to remove it when you're done testing!
We've created our first recipe!
Adding items is very much like adding blocks, but with more coding. This is because items are a little more complex than blocks, as they often have special functions.
For this tutorial we're going to make an item that, when right-clicked, sets a block of fire. Similar to flint-and-steel, but as an itemstack rather than a single item.
To start, we'll open up Item.java. This defines all of our items, as well as functions like applying textures, and defining what some of them do. This file is very similar to Block.java, in the sense that there is a giant list at the bottom.
Scroll down almost to the bottom of the file. We'll see another big list, this time it says "public static Item" in each declaration. These are all of the items in the game.
Lets add our item to the bottom of this list using this code:
Let's go over what each of these words means:
public - I hope you remember what this means, it was in the Block tutorial!
static - Again, this was in our block tutorial!
Item - This means that what we are declaring is an Item, as defined in Item.java.
fireRock - The Item we're creating.
new ItemFireRock(400) - This creates a new instance of the class "ItemFireRock.class" (which we'll create in a second) with an item ID of 400.
.setIconCoord(15, 15) - This sets the location of the texture in the items.png. We'll go over this more in-depth in a moment.
.setItemName("fireRock"); - The programming name of our item. This does not appear in game.
Now, we have to create a file called "ItemFireRock.java". It's good to stick to the same names already used, instead of using some different name.
This file will tell what our fireRock does. Let's start with a basic item file:
Before going any further, let's go over these new terms:
package net.minecraft.src; - This tells the compiler to package the file with other files that have the same package declaration.
public class ItemFireRock extends Item - This is our class declaration. This class inherits functions from Item.java, which we looked at (but didn't put too much though into) earlier.
super(i); - This sends int i to this class' super class. In this case, Item.java. int i is the ID we set for our fireRock in Item.java.
Now, let's open ItemFlintAndSteel.java to see what code it uses to do what it does. The first function that might catch your eye is this:
Since this function has to do with metadata I'll explain it as simply as I can. What's most important to us is this part:
It's time to learn even more terminology! (Which I know you all enjoy! [/sarcasm])
int i1 = world.getBlockId(i, j, k); - This function gets the blockID of the block we are selecting in-game, and assigns it to the int variable "i1".
if(i1 == 0) - If the blockID we retrieved is air, the function continues.
world.playSoundEffect(...) - This tells what sound effect to play and from where. This function is a little advanced, so let's skip ahead.
world.setBlockWithNotify(i, j, k, Block.fire.blockID); - This sets the block that we specify, and notifies all surrounding blocks to update. In this case, it will set fire. We could set anything we want, like obsidian or snow, but we'll get to that later.
itemstack.damageItem(1, entityplayer) - Since flint-and-steel has a "health bar", we have this function. It damages the flint-and-steel until it breaks. We're going to change this to "itemstack.stackSize--;", which decreases the amount we have in our ItemStack of fireRock by one.
return true; - Since this function's return type is a boolean, we have to return a true or false value.
So, let's copy and paste this function into our ItemFireRock.java, like so (of course, remembering to change our function name!):
itemstack.stacksize--; has been moved into our if statement, so that it only decreases the itemstack if the boolean is true and the block is set.
Now we have to add a recipe for our item. We'll make it a flint on top of a lava bucket. Remember that this goes in CraftingManager.java:
Now to recompile and test. If you right click with the item, it should start burning.
Congratulations, you've made your first Item!
Ores can always be a fun new addition to the game, whether they are real or made-up or fantasy. This tutorial is very basic, but will still teach you a lot about ore generation.
First, let's open up ChunkProviderGenerate.java. This contains all of the little things that generate in the world, like trees, flowers, ores, and lava/water falls. The function we're focused on right now is the function "populate" near the bottom of the file.
Let's break down the code for iron:
for(int j3 = 0; j3 < 20; j3++) - This is what we call a for-loop. It is used when we want to do something multiple times. This for-loop is executed twenty times. (Meaning, there are 20 veins of iron per chunk.)
int k6 = k + rand.nextInt(16); - This creates a random number that is <= 16, then adds k (a random number generated elsewhere) and assigns it to the variable int k6. This defines the x-value of where our ore will generate in each chunk. In this case, anywhere.
int l9 = rand.nextInt(64); - This creates a random number that is <= 64 and assigns it to variable int l9. This defines the y-value of our ore, or, the height at which it generates. In this case, anywhere below level 64.
int k12 = l + rand.nextInt(16) - This is the same thing as int k6, but this time it's assigning the z-value.
(new WorldGenMinable(Block.oreIron.blockID, 8)).generate(worldObj, rand, k6, l9, k12); - This creates a new instance of WorldGenMinable.class, and sends the constructors (ints k6, l9, and k12) to it to generate the block we specify randomly. In this case, it will generate iron. The int after Block.oreIron.blockID is how big the veins of the ore can be (In this case, 8).
Now that we know this, let's look at the code for diamond:
This code generates 1 vein per chunk, at layers <= 16. The max vein size is 7.
For us to make our own ore, we have to first make the block:
Remember that this goes in Block.java. The texture for this block goes under sandstone and to the left of light gray wool in the terrain.png. Here's a recolored ore texture you can use:
Now, we go back to ChunkProviderGenerate.java and add our code to generate our ore. Where you put the code matters, because it will generate the one on top first, and the one on bottom last. This goes in the populate() function in ChunkProviderGenerate.java:
This code generates our ore 12 times per chunk, at levels <= 128, and in veins with a maximum of 10. What you call your int declarations doesn't matter, because they are local variables and are only used in this function.
Recompile and test (or press play in Eclipse).
Congratulations, you've added a new ore to the Minecraft world!
Some blocks like ice, soulsand, sand/gravel, and netherrack have special properties like gravity and slipperiness. This tutorial will teach you how to make a slippery block that has a light level equal to that of a torch. I'll also teach you how to set different textures for different sides of the block.
Let's start by adding our block to Block.java:
This is our basic block line, but with one extra function. The "setLightValue" function allows us to set the amount of light the block gives off. 1.0F is the max you can have, anything higher than this will not be noticeable, and may make strange things happen. 0.9735F is the same level as a regular torch, at it's more well-known level of 14.
If you tried to recompile this now the compiler would go crazy and say, "What are you thinking, the class 'BlockAdvanced' doesn't exist!". Well, that's why we have to write it :wink.gif:
Let's start with our basic block class:
This is our basic block class, it sends the int "i" to its super class along with its Material, which we'll go over later.
The only block in the game with slipperiness is ice. Let's open BlockIce.java. You should notice this right away, in the BlockIce function:
This is the line that adds slipperiness to the block. This is a float value, so it has to be a decimal. Let's copy and paste this into our BlockAdvanced.java:
Now, let's look for a funtion that adds multiple textures to a block. The block that is the easiest to understand is sandstone. Here's the function that does that from BlockSandStone.java:
A new question arises now, "What is blockIndexInTexture?". Well, that is the location in the terrain.png to start with. We'll go more into this later.
For now, let's just add this to our BlockAdvanced.java:
Now, we have to tell the compiler what blockIndexInTexture is. We have to add a line to our BlockAdvanced.java:
This defines the location of our base texture in the terrain.png. This line goes in our BlockAdvanced function. For this we'll be using the spot next to the detector rail, and the two spots under that spot. We'll keep things simple, and just copy and paste some textures there. ([/laziness] :tongue.gif: )
You should now have this:
Now, paste whatever textures you like in the three spots mentioned earlier and your block will be complete. It takes the same format as sandstone; the top slot is the top of the block, the middle is the sides of the block, and the bottom is the bottom of the block. For our texture to function properly in the MCP test version, we have to add the modified terrain.png to the JAR we decompiled, the one in the MCP folder labeled "jars".
Let's recompile our code and test.
We're getting more advanced now!
Adding a toolset is a somewhat advanced mod to make for a beginner. This tutorial may be a little hard to understand at first; always remember you can go over it again if you don't get it right the first time.
Let's get started. Since tools are items, we have to open Item.java to see how they are defined. We're going to make a toolset made out of our ore from earlier. We have to add 10 lines of code to Item.java; two for each tool:
This goes in our item list found near the bottom of Item.java.
Next is the static list part. This is where we actually define our items:
This goes in the static function.
There's only one term we shouldn't know here, and that's "EnumToolMaterial". Since we have the dot (.) operator right after, it means that this is a class. Let's open EnumToolMaterial.java. The first thing you'll see is a list of all the tools you can make. Notice they are all caps; this is because they are constants, and it is conventional in Java to capitalize things that are constants like enums (short for: enumerators). Let's add ours:
Before we do anything else we have to make sure our list is correctly punctuated. To avoid making one of the most common mistakes made by amateur modders, we have to change the semicolon after GOLD to a comma. Don't forget to do this, or you will get compile-time errors. Anytime you make an addition to the enum you must change the one before to a comma instead of a semicolon. I cannot stress this enough.
Since this seems a little complicated, I'll go over this as easily as possible. Each number in our addition gives the tools a certain property. The first entry is a String, "TUTORIAL". The next number is the ID of our addition, but it doesn't really matter what you use as long as it is not already used. After that is the harvestLevel, which defines what blocks the pickaxe can and cannot harvest (more on this later). Next, we have our tools' durability; or, the number of uses it has until it breaks. After that is the speed, which is defined by all sorts of other factors (more on this later). Keep in mind, the speed of a tool is a floating-point number (float) so we have to leave that F there or the compiler will think the number is a double. And, last but not least, is the damage done to mobs (again, more on this later). So, for those who are more visual learners, here's another example with what you need between angled brackets:
Just replace anything between < and > with what you need and you should be good to go.
harvestLevel:
The harvestLevel of a tool defines what it can and cannot harvest when it breaks a block. This can most easily be learned from ItemPickaxe.java, so let's open that up. In this, you will see a function with a return type "boolean" called canHarvestBlock. We'll add our ore to this in a second, but let's go over this function a little more in-depth:
Because the function receives a block as a parameter, it uses the block it receives to tell the pickaxe if it can harvest it. Look at the if statement for obsidian:
This is basically saying "if the block the pickaxe is hitting is obsidian, the pickaxe can harvest the block if it's harvestLevel is equal to 3." Since we set our pickaxe's harvestLevel to three, it can harvest obsidian. Now for iron ore:
This says "if the block the pickaxe is hitting is an iron block or (|| means a logical "or") is an iron ore, the pickaxe can harvest the block if its harvestLevel is greater-than or equal to 1."
So, let's add our ore with a harvestLevel requirement of 2:
Now our ore can be harvest by a iron pickaxe or better.
Speed:
The speed of a tool is defined by many factors, such as the hardness of the block and the tool's speed in EnumToolMaterial. Because there are so many (and I haven't found them all yet :tongue.gif: ) I won't list them all here. To get a reference of what to set your speed to, look at the other entries in the enumerator.
Damage to entities:
The amount of damage your tools will do is on a half-heart basis. If you set it to 4, it will do 4 half-hearts, or 2 full hearts. Swords however, follow a different pattern. To find out how much damage swords do, we have to open ItemSword.java. Let's look at the constructor for this class:
The line "weaponDamage" is the line that finalizes the damage done to mobs. Let's go over this line. The constructor uses EnumToolMaterial as a parameter, so it gets the material the tool is made of and uses it's properties. The line we are looking at gets the damage of our tools ("enumtoolmaterial.getDamageVsEntity()" is the part that gets the data), multiplies it by 2, and adds 4. Since we set our damage to 2, our sword would do 2*2+4 damage, or 8 half-hearts to the mob we hit. Keep in mind a pickaxe only does 2 half-hearts to the mob we hit, only the sword has increased damage.
Add recipes to make your new tools (RecipesTools.java), recompile and test. Remember, if you get an error try the tutorial again. After three tries, make a post about it.
Congratulations, your toolset is complete!
Using the ModLoader (ML) can be much easier than normal modding. It has functions for registering almost anything you could possibly need. Since the ML has a Javadoc I don't really need to go over all of the functions, but I'll go over the basic ones that are used commonly.
Well, well, well. It seems we don't have the source code for the ModLoader. What we have to do is decompile it with the vanilla game. Install the ML into the JAR you decompiled (the one in "MCP\jars"). After you've done that we have to get rid of the old source code (the mods we made earlier). For this, we have to run cleanup.bat. After cleaning up run updatemcp.bat and decompile.bat. The decompiler will complain about hunks failing. This is normal and will happen persistently, but it doesn't affect any of the code we're going to make.
Let's get started by making our first ModLoader mod!
We're going to rewrite our ore to be ML compatible. This is almost identical to the non-ML modding, but we have to make our mod_ class (and I'll show you how!).
Your basic mod_ class follows this format (it must start with mod_ !):
This is the minimum you should have. Here's a version without comments all over the place:
For our block we can use the same line of code we made earlier in Block.java. Let's copy and paste that into our class:
Now we have to have ML register our Block. We have to add a line to the constructor:
The constructor is a neat function that is called every time you create a new instance of the class. So when you say "new Block()" it calls the constructor with the parameters that match the arguments you sent in Block.class. The ML automatically creates a new instance of any class that starts with mod_, so we don't need to worry about creating a new instance.
So, now we should have this:
Now all that's left is ore generation, public String Version(), and texture overrides. For our generation we use a new method in the mod_ class, "generateSurface()". It's exactly the same as ChunkProviderGenerate.java's "populate()" function. Let's add the base of our function:
And, let's copy and paste the generation code from our ores and ore generation tutorial:
There is one more line we have to add at this point. Because the ore generation code utilizes the Random class we have to import it:
This line goes directly under the package declaration at the top of the file. We also have to change Block.oreTutorial.blockID to mod_TutorialOre.oreTutorial.blockID, as we have declared the Block oreTutorial in mod_TutorialOre.class instead of Block.class.
Okay, now that we have that done let's go on to texture overrides. When coding the overrides you have to make sure that everything is capitalized correctly. The first thing we have to do is set our block's blockIndexInTexture to 0. This is the texture for grass, and the ML uses it to lay other textures on top of it.
Next, we have to add the override function to our constructor. After that, we should have this:
Now, we fill in our public String Version() with something that is relevant. Since our mod is complete, we'll make it version 1.0.
It's best to put your mod's version and the MC version it is made for. Since some mods (even ML mods) can be outdated it is important for debuggers to know what Minecraft version the mod is made for to check if it is up-to-date.
Your first ModLoader mod is complete! Next: Adding items with ML!
All aboard the SwaggaTrain...
Yes, did you not notice the big red letters at the top of the post? :tongue.gif:
So;
When <event>, the player will change into a different model, e.g. (Dwarf, making the body slightly smaller).
This might be a bit complex, maybe not that possible. But if you've seen the 'You are the Creeper' mod, that's what I mean. Changing the player's default body, (Not skin).
he reserved some spots so he can keep them in order and so that other people would not steal the spots, in other words makes his post look neat and clean and professional in the end.
This might be a little complex.
If you wanted to make a permanent change, you would just need to replace the player model with the model you want the player to be. To make it change under certain circumstances might be harder. A boolean to tell if the player should use the alternate model might work, but that's really advanced stuff.
Thanks, next part coming today!
I've never glanced at that code before, but I don't think I will have to after this :smile.gif: