Welcome to my tutorials!
In this thread I will be writing tutorials on how to mod utilizing ModLoader. I aim not to do the same tutorials as everyone else, but will still go over the basics for those who are just starting to mod. I also want to explain in quite great depth about what each part of the code does so that the people using these tutorials actually understand what it means, and hope that they wont just copy & paste the code I have written. I also aim to make tutorials that don't edit a single base class.Getting Set-Up
Installing the Java Development Kit is the first thing you'll need to do. Get it here. Now you'll need to set up the java path. I'm not sure how to do it on Mac, but this is how you do it on Windows. Go to My Computer, right click on 'Computer' in the left bar, and select 'Properties'. Once in properties, select 'Advanced System Settings'. Click 'Environment Variables...', then under 'System Variables', go to 'Path'. Without deleting any current path in there, add this to the end.
C:\Program Files\Java\jdk1.7.0_03\bin;. Make sure that your version is the same and it is in that same location. Just go to your C:/ drive and in program files look for Java, all your information for this will be in there if it is different.
Next, you'll need to download the Minecraft Coders Pack(MCP). Once you've downloaded it, you'll need to extract it somewhere. My Documents is a good place, but just send a shortcut to your desktop so its easier to get to it. You can place the folder on your desktop if you want to, but if you don't have a powerful computer, it can slow it down. Now, go to your .minecraft folder, and copy the whole bin folder to 'jars' in the extracted MCP. Make sure the minecraft.jar only has ModLoader in it. Any other mod, and it will probably fail decompiling. Once you have your jar set up, double click 'decompile.bat' in the MCP directory(or open the decompile.sh it in terminal if on a mac).. It will bring up a
command prompt/terminal window and will decompile the minecraft.jar. Once it has finished, it should say '1 out of 1 hunks failed', or something like that. Don't worry about it, it doesn't matter. All of the decompiled Minecraft files will be in mcp61/src/net/minecraft/src.
This is optional, but I highly recommend it. Download Eclipse. Its the first one on the list, 'Eclipse for Java Developers', just select your OS and download. After its downloaded, extract it to a folder and open eclipse.exe. This is very easy to set up. When it asks you to select a workspace, select the 'eclipse' folder in your MCP directory. It will now set everything up automatically. To get to the src files from the game in Eclipse, on the left, click 'Client', 'src', 'net.minecraft.src'.
The ModLoader Basics
package net.minecraft.src;
public class mod_*** extends BaseMod
{
public void load()
{
}
public String getVersion()
{
return "1.2.5";
}
}
This is the basic ModLoader 'template'. It is fairly simple and I will explain what each of the parts do.package net.minecraft.src;This line simply defines the package of the game that this file is placed in. There are several packages in Minecraft and different packages are called at different times.
public class mod_*** extends BaseMod'public class' defines that this is a class. It is a part of the Java language which Minecraft is written on. Other coding languages use it too. 'mod_***' defines that this is a ModLoader mod. The mod_ file is the most important part of a ModLoader mod. Without it, the mod will not work. 'extends BaseMod' allows you to use all of the ModLoader methods in the mod_ file. It is just as important as the class name starting with mod_ because your mod will not work without it.
public void load()This is the constructor of a mod_ file. This is ModLoader's constructor. Do not use or include the java constructor in this file. The ModLoader methods go in between the two squiggly brackets.
public String getVersion()
{
return "1.2.5";
}
This is used by ModLoader when it loads your mod. The version of Minecraft your mod is made for goes in here. A number/words in quotes should always be returned in this method. It should never return null.The Tutorials
All tutorials updated for 1.2.5! Please let me know of any problems you encounter.
Block
mod_Block
package net.minecraft.src;
public class mod_Block extends BaseMod
{
public static final Block Namehere = new BlockNamehere(160, 0).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
BlockNamehere
package net.minecraft.src;
import java.util.Random;
public class BlockNamehere extends Block
{
public BlockNamehere(int i, int j)
{
super(i, j, Material.wood);
}
public int idDropped(int i, Random random, int j)
{
return mod_Block.Namehere.blockID;
}
public int quantityDropped(Random random)
{
return 1;
}}
Understanding the Code
mod_Block
public static final Block Namehere = new BlockNamehere(160, 0)
- This declares the new block.
- The first name you put in('Namehere' in this case), is what you use in the rest of the file for referencing to each particular block.
- '= new BlockName' means that when the block is created, to get its data from the class called 'BlockName'. It will be different for each block if it has special features(See below if it doesn't).
- '(160, 0)' is the data value and the image coordinate in the terrain.png. Block ID's MUST be no higher then 255 and not being used already by Minecraft. As of 1.2.4, id's between 123-255 can be used.
- If you want to use your own image for your block, leave the second number in the brackets as 0, and use the ModLoader method for your image.
.setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);- '.setBlockName("name")' is used by the game to call the block while its running, instead of calling the other name you gave it, which is only used with-in the mod_ file.
- '.setHardness(3F)' defines how hard the block is(obviously), and how long it takes to mine. Remember to put an F after the integer(number).
- '.setResistance(4F)' is how resistant the block is to TNT.
- '.setLightValue(1F)' is the amount of light the block emits. If the number is too high, the game will crash because it cant handle the brightness. If you dont want your block to emit any light at all, just leave out this piece of code.
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});- The most important parts of this bit of code is the 'ModLoader.registerBlock' and 'ModLoader.addName'. 'ModLoader.registerBlock', quite simply, registers the block with the game so it knows that it is there. Without it, it wouldn't find it, and you might even get a crash.
- 'ModLoader.addName' adds the in-game name of the block, the name you see when the block is in your inventory/chest ect..
- 'Namehere.blockIndexInTexture' is not needed unless you want to use your own image for the block. Despite what it looks like, this doesn't actually override the terrain.png image. It only overrides the index to the terrain.png, which would normally be used for blocks. All images must be 16pixels by 16pixels and png in format.
- 'ModLoader.AddRecipe......' just adds the recipe for the block. Have a look at the "Crafting and Smelting Recipes" section for more information.
BlockNamehere
- Not much to explain here except for the material. There are several materials you can use for blocks, they all do different things. Ground, wood, rock and iron, are the main materials to use, but there are many more. If you want to see them all, have a look in Material.java.
- You can change what your block drops by adding its name in the idDropped method. You can only put one block or item here. If you need it to drop more, use some ''if'' statements. You can find an example of this in BlockCrops.
- The ''quantityDropped'' method simply allows you to change the amount dropped from the block when destroyed.
If your block has no special features, you can minimize the amount of files you have by doing this:
In your mod_ file, go to the line starting with 'public static final'. It should look something like this:public static final Block Namehere = new BlockName(160, 0).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
Now change it to say ' = new Block(id, 0, Material.wood)'. So it would look like this:public static final Block Namehere = new Block(160, 0, Material.wood).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
You can then delete the separate class you made for the block. You can change the matieral like explained above.Item
mod_Item
package net.minecraft.src;
public class mod_Item extends BaseMod
{
public static final Item Namehere = new ItemNamehere(5000).setItemName("anynamehere");
public void load()
{
Namehere.iconIndex = ModLoader.addOverride("/gui/items.png", "/pathtoyourfile/image.png");
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
ItemNamehere
package net.minecraft.src;
public class ItemNamehere extends Item
{
public ItemNamehere(int i)
{
super(i);
maxStackSize = 64;
}
}
Understanding the Code
mod_Item
- This is basically the same as the block except for a few differences.
- The public static final line states that the new object is an item. It says "public static final Item" instead of "public static final Block".
- '.setBlockName' is also changed to '.setItemName' for items.
- The other main difference is the icon indexing. For an item, it is
ItemNamehere
This is the same as a blocks, except it doesn't have 'int j' or the material included. Items do not have a material. They also don't have an idDropped or quantityDropped method
If your item has no special features, you can minimize the amount of files you have by doing this:
In your mod_ file, go to the line starting with 'public static final'. It should look something like this:public static final Item Namehere = new ItemNamehere(960).setItemName("anynamehere");
Now change it to say ' = new Item(id)'. So it would look like this:public static final Item Namehere = new Item(960).setItemName("anynamehere");
You can then delete the separate class you made for the item.Textures
Namehere.iconIndex = ModLoader.addOverride("/gui/items.png", "/pathtoyourfile/image.png");
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
You will have one of these two for your block/item. Make sure you have a / in front of your image directory. If you are wondering what this means, or where you put your images, keep reading. Basically, this method just overrides the index of your item/blocks picture. The game would normally look in the terrain.png or items.png for an image, but because we're using ModLoader, and not editing any base classes or images, we add 'ModLoader.addOverride...'.Your images can go in:
mcp/bin
mcp/bin/minecraft
mcp/jars/bin/minecraft.jar
If you're using Eclipse, they go here(Note: images can't go in the above directories when using eclipse):
mcp/eclipse/Client/bin
mcp/jars/bin/minecraft.jar
If my line looked like this:
Namehere.iconIndex = ModLoader.addOverride("/gui/items.png", "/mods/flower.png");
and was using eclipse,my picture would go in here:
mcp/eclipse/Client/bin/mods/flower.png
Its basically the same thing, if you're not using eclipse. Using the example above, but without eclipse, my picture would go in here:
mcp/bin/minecraft/mods/flower.png
All images should be 16pixelsX16pixels and must be .png in format.
I hope this has cleared things up for a few people wondering about their custom images.
Crafting & Smelting Recipes
(Incl. Dyes)
Crafting
ModLoader.addRecipe(new ItemStack(itemtoreceive, quantity), new Object [] {"#@#", "%%%", "@#@", Character.valueOf('#'), Block.stone, Character.valueOf('@'), Block.dirt, Character.valueOf('%'), Item.ingotIron});
That recipe would look like this:
- 'ModLoader.addRecipe' is just the ModLoader method for adding a recipe.
- '(new ItemStack(itemtoreceive, quantity), new Object []' means to create a new inventory stack of the item in brackets, and add the number after the item name to the quantity of the stack.
- '{"#@#", "%%%", "@#@", ' is the actual recipe of the item. The first set of quotes is the first row in the crafting table, the second set of quotes is the second row, and so on.
- 'Character.valueOf('#'), Block.stone... ' means to associate the name of the block/item, with the symbol in brackets, and then that symbol in the recipe. There must be an equal amount of spaces in each row. If you have a recipe like this,

"###", " $ ", " $ ", Character.valueOf('#')//and so on
Smelting
ModLoader.addSmelting(Block.dirt.blockID, new ItemStack(Item.ingotGold, 1));Smelting recipes are fairly simple, 'ModLoader.addSmelting' is the ModLoader method for smelting recipes. '(Block.dirt.blockID, new ItemStack(Item.goldIngot, 1));' just says that putting a block of dirt into the furnace and smelting it, will result into a new stack being created of gold ingots. One ingot being added to the new stack every time a dirt block is smelted.
Using Your Own Item
If you want to use your own item in a recipe, just use the name you made for it in the 'public static final' line. For example(also applys to blocks):
public static final Item Camera = new Item(2112).setItemName("Camera");
ModLoader.addRecipe(new ItemStack(cameraOnTripod, 1), new Object [] {" # ", " % ", "% %", Character.valueOf('#'), Camera, Character.valueOf('%'), Item.ingotIron});
ModLoader.addSmelting(Camera.shiftedIndex, new ItemStack(BurntCamera, 1));
Using Dyes
ModLoader.addRecipe(new ItemStack(itemname, quantity), new Object[] {"#", Character.valueOf('#'), new ItemStack(Item.dyePowder, 1, 3)});
That recipe would make an item from cocoa beans being alone in the crafting grid. This is the part for adding the dye as an ingredient.
Character.valueOf('#'), new ItemStack(Item.dyePowder, 1, 3)
It is basically a call for metadata, which is what the dye is stored in(multiple items, 1 id. 15:1, 15:2, etc) 1 is the quantity, and 3 is the colour of the dye. Even as an ingredient, you must have the quantity there. The colour of 3 is cocoa beans. All of the id's for dyes can be found hereFood
mod_Food
package net.minecraft.src;
public class mod_Food extends BaseMod
{
public static final Item Namehere = new ItemFood(5001, 4, 1F, false).setItemName("anynamehere");
public void load()
{
Namehere.iconIndex = ModLoader.addOverride("/gui/items.png", "/pathtoyourfile/image.png");
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", "#", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
Understanding the Code
- Food is just an item, that has a little difference. It heals the food bar.
- How this is done, is by making the new item extend a class called ItemFood. ItemFood is set up with three integers and a boolean.
- The first, is simply the id of the item.
- The second is how many half
it heals. Putting a 4 in this spot will heal 
on the food bar when the food is eaten. - The third is the saturation level. Food saturation is an invisible bar that stops you from getting hungry for a certain amount of time. When the saturation bar is empty, the food bar 'jitters'.
- The boolean at the end is whether or not a wolf can eat it. Putting a 'true' here will allow it to be eaten by a wolf.
Potion Effected Food
Applying a potion effect to a food. This is very easy to do. You simply make a food(follow the tutorial above), and add this bit of code to it:
.setPotionEffect(Potion.hunger.id, 30, 0, 0.8F)so it would fit in like this:
public static final Item Namehere = new ItemFood(5001, 4, 1F, false).setPotionEffect(Potion.hunger.id, 30, 0, 1F).setItemName("anynamehere");
Note that .setPotionEffect MUST go before .setItemName otherwise you will get recompilation errors. I use the hunger potion in this example, which is what is used in rotten flesh. You can use any potion effect when doing this. They are all listed in Potion.java. I'm not sure what the 0 means, but the 30 is the time the effect lasts for. An int of 1 here lasts for a second, 15 lasts for 15 seconds, etc. The float(1F) is the chance of the potion being successful. Rotten flesh has 0.8F here, and it has an 80% chance of giving you food poisoning. Having 1F in this position should be a 100% success rate.
Human NPC
mod_HumanNPC
package net.minecraft.src;
import java.util.Map;
public class mod_HumanNPC extends BaseMod
{
public void load()
{
ModLoader.registerEntityID(EntityNamehere.class, "IngameEntityName", ModLoader.getUniqueEntityId());
ModLoader.addSpawn(EntityNamehere.class, 12, 14, 18, EnumCreatureType.creature);
}
public void addRenderer(Map map)
{
map.put(EntityNamehere.class, new RenderBiped(new ModelBiped(), 0.5F));
}
public String getVersion()
{
return "1.2.5";
}
}
EntityNamehere
package net.minecraft.src;
import java.util.Random;
public class EntityNamehere extends EntityCreature
{
public EntityNamehere(World world)
{
super(world);
texture = "/image.png";
moveSpeed = 0.5F;
attackStrength = 4; //take this line out if this class doesn't extend EntityMob.
}
public int getMaxHealth()
{
return 20;
}
protected String getLivingSound()
{
return "mob.villager.default";
}
protected String getHurtSound()
{
return "mob.villager.defaulthurt";
}
protected String getDeathSound()
{
return "mob.villager.defaultdeath";
}
protected int getDropItemId()
{
return Item.ingotIron.shiftedIndex;
}
protected boolean canDespawn()
{
return false;
}
}
Understanding the Code
mod_HumanNPC
- "ModLoader.registerEntityID" is the ModLoader string for registering a new entity.
- "(EntityNamehere.class, "In-gameEntityName", ModLoader.getUniqueEntityId());" registers the class, with the name you give it in quotes, and gives each one of the entitys spawned a unique id, that you used to be able to see above mobs when you pressed F3.
- The name you put in quotes, is the name you would use in Single Player Commands to spawn it. This is just one example that the name is used for.
- "ModLoader.addSpawn" is the ModLoader string for add entities to the spawn list.
- "(EntityNamehere.class, 12, 14, 18, EnumCreatureType.creature);", this just defines the entity to be spawned, the spawn rates of the entity and the type of entity it is.
- The ints in the middle(12, 14, 18) all mean different things.
- The 12 is the probability of the amount being spawned.
- The 14 is the minimum spawned per chunk and the 18 is the maximum spawned per chunk.
- There are three different types of creatures a mob can be. The three different types are 'monster', 'creature' and 'waterCreature'.
- These define when the mobs will spawn. 'monster' means at night, 'creature' means during the day and 'waterCreature' means, obviously, in water.
public void addRenderer(Map map)
{
map.put(EntityNamehere.class, new RenderBiped(new ModelBiped(), 0.5F));
}
This simply links the model and render class with the entity. Without this, your entity will be a big white box.EntityNamehere
- This class can extend: EntityCreature, EntityMob or EntityWaterCreature. EntityCreature will be a friendly mob, EntityMob will be hostile like a zombie and EntityWaterCreature will be just like a squid.
- The texture is the same as the player skin.
- 'moveSpeed' and 'attackStrength' are completebly changeable to what you want them to be. They are kind of self-explanatory. 'attackStrength' is only for hostile mobs, you cannot have it in the code if making a friendly mob.
- 'getMaxHealth' is the amount of health the mob has, and again it is changeable to what you want it to be. There is a limit for this, but it is very, very high.
- Putting sounds in for it is up to you. You will find the sounds that each mob makes in its entity file(ex. EntityCow).
- If you want the mob to drop something when it dies, put it in the 'getDropItemId()' method.
- Setting the 'canDespawn()' to false, will not allow the mob to despawn unless killed.
Custom NPC
mod_CustomNPC
package net.minecraft.src;
import java.util.Map;
public class mod_CustomNPC extends BaseMod
{
public void load()
{
ModLoader.registerEntityID(EntityNamehere.class, "In-gameEntityName", ModLoader.getUniqueEntityId());
ModLoader.addSpawn(EntityNamehere.class, 15, 5, 7, EnumCreatureType.creature);
}
public void addRenderer(Map map)
{
map.put(EntityNamehere.class, new RenderNamehere(new ModelNamehere(), 0.5F));
}
public String getVersion()
{
return "1.2.5";
}
}
EntityNamehere
package net.minecraft.src;
import java.util.Random;
public class EntityNamehere extends EntityMob
{
public EntityNamehere(World world)
{
super(world);
texture = "/image.png";
moveSpeed = 0.5F;
isImmuneToFire = false;
attackStrength = 4; //This line can only be here if the class extends EntityMob above ^^^. If it doesn't, just delete this whole line
}
public int getMaxHealth()
{
return 20;
}
protected String getLivingSound()
{
return "mob.villager.default";
}
protected String getHurtSound()
{
return "mob.villager.defaulthurt";
}
protected String getDeathSound()
{
return "mob.villager.defaultdeath";
}
protected int getDropItemId()
{
return Item.ingotIron.shiftedIndex;
}
protected boolean canDespawn()
{
return false;
}
}
ModelNamehere
package net.minecraft.src;
public class ModelNamehere extends ModelBase
{
ModelRenderer Shape1;
public ModelNamehere()
{
textureWidth = 64;
textureHeight = 32;
Shape1 = new ModelRenderer(this, 0, 0);
Shape1.addBox(0F, 0F, 0F, 11, 8, 13);
Shape1.setRotationPoint(0F, 0F, 0F);
Shape1.setTextureSize(64, 32);
Shape1.mirror = true;
setRotation(Shape1, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5);
Shape1.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5);
}
}
RenderNamehere
package net.minecraft.src;
import org.lwjgl.opengl.GL11;
public class RenderNamehere extends RenderLiving
{
protected ModelNamehere modelNamehereMain;
protected float field_40296_d;
public RenderNamehere(ModelNamehere par1ModelNamehere, float par2)
{
this(par1ModelNamehere, par2, 1.0F);
modelNamehereMain = par1ModelNamehere;
}
public RenderNamehere(ModelNamehere par1ModelNamehere, float par2, float par3)
{
super(par1ModelNamehere, par2);
modelNamehereMain = par1ModelNamehere;
field_40296_d = par3;
}
}
Understanding the Code
mod_CustomNPC
- This is the same as the human NPC mod_ class except that it has two main differences. In the map.put line, it now has RenderBiped and ModelBiped changed to RenderNamehere and ModelNamehere. This allows us to use our own model and render it on the screen correctly.
EntityNamehere
- For what this class should extend, see the tutorial above, or other classes in the game that you want your mob's behaviour to share in.
- The texture line in this should be linked to an edited texture map that techne has outputted. This texture is then mapped to the model correctly. You put the texture for your mob in the same place as you would put the textures for items and blocks.
- moveSpeed is obviously how fast your mob moves. Play with this number until you find an appropriate speed for it to walk.
- isImmuneToFire is also an obvious one. If you want your mob to take no damage from fire or lava, return this to true.
- attackStrength, yet another obvious one. How much damage your mob does when it attacks. An 8 here equals 4 full hearts of damage. You can only have this line if the class extends EntityMob. You can't have it if it extends anything else.
- getMaxHealth is the amount of health the mob has. A 20 here means 10 full hearts of health.
- getLivingSounds, getHurtSound and getDeathSound are all optional. You can use the sounds of other mobs in the game by going to their Entity class and getting the name of the sound.
- getDropItemId is simply the item that the mob drops when it dies.
- canDespawn allows the mob to or not to despawn when you are not in range of it. Making this return false means it will never despawn apart from being killed.
ModelNamehere
- This class extends ModelBase because it is the only model that is blank which allows you to create your own design in it.
- "ModelRenderer Shape1" just calls the model renderer to keep Shape1 until it is time to render the whole model.
- textureWidth and textureHeight are quite simply the dimensions in pixels of your texture map. If you changed that in Techne, it should automatically change it in the code when it is generated.
- "Shape1.addBox(0F, 0F, 0F, 11, 8, 13);" means to add a prism. The first three Floats are the offset of the shape, on the x, y, z / i, j, k axes. The last 3 ints are the dimensions of your prism. These are in the x, y, z / i, j, k order as well.
- "Shape1.setRotationPoint(0F, 0F, 0F);" This line isn't actually the rotation point as such, but it is the position of the box. Once again, these are in order of x, y, z.
- "Shape1.setTextureSize(64, 32);" The 2 ints on this line should be the same the ones as above in the textureHeight and textureWidth statements.
- "Shape1.mirror = true;" This is what makes the texture mirrored if it is on top of another texture in the map.
- "setRotation(Shape1, 0F, 0F, 0F);" This is actually the rotation of the shape. Again, in order of the x, y, z axes.
- The "render" method is what actually renders everything onto the screen. All of your shapes that you have created need to be in here to be displayed.
- The "setRotation" method is just defining what axis each of the Floats belong to in the setRotation(Shape1..." line above.
- The "setRotationAngles" method is different to the one above. It is what calls the rotation angles of the shape.
RenderNamehere
- Explanation coming soon!
Other NPC Information
Specific Biome Spawning
ModLoader.addSpawn(EntityNamehere.class, 2, 1, 4, EnumCreatureType.monster, new BiomeGenBase[]
{
BiomeGenBase.biomesinhere
});- This is a part of ModLoader which allow specific biome spawning of mobs with the addSpawn method.
- Additional biomes that are added are separated by a comma. The last biome in between the {} doesn't need a comma.
ModLoader.addSpawn(EntityNamehere.class, 2, 1, 4, EnumCreatureType.monster, new BiomeGenBase[]
{
BiomeGenBase.mushroomIsland,
BiomeGenBase.jungle,
BiomeGenBase.jungleHills,
BiomeGenBase.hell
});
Look at the names of all the biomes in BiomeGenBase.
Holding an Item
To make your mob hold something, simply add this code to its Entity*** class.
public ItemStack getHeldItem()
{
return defaultHeldItem;
}
static
{
defaultHeldItem = new ItemStack(Item.ingotIron, 1);
}
private static final ItemStack defaultHeldItem;
So that it fits in like this:
package net.minecraft.src;
import java.util.Random;
public class EntityNamehere extends EntityMob
{
public EntityNamehere(World world)
{
super(world);
texture = "/image.png";
moveSpeed = 0.5F;
isImmuneToFire = false;
attackStrength = 4; //This line can only be here if the class extends EntityMob above ^^^. If it doesn't, just delete this whole line
}
public int getMaxHealth()
{
return 20;
}
protected String getLivingSound()
{
return "mob.villager.default";
}
protected String getHurtSound()
{
return "mob.villager.defaulthurt";
}
protected String getDeathSound()
{
return "mob.villager.defaultdeath";
}
protected int getDropItemId()
{
return Item.ingotIron.shiftedIndex;
}
protected boolean canDespawn()
{
return false;
}
public ItemStack getHeldItem()
{
return defaultHeldItem;
}
static
{
defaultHeldItem = new ItemStack(Item.ingotIron, 1);
}
private static final ItemStack defaultHeldItem;
}
Understanding the Code
- This is set up to work in the RenderBiped class. When this code is read, it calls to the render class, which gets the item we define and renders it icon in the mobs hand.
- This is quite a large amount of code for this simple thing that we are doing. But, as you can see, it is all linked together.
- getHeldItem calls defaultHeldItem
- defaultHeldItem calls itself in the static context
- In the static context, defaultHeldItem is equal to a new ItemStack of the type Item.ingotIron.
- An iron ingot is then rendered in the mobs hand.
Advanced Blocks
Flower
mod_Flower
package net.minecraft.src;
public class mod_Flower extends BaseMod
{
public static final Block Namehere = new BlockFlower(165, 0).setBlockName("anynamehere");
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"##", "##", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
Understanding the Code
This is a standard block with one little difference. It extends BlockFlower. BlockFlower has a few different methods in it. The most important ones are these:
public boolean isOpaqueCube()
{
return false;
}
public boolean renderAsNormalBlock()
{
return false;
}
public int getRenderType()
{
return 1;
}- isOpaqueCube allows us to use transparency/see through the block, without seeing down into the rest of the world.
- renderAsNormalBlock, quite an obvious one, returning false means that it will not look like a normal block.
public int getRenderType()
{
return 1;
}
This is the most important one for making your block look like a flower. The render type of 1 duplicates your image, and then rotates them to like in an X shape(top view).
More Complex Version
mod_Flower
package net.minecraft.src;
public class mod_Flower extends BaseMod
{
public static final Block Namehere = new BlockNamehereFlower(165, 0).setBlockName("anynamehere");
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"##", "##", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
BlockNamehereFlower
package net.minecraft.src;
import java.util.Random;
public class BlockNamehereFlower extends Block
{
protected BlockNamehereFlower(int i, int j)
{
super(i, Material.plants);
blockIndexInTexture = j;
setTickRandomly(true);
float f = 0.2F;
setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, f * 3F, 0.5F + f);
}
public boolean canPlaceBlockAt(World world, int i, int j, int k)
{
return super.canPlaceBlockAt(world, i, j, k) && canThisPlantGrowOnThisBlockID(world.getBlockId(i, j - 1, k));
}
protected boolean canThisPlantGrowOnThisBlockID(int i)
{
return i == Block.grass.blockID || i == Block.dirt.blockID || i == Block.tilledField.blockID;
}
public void onNeighborBlockChange(World world, int i, int j, int k, int l)
{
super.onNeighborBlockChange(world, i, j, k, l);
checkFlowerChange(world, i, j, k);
}
public void updateTick(World world, int i, int j, int k, Random random)
{
checkFlowerChange(world, i, j, k);
}
protected final void checkFlowerChange(World world, int i, int j, int k)
{
if (!canBlockStay(world, i, j, k))
{
dropBlockAsItem(world, i, j, k, world.getBlockMetadata(i, j, k), 0);
world.setBlockWithNotify(i, j, k, 0);
}
}
public boolean canBlockStay(World world, int i, int j, int k)
{
return (world.getFullBlockLightValue(i, j, k) >= 8 || world.canBlockSeeTheSky(i, j, k)) && canThisPlantGrowOnThisBlockID(world.getBlockId(i, j - 1, k));
}
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int i, int j, int k)
{
return null;
}
public boolean isOpaqueCube()
{
return false;
}
public boolean renderAsNormalBlock()
{
return false;
}
public int getRenderType()
{
return 1;
}
}
Understanding the Code
This will have the same appearance as the less complex version above, but gives you a few more options on what you can change. I won't be explaining everything in here, but I will try to explain the most important things you might want to change.- setBlockBounds is basically the area that the black line is drawn around when looking at a block. Each of those floats do something different, you'll just have to fiddle with them until you figure out what each one does.
- canPlaceBlockAt and canThisPlantGrowOnThisBlockID just state which blocks you can put your new block on.
- The isOpaqueCube, renderAsNormalBlock and getRenderType methods are all explained above.
Transparent Block
mod_Block
package net.minecraft.src;
public class mod_Block extends BaseMod
{
public static final Block Namehere = new BlockName(160, 0).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
BlockName
package net.minecraft.src;
public class BlockName extends Block
{
public BlockName(int i, int j)
{
super(i, j, Material.wood);
}
public boolean isOpaqueCube()
{
return false;
}
}
Understanding the Code
The mod_ class is exactly the same as normal. No changes whatsoever. The only difference here is that the 'isOpaqueCube' method is added to the block class. This is the method that makes your block transparent, without you being able to see down into the rest of the world. This needs to return false to be able to work. If it returns true, you'll still see be able to see through into the world.Stairs
mod_Stairs
package net.minecraft.src;
public class mod_Stairs extends BaseMod
{
public static final Block Namehere = new BlockNamehereStairs(170, 0).setBlockName("mystairs").setHardness(3F).setResistance(4F);
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"# ", "## ", "###", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
BlockNamehereStairs
package net.minecraft.src;
import java.util.ArrayList;
public class BlockNamehereStairs extends Block
{
public BlockNamehereStairs(int i, int j)
{
super(i, j, Material.wood);
}
public void getCollidingBoundingBoxes(World world, int i, int j, int k, AxisAlignedBB axisalignedbb, ArrayList arraylist)
{
int l = world.getBlockMetadata(i, j, k);
if (l == 0)
{
setBlockBounds(0.0F, 0.0F, 0.0F, 0.5F, 0.5F, 1.0F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
setBlockBounds(0.5F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
}
else if (l == 1)
{
setBlockBounds(0.0F, 0.0F, 0.0F, 0.5F, 1.0F, 1.0F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
setBlockBounds(0.5F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
}
else if (l == 2)
{
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 0.5F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
setBlockBounds(0.0F, 0.0F, 0.5F, 1.0F, 1.0F, 1.0F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
}
else if (l == 3)
{
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 0.5F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
setBlockBounds(0.0F, 0.0F, 0.5F, 1.0F, 0.5F, 1.0F);
super.getCollidingBoundingBoxes(world, i, j, k, axisalignedbb, arraylist);
}
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
public void onBlockPlacedBy(World world, int i, int j, int k, EntityLiving entityliving)
{
int l = MathHelper.floor_double((double)((entityliving.rotationYaw * 4F) / 360F) + 0.5D) & 3;
if (l == 0)
{
world.setBlockMetadataWithNotify(i, j, k, 2);
}
if (l == 1)
{
world.setBlockMetadataWithNotify(i, j, k, 1);
}
if (l == 2)
{
world.setBlockMetadataWithNotify(i, j, k, 3);
}
if (l == 3)
{
world.setBlockMetadataWithNotify(i, j, k, 0);
}
}
public void setBlockBoundsBasedOnState(IBlockAccess iblockaccess, int i, int j, int k)
{
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
}
public boolean isOpaqueCube()
{
return false;
}
public boolean renderAsNormalBlock()
{
return false;
}
public int getRenderType()
{
return 10;
}
}
Understanding the Code
mod_Stairs
- This is the same as a normal block.
BlockNamehereStairs
- getCollisionFromBoundingBox adds the collision boxes for the block. I believe the 'else if' statements change the collision box depending on the direction that the block is facing.
- All the 'if' statements in the onBlockPlaced method just make the block face you when you place it.
- The isOpaqueCube and renderAsNormalBlock methods are explained in the Flower tutorial in the Advanced Block spoiler.
- getRenderType is also explained in the Flower tutorial, but this time it is a little different. This time, it returns 10 instead of 1. 10 is the render type of stairs and will change your tesxtures to fit the block for you.
Half-Slab
mod_Slab
package net.minecraft.src;
public class mod_Slab extends BaseMod
{
public static final Block Namehere = new BlockNamehereSlab(250, 0).setBlockName("anynamehereslab").setHardness(3F).setResistance(4F);
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/imageslab.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.cobblestone});
}
public String getVersion()
{
return "1.2.5";
}
}
BlockNamehereSlab
package net.minecraft.src;
import java.util.Random;
public class BlockNamehereSlab extends Block
{
protected BlockNamehereSlab(int i, int j)
{
super(i, j, Material.wood);
setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.5F, 1.0F);
setLightOpacity(255);
}
public boolean isOpaqueCube()
{
return false;
}
public int idDropped(int i, Random random, int j)
{
return mod_Slab.Namehere.blockID;
}
public int quantityDropped(Random random)
{
return 1;
}
public boolean renderAsNormalBlock()
{
return false;
}
public boolean shouldSideBeRendered(IBlockAccess iblockaccess, int i, int j, int k, int l)
{
if (this != Block.stairSingle)
{
super.shouldSideBeRendered(iblockaccess, i, j, k, l);
}
if (l == 1)
{
return true;
}
if (!super.shouldSideBeRendered(iblockaccess, i, j, k, l))
{
return false;
}
if (l == 0)
{
return true;
}
else
{
return iblockaccess.getBlockId(i, j, k) != blockID;
}
}
}
Understanding the Code
- The mod_ class is the same as a normal block except so I won't explain anything in it.
- I have also explained pretty much all methods in the BlockNamehereSlab class too in above tutorials. I will explain a few things you might not have seen before though.
- setBlockBounds in the constructor of the block class is what makes you able to walk over it. 1F, 0.5F, and 1F are the length, height and width of the block, respectively.
- setLightOpacity can go up to 255 and down to 0. It simply means how much light it blocks out.
- The shouldSideBeRendered method is one that I can't seem to figure out. I have used the block with and without this code, next to stairs and such, but it doesn't seem to make a difference. I have left it in the tutorial in case someone does run into a few lighting issues when the block is next to stairs.
Achievement
mod_Achievement
package net.minecraft.src;
public class mod_Achievement extends BaseMod
{
public static final Achievement Namehere = new Achievement(4560, "Namehere", 5, 7, Item.diamond, null).registerAchievement();
public void load()
{
ModLoader.addAchievementDesc(Namehere, "Achievement Name", "Achievement Sub-Name");
}
public void takenFromCrafting(EntityPlayer entityplayer, ItemStack itemstack, IInventory iinventory)
{
if(itemstack.itemID == Block.fence.blockID)
{
entityplayer.addStat(Namehere, 1);
}
}
public String getVersion()
{
return "1.2.5";
}
}
Understanding the Code
mod_Achievement
public static final Achievement Namehere = new Achievement(4560, "Namehere", 5, 7, Item.diamond, null).registerAchievement();
- This initiates the achievement. 'Namehere' is just the name of the achievement you will use in the rest of the class just like you would with an item.
- 4560 is a unique id for the achievement, no other achievement can have it.
- The Namehere in quotes after 4560 should be the same as the first name you put before = new Achievement.
- 5 and 7 are the position of the achievement icon in the achievement window. You will just have to play with this until you find the right position.
- Item.diamond defines what icon will be used for the achievement. If you want to use your own icon, you'll need to create an item with that icon.
- null is where an achievement name is meant to be, but just leave it as null. See the Offspring section below for actually using this part.
- .registerAchievement() is to register it so it is actually used by the game.
ModLoader.addAchievementDesc(Namehere, "Achievement Name", "Achievement Sub-Name");
- ModLoader's achievement description string.
- Namehere is the same as the first name you put at the top of the class.
- "Achievement Name" is the name that appears as the main name, and what is under Achievement Get! when you acquire the achievement.
- "Achivement Sub-Name" is the name that appears under the main name in the achievement gui screen.
public void takenFromCrafting(EntityPlayer entityplayer, ItemStack itemstack, IInventory iinventory)
{
if(itemstack.itemID == Block.fence.blockID)
{
entityplayer.addStat(Namehere, 1);
}
}- This is used if you want to acquire the achievement by picking something up off the crafting grid.
- ''if(itemstack.itemID == Block.fence.blockID)'' means that it will continue through the code if you pick up a fence from the results slot after crafting it from sticks
- "entityplayer.addStat(Namehere, 1);" means to give you the achievement called ''Namehere''
I will be adding more ways to get the achievement as time goes on. Check back often for updates.
Making an Achievement Offspring of Another
This is just like where you need to have the "Acquire Hardware" achievement to get the "DIAMONDS!" achievement. To do this, you simply add this line of code:static Achievement name = AchievementList.diamonds;and change the "null" in the public static final line to the name you gave it before the "=" sign in the static line above. In this case it would be "name".
public static Achievement new Achievement = new Achievement(6130, "Diamond Hunter", -1, 3, Block.blockDiamond, name).registerAchievement();
You change the "AchievementList.diamonds" to any other achievement in AchievementList.java. For example, you might want your achievement to need to have the "Getting Wood" achievement, so your static line of code would look like this:
static Achievement name = AchievementList.mineWood;You just use the name of the achievement from AchievementList.java in that space.
Below is an example of needing to have the "DIAMONDS!" achievement, to be able to get a new modded achievement, called "Diamond Hunter" which you receive from crafting a diamond block.
package net.minecraft.src;
public class mod_Achievement extends BaseMod
{
static Achievement diamonds = AchievementList.diamonds;
public static Achievement diamondBlockAchievement = new Achievement(6130, "Diamond Hunter", -1, 3, Block.blockDiamond, diamonds).registerAchievement();
public void load()
{
ModLoader.addAchievementDesc(diamondBlockAchievement , "Diamond Hunter", "Craft a Diamond Block");
}
public void takenFromCrafting(EntityPlayer entityplayer, ItemStack itemstack, IInventory iinventory)
{
if(itemstack.itemID == Block.blockDiamond.blockID)
{
entityplayer.addStat(diamondBlockAchievement , 1);
}
}
public String getVersion()
{
return "1.2.5";
}
}
Here is a picture of that in-game:

After achievements required are completed

Thanks to 61352151511 for letting me build off his base diamond block achievement code, so I could make a good example for how to use offspring.
Making an Achievement "Special"
This is what changes the achievement from looking like a standard square achievement in the achievement GUI, to looking like the "Overkill". This is very, very simple to do. All you do is add this code to the public static final line:.setSpecial()so that it fits in like this:
public static Achievement diamondBlockAchievement = new Achievement(6130, "Diamond Hunter", -1, 3, Block.blockDiamond, diamonds).setSpecial().registerAchievement();
Using the example from above, it will now look like this:

Structure Generation
mod_WorldGen
package net.minecraft.src;
import java.util.Random;
public class mod_WorldGen extends BaseMod
{
public void load()
{
}
public void generateSurface(World world, Random random, int chunkX, int chunkZ)
{
for(int k = 0; k < 10; k++)
{
int RandPosX = chunkX + random.nextInt(5);
int RandPosY = random.nextInt(80);
int RandPosZ = chunkZ + random.nextInt(5);
(new WorldGenNamehere()).generate(world, random, RandPosX, RandPosY, RandPosZ);
}
}
public String getVersion()
{
return "1.2.5";
}
}
WorldGenNamehere
package net.minecraft.src;
import java.util.Random;
public class WorldGenNamehere extends WorldGenerator
{
public WorldGenNamehere()
{
}
public boolean generate(World world, Random random, int i, int j, int k)
{
int stoneBrick = Block.stoneBrick.blockID;
world.setBlockWithNotify(i, j, k, stoneBrick);
world.setBlockAndMetadataWithNotify(i, j + 1, k, stoneBrick, 1);
return true;
}
}
Understanding the Code
mod_WorldGen
- The first thing different is that Random is imported into the class.
- The next is the generateSurface method, which can be found in BaseMod as well.
- The line beginning with 'for' is a 'for loop'. The 10 in that line is the rarity of the structure.
- 'RandPosX' and 'RandPosZ' mean to start the structure at any random position on that axis at least 5(or whatever the number is in the brackets) blocks away from the edge of the chunk. (Not 100% sure about this, I think it has more to do with the density of generation)
- 'RandPosY' means to place the structure anywhere on the y axis up to the layer in the brackets. (80 in this case)
(new WorldGenNamehere()).generate(world, random, RandPosX, RandPosY, RandPosZ);
This line links it all together, and is where the structure in your WorldGenNamehere class is called.
WorldGenNamehere
- Random is also imported in this class.
- This class extends WorldGenerator which is where the main methods are located. (The generate method is mainly used)
public WorldGenNamehere() { }This is the constructor of the class. We don't need to add anything into it for what we're doing.- The next method is the generate method, and is where the designing of our structure takes place.
- Using an int like this one
int stoneBrick = Block.stoneBrick.blockID;
makes it a lot quicker to type things in. This is because we don't need to type Block.stoneBrick.blockID every time we want to generate that block. Instead, we just writestoneBrick
like is shown in the example code. world.setBlockWithNotify(i, j, k, stoneBrick);
That is the main method used to generate blocks. The i, j and k are positions on the i, j, k (x, y, z, respectively) axes of the block.- As your structures get bigger, these do too. You simply make the distance change by using a + (plus) or - (minus/hyphen) after the letter, and then putting a number, which is the number of blocks. For example:
world.setBlockWithNotify(i + 3, j + 2, k - 7, stoneBrick);
That would place a block 3 blocks further away from the starting point on the i/x axis, it would be 2 blocks higher than the starting point(It will still be at the same i/k position), and 7 blocks along the k/z axis away from the starting point. world.setBlockAndMetadataWithNotify(i, j, k, stoneBrick, 1);
You don't need to use this unless trying to generate blocks with a damage value. In this example, I am generating a stone brick block with the damage value of 1. A stone brick block with the damage value of 1 is mossy stone brick, 2 is cracked stone brick.

As you can see, the amount of generated sets of blocks in the background is quite high. This can be changed by changing the number in the brackets, in the 'RandPosX' and 'RandPosY' lines, in the GenerateSurface method, in your mod_ class. You can also change the 10 in the for loop line.
Note: Everytime that you change your design in your WorldGenNamehere class, or the density of it in the generateSurface method in mod_, you need to create a new world to see it.
Ore Generation
This tutorial will build off the block tutorial.
mod_OreGeneration
package net.minecraft.src;
import java.util.Random;
public class mod_OreGeneration extends BaseMod
{
public static final Block Namehere = new BlockNamehere(160, 0).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});
}
public void generateSurface(World world, Random random, int chunkX, int chunkZ)
{
for(int i = 0; i < 7; i++)
{
int randPosX = chunkX + random.nextInt(16);
int randPosY = random.nextInt(128);
int randPosZ = chunkZ + random.nextInt(16);
(new WorldGenMinable(Namehere.blockID, 25)).generate(world, random, randPosX, randPosY, randPosZ);
}
}
public String getVersion()
{
return "1.2.5";
}
}
Understanding the Code
As you'll notice, the generateSurface method has been added. All the information about this is as follows:- The 7 in the for loop is the rarity of your block when generated.
- The following three ints, as it says in the code, are the random positions that the blocks may be generated.
- In the randPosX and randPosZ lines, chunkX and chunkZ signify the edge of the chunk on those axes. The random.nextInt(16) parts means that any number up to 16 can be chosen. The number is chosen for how far in from the side of a chunk the block can be generated. Because a chunk is 16x16, having 16 in the brackets allows for the block to be generated anywhere in the chunk.
- The randPosY line is pretty much the same thing, except it goes up the vertical axis. Therefore, the number in the brackets is the height the block can be generated up to.
- The last line uses all the information your provide it with, in the random position ints.
- You put the block you want to generate in the brackets after "WorldGenMinable"
- The three inside the brackets is the size of the vein(I think, PM if you know for certain what it is)
- The generate method in WorldGenMinable requires 5 arguments. Those arguments are World(The world of the game), Random(A Java class, read the info about it at the link at the bottom of the OP), randPosX, randPosY and randPosZ. That is where the information from the ints is actually called and used.
Other World Generation
Specific Biome Block/Structure Generation
(Generating a structure/block in a specific biome only)
This tutorial will build off the Ore Generation tutorial, but can be used the same way with Structure tutorial.
mod_OreGeneration
package net.minecraft.src;
import java.util.Random;
public class mod_OreGeneration extends BaseMod
{
public static final Block Namehere = new BlockNamehere(160, 0).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});
}
public void generateSurface(World world, Random random, int chunkX, int chunkZ)
{
BiomeGenBase biomegenbase = world.getWorldChunkManager().getBiomeGenAt(chunkX, chunkZ);
WorldGen*** worldgen*** = new WorldGen***();
if(biomegenbase instanceof BiomeGen***)
{
for(int i = 0; i < 7; i++)
{
int randPosX = chunkX + random.nextInt(16);
int randPosY = random.nextInt(128);
int randPosZ = chunkZ + random.nextInt(16);
(new WorldGenMinable(Namehere.blockID, 25)).generate(world, random, randPosX, randPosY, randPosZ);
}
}
}
public String getVersion()
{
return "1.2.5";
}
}
Understanding the Code
The only added code here is this:
BiomeGenBase biomegenbase = world.getWorldChunkManager().getBiomeGenAt(chunkX, chunkZ);
WorldGen*** worldgen*** = new WorldGen***();
if(biomegenbase instanceof BiomeGen***)
{
//... code from previous tutorial/s
}
Basically, it creates an instance called biomegenbase from the BiomeGenBase type, it then gets the current biome at the location from the world's chunk manager. The next line just gets the BiomeGen class so you can use it from a static context. The third line, the if statement, just uses the biomegenbase instance, and checks it is equivalent to the BiomeGen*** class, then it continues on with the generation.
Obviously, you change the asterisks in the BiomeGen*** parts to the actual name of a BiomeGen class.
I know this wasn't a very good explanation and I didn't really use the correct names for certain things, but I think the methods that are called basically explain what they actually do anyway. Self-explanatory!
Multi-Textured Blocks
I'm using the block tutorial for this, and adding some code for the textures.
mod_Block
package net.minecraft.src;
public class mod_Block extends BaseMod
{
public static final Block Namehere = new BlockName(160, 0).setBlockName("anynamehere").setHardness(3F).setResistance(4F).setLightValue(1F);
public static int NamehereBottom = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/blockbottom.png");
public static int NamehereTop = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/blocktop.png");
public static int NamehereSides = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/blocksides.png");
public void load()
{
Namehere.blockIndexInTexture = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/image.png");
ModLoader.registerBlock(Namehere);
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addRecipe(new ItemStack(Namehere, 1), new Object [] {"#", Character.valueOf('#'), Block.dirt});
}
public String getVersion()
{
return "1.2.5";
}
}
BlockName
package net.minecraft.src;
public class BlockName extends Block
{
public BlockName(int i, int j)
{
super(i, j, Material.wood);
}
public int getBlockTextureFromSideAndMetadata(int i, int j)
{
return getBlockTextureFromSide(i);
}
public int getBlockTextureFromSide(int i)
{
if (i == 0)
{
return mod_Block.NamehereBottom;
}
if (i == 1)
{
return mod_Block.NamehereTop;
}
else
{
return mod_Block.NamehereSides;
}
}
}
Understanding the Code
mod_Block
- The only thing that is added to this class are the public static ints that contain our texture override information
public static int NamehereBottom = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/blockbottom.png");
public static int NamehereTop = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/blocktop.png");
public static int NamehereSides = ModLoader.addOverride("/terrain.png", "/pathtoyourfile/blocksides.png");- Using an int like this allows us to use it in another class.
BlockName
- This is what we need to add to allow us to choose our textures for each side of the block:
public int getBlockTextureFromSideAndMetadata(int i, int j)
{
return getBlockTextureFromSide(i);
}
public int getBlockTextureFromSide(int i)
{
if (i == 0)
{
return mod_Block.NamehereBottom;
}
if (i == 1)
{
return mod_Block.NamehereTop;
}
else
{
return mod_Block.NamehereSides;
}
}- In the getBlockTextureFromSide method, there are if statements saying things like "if (i == 0)" and "if (i == 1)", etc. The i 's mean the different faces of the block. For example, side 0 is the bottom of the block, side 1 is the top of the block, and sides 2, 3, 4 and 5 are the sides of the block.
- Where it has "return mod_Block.NamehereBottom;", this is the class that the texture int is in, and its name. For the bottom of the block, we made a public static int in mod_Block, and its name was NamehereBottom. So the game then gets the texture from that int, and applies it to that face of the block.
- In this example, I have shown you how to use a different texture for the top, bottom of the block, and the same one for all the sides of it.
Biome
This is quite a basic tutorial on a biome. There are heaps of variables you can use to change your biome around and make it really different and creative. Let your imagination run wild!
mod_BiomeNamehere
package net.minecraft.src;
public class mod_BiomeNamehere extends BaseMod
{
public static final BiomeGenBase Namehere = (new BiomeGenNamehere(25)).setColor(0xfa9418).setBiomeName("Any Name Here");
public void load()
{
ModLoader.addBiome(Namehere);
}
public String getVersion()
{
return "1.2.5";
}
}
BiomeGenNamehere
package net.minecraft.src;
import java.util.List;
import java.util.Random;
public class BiomeGenNamehere extends BiomeGenBase
{
public BiomeGenNamehere(int par1)
{
super(par1);
spawnableCreatureList.clear();
topBlock = (byte)Block.blockGold.blockID;
fillerBlock = (byte)Block.blockSteel.blockID;
biomeDecorator.treesPerChunk = 5;
biomeDecorator.flowersPerChunk = 4;
biomeDecorator.grassPerChunk = 10;
}
}
Understanding the Code
mod_BiomeNamehere
public static final BiomeGenBase Namehere = (new BiomeGenNamehere(25)).setColor(0xfa9418).setBiomeName("Any Name Here");- "BiomeGenBase" is put before the name of your instance just like items, blocks and achievements, etc.
- The number in brackets after the name of your new BiomeGen class is the ID of the new biome. This must be more than 23(that is the currently the highest uses biome ID) and less than 256.
- I think the ".setColor()" part of this line is optional. I believe it basically sets the ambience/colour around you when you're in it. You can find some colours here.
- ".setBiomeName("")" is the name of the biome(obviously). It is mainly used in the F3 Debug screen where it tells you what biome you're in.
ModLoader.addBiome(Namehere);
- This is the ModLoader string for adding a biome to biomesList[] array and the other classes needed so that the biome actually generates with the world.
BiomeGenNamehere
- This is a basic class that extends BiomeGenBase.
spawnableCreatureList.clear();
- That basically clears the list of creatures that can spawn in the biome.
- Have a look in the other BiomeGen*** classes on how you can make certain mobs spawn in your biome.
topBlock = (byte)Block.blockGold.blockID; fillerBlock = (byte)Block.blockSteel.blockID;
- "topBlock" is the block in the biome that is the top 1-5 blocks.
- "fillerBlock" is the block that fills the rest of the space until stone.
biomeDecorator.treesPerChunk = 5; biomeDecorator.flowersPerChunk = 4; biomeDecorator.grassPerChunk = 10;
- I think these lines are fairly self-explanatory. Please ask if you need an explanation though.
- Some other biomeDecorator strings/methods you can use include:
biomeDecorator.deadBushPerChunk = 2; biomeDecorator.reedsPerChunk = 50; biomeDecorator.cactiPerChunk = 10; biomeDecorator.mushroomsPerChunk = 8; biomeDecorator.clayPerChunk = 1; biomeDecorator.waterlilyPerChunk = 4;
Fuels
This tutorial will build off the item tutorial.
mod_Fuels
package net.minecraft.src;
public class mod_Fuels extends BaseMod
{
public static final Item Namehere = new Item(5000).setItemName("anynamehere");
public void load()
{
Namehere.iconIndex = ModLoader.addOverride("/gui/items.png", "/pathtoyourimage/image.png");
ModLoader.addName(Namehere, "In-Game Name Here");
ModLoader.addShapelessRecipe(new ItemStack(Namehere, 1), new Object[] {Item.coal, Item.wheat});
}
public int addFuel(int i, int j)
{
if(i == Namehere.shiftedIndex)
return 2750;
return 0;
}
public String getVersion()
{
return "1.2.5";
}
}
Understanding the Code
Adding a fuel is fairly simple and self-explanatory. The only extra code you need to use is the addFuel method.
- addFuel is a ModLoader method inherited from BaseMod.
- The name in the in the if statement is just the fuel you want to add.
- The int returned after it is the amount of ticks that the item fuels the furnace for. To refer to it more simply, you could call it the "smelting level" of the item.
- A return of 200 here will smelt one item. More simply, a full "smelting cycle".
- For reference, sticks are 100 and coal is 1600.
Adding Blocks to Creative Inventory
Read the following before spamming: "There is an easier way to do this, just add your block to ContainerCreative":
That is stupidand lazy. When you're modding, you should always aim not to edit ANY base class. If every mod was to edit ContainerCreative, only the mod that was last added would have its blocks added because the file would just get overridden each time. If you want to be an idiot, go right ahead and edit ContainerCreative, but don't leave a reply here saying something like "I know an easier way, add to ContainerCreative!". Leaving a reply like that just shows everyone that you have nothing better to do. I have an idea for you, go learn how to do stuff properly!
If you are smart and would like to add blocks to the creative inventory the proper way, keep reading.
This will just be a snippet of code(with an explanation, of course). It won't include any parts from the block tutorial. It will have a very simple explanation.
All of the code below goes into your mod_ class.
Firstly, you need to import Minecraft and List.
import net.minecraft.client.Minecraft; import java.util.List;Then this code:
public void load()
{
ModLoader.setInGameHook(this, true, false);
ModLoader.setInGUIHook(this, true, false);
}
public boolean onTickInGame(float f, Minecraft minecraft)
{
if(minecraft.currentScreen == null)
{
creativeInventory = null;
}
return true;
}
public boolean onTickInGUI(float f, Minecraft minecraft, GuiScreen guiscreen)
{
if((guiscreen instanceof GuiContainerCreative) && !(creativeInventory instanceof GuiContainerCreative) && !minecraft.theWorld.isRemote)
{
Container container = ((GuiContainer)guiscreen).inventorySlots;
List list = ((ContainerCreative)container).itemList;
int i = 0;
list.add(new ItemStack(block1, 1, i));
list.add(new ItemStack(block2, 1, i));
list.add(new ItemStack(block3, 1, i));
}
creativeInventory = guiscreen;
return true;
}
private static GuiScreen creativeInventory;
Understanding the Code
- As basically as I can put it, the code above checks if the creative inventory gui is open, then adds the blocks that you declare, into the inventory so you can get them.
list.add(new ItemStack(block1, 1, i));
- The line above is what actually adds your block to the inventory after all the checks are done. You just replace block1, block2, block3, etc. with the name of your block which you declared in its public static final line.
- Please ask if you need more of an explanation.
More tutorials on the post below!
List to Do, Not taking any more requests at this time:
- Crop
- Armour, Bow, Gun
- Trees
Tips & Info
- .blockID is only used for blocks.
- .shiftedIndex is used for items only.
- If the game crashes when starting the MCP client, and says it can't find your image, check your images location, its name and where you have told minecraft to look for it in your code.
- Only use one mod_ class for your whole mod.
Thank-you ![]()
-Reaper- - For helping people when I'm not around.
HellishINC - For letting me know of some errors so I could fix them.
RainbowLuigi - For support and helping people when I'm not around
KoadMaster - For heaps of support and helping people when I'm not around
PhantomJedi759 - For giving great help to people when I'm not around
Banners
By WadupMan!

[center] [url="http://www.minecraftforum.net/topic/960286-"] [img] http://i.imgur.com/alte6.png [/img] [/url] [/center]
By starfox1o1!

[url="http://www.minecraftforum.net/topic/960286-"][img]http://i.imgur.com/loo6b.png[/img][/url]
My Mods
1.SuperFoods - Adds Cocoa trees for all your cocoa bean needs, and heaps more!
2.Undead+ - Heaps of new hostiles! RandumbDude, lockNload147, MrCompost and myself are currently working very hard on this mod.
Final Notes
More to Come! Please do not troll saying "These tutorials have all been done before!". My main aim is to teach people what the code means. Most of the, so called, 'tutorials' on the forums, have no explanation whatsoever. Please remember there are people out there, who are just starting out. That's why they come here. TO LEARN. If I helped you understand something better, or think I should keep the tutorials coming, please hit that
button on the bottom right hand of this post, it helps and motivates me a lot.
If you have used someone else's tutorials and you have a problem with your code, do not ask for help here. I WILL ignore you. I will only help people who are having problems with their code from using my tutorials.
On the same note, if you are having trouble modding, don't just ask here, go and ask in the Mod Development section. As I said above, this thread is ONLY for people who are using the tutorials I have written and need some help.
How to Get Help
- Post your code and error using
code tags! Please do not just colour all the code and leave it in plain text form. Just put it inside the tags!
- Put all your code and errors in a spoiler. Even if it is short.
I suggest that everyone takes a look at this page, even if you aren't having trouble. It will help you a great deal.
Curse
MMO-Champion
WowStead
Arena Junkies
Minecraft Forums
DarthHater
Diablo Fans
Terraria Online















