[1.5] [WIP (again)] Deverion's Forge Modding Tutorials [Updated 16-03-2013] [1.5 Tutorials: 1!]

  • #1
    Deverion's Forge
    Modding Tutorials:

    Hey everyone, I just wanted to make this thread to help people with making mods :) Enjoy these tuts and give feedback, they should be able to take you from the basics to some fairly advanced work.

    PLEASE: Make sure you have at least a basic java knowledge before beginning on minecraft modding, you'll just get confused and find it hard to make interesting content. I recommend TheNewBoston, yes, it is a lot of tutorials, but he is a VERY good teacher :)

    To see the code used for this tutorial, visit the github, and also, don't try to change stuff, I'm a major github noob and I'll probably freak out xD

    I'm not just going to solve any problems you give me, if you have a legitimate problem, ask around elsewhere on the forums, I'm not here to write your mod for you. Note that you can also ask for help at the forge forums, the community over there is cool. I will, btw, help with requests for how to add content, suggestions for tutorials, and things I should add to my tutorials.

    Required programs:
    1. Eclipse

    2. Gimp

    3. WinRar/7Zip (Optional)
    Content:

    1.5:
    • Setting up mcp
    1.4.7:
    • Setting up your mod
    • Creating your first basic item
    • Creating items with metadata
    • Recipes, smelting and custom fuel
    • Custom creative mode tabs
    • Creating your first basic block
    • Creating blocks with metadata
    • Ore generation
    • Updating past 1.4.5
    • Special item effects
    • Using the ore dictionary
    • Distributing your mod! (Make sure you have a config first)
    • Using metadata items for tab icon
    • Using the ore dictionary pt.2
    • Updating to 1.4.7
    • Using the ore dictionary pt.3
    • Making items get damaged when used in crafting
    • Creating transparent blocks
    • Creating custom swords
    • Creating custom tools
    • Making your blocks get broken by a specific tool level
    • Creating configuration files
    Coming Soon:
    • Special block effects!
    • Crops!
    • Redstone interaction!
    • Basic tile entities and GUI's!
    • Custom trees!
    • Basic entities!
    • Special entity abilities!
    • Custom packets!
    • Advanced tile entities!
    • Special event hooks!
    • Custom liquids!
    • Liquid storage!
    • Liquid dictionary!
    • Custom stairs/slabs
    • ...and stuff (and things)!!
    Tutorials:

    1.5:

    Setting up MCP:
    To mod in minecraft, there are a few things you need:
    1. A basic/intermediate knowledge of java

    2. An idea for what you want to create

    3. MCP (Minecraft Coder Pack) version 742

    4. Minecraft Forge version 7.7.0.582+

    5. Winrar / 7Zip

    6. Any image editor (I prefer gimp)

    7. Eclipse / Other IDE
    To start open your zip with winrar / 7zip, and do the same with the minecraft forge zip. From minecraft forge, copy over the forge folder into mcp742.

    When you have that, you'll need to make a folder to keep your mod in, note that this can be in a github folder :) GIve the folder the name of your mod.

    From there, copy everything from mcp742 into your mod folder, and navigate to */forge, * being the name of your mod folder. Innside of that, run install.bat, or .sh if you're not on windows. With that running, sit back and relax, this could take a while depending on your system.

    Finally, once that finishes, you can open the minecraft code by opening */eclipse with eclipse. Note that if you are using a different IDE, you'll have to check on the MCP page for tutorials on how to open with it :)

    And with that, we're done here. In the next tutorial we can set up the framework for our mod, and then finally get to some more interesting things, I hope you enjoyed this tutorial, and remember to keep an eye on the thread!

    1.4.7:

    Starting you mod:
    Now that you have a decompiled Minecraft, you can open it by opening mod/eclipse inside of eclipse, this is where you'll spend most of your time modding...


    When it's open, navigate to Minecraft/src, and make a new package, name this package anything you want, preferably your username, which will help to avoid conflicts with other mods, just in case, this will be a global package that will hold all of you mods inside of MC (eg. deverionx.mineTech or deverionx.baitedFishing).

    Inside of that, make another package, the name of your mod, for this tutorial, I'll be working inside of deverionx.tutorial, but you can name it whatever you're working on. For the sake of neatness, I'll be organising the mod into deverionx.tutorial.common for everything based in the serverside, and deverionx.tutorial.client, for everything clientside, like GUI's and everything else to do with rendering, though this isn't actually necessary, it makes the mod easier to look at, if other people were to look at your code for some reason :) .

    Now, inside your common package, make your mod class, unlike old 1.2 modding, this doesn't have to be mod_***, it can be anything you want. This is the code you need, keep in mind that you should change the names to fit your own mod:

    package deverionx.tutorial.common; //The package your mod is in
    
    import net.minecraft.block.Block;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.item.Item;
    import cpw.mods.fml.common.Mod;
    import cpw.mods.fml.common.Mod.Init;
    import cpw.mods.fml.common.Mod.Instance;
    import cpw.mods.fml.common.event.FMLInitializationEvent;
    import cpw.mods.fml.common.network.NetworkMod;
    import cpw.mods.fml.common.network.NetworkRegistry;
    import cpw.mods.fml.common.registry.GameRegistry;
    import cpw.mods.fml.common.registry.LanguageRegistry;
    import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
    import cpw.mods.fml.common.SidedProxy;
    import deverionx.tutorial.client.core.handlers.ClientPacketHandler;
    import deverionx.tutorial.common.core.CommonProxy;
    
    @NetworkMod(clientSideRequired=true,serverSideRequired=false, //Whether client side and server side are needed
    clientPacketHandlerSpec = @SidedPacketHandler(channels = {"TutorialGeneral" }, packetHandler = ClientPacketHandler.class), //For clientside packet handling
    serverPacketHandlerSpec = @SidedPacketHandler(channels = {}, packetHandler = ServerPacketHandler.class)) //For serverside packet handling
    @Mod(modid="DeverionXTutorial",name="DeverionXTutorial",version="1.0") //Gives Forge extra info about your mod
    public class TutorialMain { //The class file
    
    @Instance("DeverionXTutorial") //The instance, this is very important later on
    public static TutorialMain instance = new TutorialMain();
    
    @SidedProxy(clientSide = "deverionx.tutorial.client.core.ClientProxy", serverSide = "deverionx.tutorial.common.core.CommonProxy") //Tells Forge the location of your proxies
    public static CommonProxy proxy;
    
    @Init
    public void InitCobaltCraft(FMLInitializationEvent event){ //Your main initialization method
    
    NetworkRegistry.instance().registerGuiHandler(this, proxy); //Registers the class that deals with GUI data
    }
    }


    You'll get some errors, but these will be resolved shortly. For the @Mod, modID is an incode name for you mod, and also appears in the server console when players log in with the mod, name and version are extra info that appear in the mod list ingame. Now though, you need to make your proxy classes:

    First, make a new package: deverionx.tutorial.common.core in my case
    CommonProxy:
    package deverionx.tutorial.common.core;
    
    import net.minecraft.block.Block;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.item.crafting.FurnaceRecipes;
    import net.minecraft.world.World;
    import cpw.mods.fml.common.network.IGuiHandler;
    import cpw.mods.fml.common.registry.GameRegistry;
    import cpw.mods.fml.common.registry.LanguageRegistry;
    import deverionx.tutorial.common.TutorialMain;
    
    public class CommonProxy implements IGuiHandler{ //THIS IS IMPORTANT, CANNOT BE A PROXY/GUI HANDLER WITHOUT THIS!!
    public void registerRenderInformation() //Client side texture registering
    {
    }
    @Override
    public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { //For GUI's
    return null;
    }
    @Override
    public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) { //For GUI's
    return null;
    }
    public void registerTiles(){ //For registering TileEntities
    }
    public void registerBlocks(){ //For registering Blocks
    }
    public void addNames(){ //For adding Item's ingame names
    }
    public void addRecipes(){ //For adding your Item's recipes
    }
    }


    And now the ClientProxy:
    package deverionx.tutorial.client.core;
    import deverionx.tutorial.common.core.CommonProxy;
    import net.minecraftforge.client.MinecraftForgeClient;
    public class ClientProxy extends CommonProxy {
    	
    public void registerRenderInformation(){
    }
    
    }


    Finally, add the packet handlers for later on:

    ServerPacketHandler:
    package deverionx.tutorial.common.core.handlers;
    
    import java.io.ByteArrayInputStream;
    import java.io.DataInputStream;
    
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.network.INetworkManager;
    import net.minecraft.network.packet.Packet250CustomPayload;
    import cpw.mods.fml.common.network.IPacketHandler;
    import cpw.mods.fml.common.network.Player;
    
    public class ServerPacketHandler implements IPacketHandler{
    
    
    @Override
    public void onPacketData(INetworkManager manager, Packet250CustomPayload payload, Player player){
    DataInputStream data = new DataInputStream(new ByteArrayInputStream(payload.data)); //Handles incoming data
    EntityPlayer sender = (EntityPlayer) player;
    }
    }


    ClientPacketHandler:
    package deverionx.tutorial.client.core.handlers;
    
    
    import java.io.ByteArrayInputStream;
    import java.io.DataInputStream;
    import java.io.IOException;
    
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.network.INetworkManager;
    import net.minecraft.network.packet.Packet250CustomPayload;
    import cpw.mods.fml.common.network.IPacketHandler;
    import cpw.mods.fml.common.network.Player;
    import cpw.mods.fml.relauncher.*;
    
    @SideOnly(Side.CLIENT)
    public class ClientPacketHandler implements IPacketHandler{
    @Override
    public void onPacketData(INetworkManager manager, Packet250CustomPayload payload, Player player){
    DataInputStream data = new DataInputStream(new ByteArrayInputStream(payload.data)); //Handles incoming data
    }
    }


    And with that, you have the foundation of a working mod! The next step is to start adding some items and blocks, and then we can get into more interesting stuff!
    Creating your first basic item:
    In this tutorial, I'm going to explain how to make a basic item in your mod. To start with, we need a texture! Put the texture inside a new file in the Minecraft/common folder named *yourMod*GFX.


    When you have the texture, add this line to ClientProxys' registerRenderInformation method:
    MinecraftForgeClient.preloadTexture("/TutorialGFX/Items.png");


    This will allow you to use your texture for items, but now we need to make our item class:

    We need a new package for items, for me it is: deverionx.tutorial.common.item. Now add the class:

    ItemRuby:
    package deverionx.tutorial.client.core.item;
    import net.minecraft.item.Item;
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    import net.minecraft.creativetab.CreativeTabs;
    public class ItemRuby extends Item {
    public ItemRuby(int par1) {
    super(par1); //Returns super constructor: par1 is ID
    setTextureFile("/TutorialGFX/Items.png"); //Sets the item texture file
    setItemName("DeverionXItemRuby"); //Sets the incode name of the item, make sure it doesn't clash with other items, weird stuff happens
    setCreativeTab(CreativeTabs.tabMaterials); //Tells the game what creative mode tab it goes in
    }
    
    @SideOnly(Side.CLIENT) //Marks a method as client side only, typically for graphics and rendering
    public int getItemIconFromDamage(int i){
    return 0; //The first icon on the spritesheet
    }
    }


    Everything in there is fairly self-explanatory, but I explained it in comments anyway. Now we need to make out item's object in the mod, so add this line:

    public static Item ruby = new ItemRuby(15000); //The ruby object


    Don't forget to import ItemRuby. Next, we should add an ingame name for it, go to addNames() in CommonProxy and add:

    LanguageRegistry.addName(TutorialMain.ruby, "Ruby"); //Adds the name for the ruby item


    And then call it in your mod class:

    proxy.addNames();


    And with that, your item should be working! Feel free to check it out in game, and keep an eye on this thread for more tutorials!
    Creating Metadata items:
    In this tutorial, I will be teaching you how to make more than one item in one ID, also called metadata. For this tutorial, you need this texture.


    Now that you have that (making sure it's in the TutorialGFX folder), you can make your item's class in the item package:

    ItemMetaGem:
    package deverionx.tutorial.client.core.item;
    import java.util.List;
    
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    import net.minecraft.creativetab.CreativeTabs;
    public class ItemMetaGem extends Item {
    public ItemMetaGem(int par1) {
    super(par1); //Returns super constructor: par1 is ID
    setTextureFile("/TutorialGFX/Items.png"); //Sets the item texture file
    setItemName("DeverionXItemMetaGem"); //Sets the incode name of the item, make sure it doesn't clash with other items, weird stuff happens
    setCreativeTab(CreativeTabs.tabMaterials); //Tells the game what creative mode tab it goes in
    setHasSubtypes(true); //Marks item as having metadata
    setMaxDamage(0);
    }
    
    @SideOnly(Side.CLIENT) //Marks a method as client side only, typically for graphics and rendering
    public int getIconFromDamage(int i){
    switch(i){ //Checks what the damage is
    case 0:return 1; //If damage equals 0 then return second icon
    case 1:return 2; //^
    case 2:return 3; //^
    }
    
    return 0; //If icon not already returned, just return 0
    }
    
    public String getItemNameIS(ItemStack is){ //Gets the metadata sensitive item name
    switch(is.getItemDamage()){ //Checks what damage is
    case 0:return "DeverionXItemSapphire"; //If damage is one, return name
    case 1:return "DeverionXItemAmethyst"; //^
    case 2:return "DeverionXItemTopaz"; //^
    }
    return "itemUnknown";
    }
    
    @SideOnly(Side.CLIENT)
    public void getSubItems(int itemID, CreativeTabs tab, List itemList) //Adds the metadata items to the creative inventory
    {
    for(int i=0;i<3;i++){
    itemList.add(new ItemStack(itemID,1,i)); //Adds all the metadatas
    }
    }
    }


    Then add the object to your mod class:

    public static Item metaGem = new ItemMetaGem(15001);


    Once again, don't forget to import it. Next we need to add their ingame names:

    LanguageRegistry.addName(new ItemStack(TutorialMain.metaGem,1,0), "Sapphire"); //Adds the sapphire gem name (metadata sensitive)
    LanguageRegistry.addName(new ItemStack(TutorialMain.metaGem,1,1), "Amethyst"); //Adds the amethyst gem name (metadata sensitive)
    LanguageRegistry.addName(new ItemStack(TutorialMain.metaGem,1,2), "Topaz"); //Adds the topaz gem name (metadata sensitive)


    Depending on how many metadata values you have, you may or may not want to use a for loop for it, but I decided not to for this tutorial.

    With that, you can check out your item ingame, and feel free to follow this thread to get updates on tutorials :)
    Recipes, smelting and fuel:
    In this tutorial, I will be explaining how to add recipes, shapeless recipes, smelting recipes and custom fuels.


    To start, let's make a recipe for the ruby, this goes in CommonProxy addRecipes() method:
    GameRegistry.addRecipe(new ItemStack(TutorialMain.ruby,1), "XAX", Character.valueOf('X'), new ItemStack(Item.dyePowder,1,1), Character.valueOf('A'),
    Block.glass); //Adds the ruby recipe



    This recipe will be one glass in between two red dye gives ruby. I'll go through this step by step:
    1: GameRegistry.addRecipe is the method used to add a regular recipe
    2: The first parameter is the ouput, in this case 1 ruby
    3: Then you put a string with letters, these indicate the location and type of item to be used
    4: Character.valueOf follows that, it tells what letter you'll describe
    5: This is followed by an Item/Block/ItemStack, you only really use itemstacks for adding metadata
    ingredients

    In this case, I use dye, the dye metadatas are as follows:

    0=Black
    1=Red
    2=Green
    3=Brown
    4=Blue(lapis lazuli)
    5=Purple
    6=Cyan
    7=Silver(light grey)
    8=Grey
    9=pink
    10=Lime
    11=Yellow
    12=Light Blue
    13=Magenta
    14=Orange
    15=White

    For wool blocks, it is reversed. Anyway, now to add a shapeless recipe:

    GameRegistry.addShapelessRecipe(new ItemStack(TutorialMain.metaGem,1,0), new ItemStack(Item.dyePowder,1,4), Block.glass); //Adds a shapeless recipe for sapphire
    GameRegistry.addShapelessRecipe(new ItemStack(TutorialMain.metaGem,1,1), TutorialMain.ruby, new ItemStack(TutorialMain.metaGem,1,0)); //Adds a shapeless recipe for amethyst


    The first recipe is one glass and one lapis anywhere on the table for a sapphire, and the second is one ruby and one sapphire anywhere on the table for an amethyst. If you look at the method, you'll see that there are no strings and no Character.valueOf's, this is because the items can be anywhere on the table. Now for the smelting recipe:

    GameRegistry.addSmelting(TutorialMain.ruby.itemID, new ItemStack(TutorialMain.metaGem,1,2), 5); //A non-metadata sensitive smelting recipe


    This is the main way to add a smelting recipe, the first parameter is the itemID of the input, the second is the output itemstack and the third is the xp reward. This recipe is that you put in one ruby and take out one topaz. Now for a meta-sensitive version:

    FurnaceRecipes.smelting().addSmelting(TutorialMain.metaGem.itemID, 1, new ItemStack(TutorialMain.metaGem,1,2), 5); //Metadata sensitive


    This makes it meta-sensitive. The first parameter is the itemID, the second is metadata, the third is output and the fourth is xp reward. The final thing left to do is add a custom fuel:

    To do this, first make the FuelHandler class in your common.core.handlers package:

    package deverionx.tutorial.common.core.handlers;
    
    import net.minecraft.item.ItemStack;
    import cpw.mods.fml.common.IFuelHandler;
    import deverionx.tutorial.common.TutorialMain;
    public class FuelHandler implements IFuelHandler{
    @Override
    public int getBurnTime(ItemStack fuel) { //This method sets burn time
    if(fuel.itemID == TutorialMain.ruby.itemID){
    return 150; //1/4 of coal
    }
    
    return 0;
    }
    }


    Then add this to your mod class:

    GameRegistry.registerFuelHandler(new FuelHandler());


    Don't forget to call CommonProxy.addRecipes(), otherwise your recipes won't work!:

    proxy.addRecipes();


    And with that, everything should be working! Feel free to check it out ingame, and keep an eye out for new tutorials :)
    Custom creative mode tabs:
    In this tutorial, I will be teaching you how to make a custom creative inventory tab. The first thing we need is out tab class, which is as follows (put it in a new package, for me: deverionx.tutorial.common.tabs):

    TabGems:
    package deverionx.tutorial.common.tabs;
    import net.minecraft.creativetab.CreativeTabs;
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    public class TabGems extends CreativeTabs {
    public TabGems(int position, String tabID) {
    super(position, tabID); //The constructor for your tab
    }
    @SideOnly(Side.CLIENT)
    public int getTabIconItemIndex() //The item it displays for your tab
    {
    return TutorialMain.ruby.itemID; //For this we'll use the ruby
    }
    public String getTranslatedTabLabel()
    {
    return "Gems"; //The name of the tab ingame
    }
    }


    I've explained everything in there in the comments, so now what we need to do is add the object to our mod class. Keep in mind that for this to work, you NEED to create the constructor before your items and blocks, otherwise they don't appear inside. This is our object's line:

    public static CreativeTabs tabGems = new TabGems(CreativeTabs.getNextID(),"DeverionXTabGems"); //Our custom creative tab's object


    Fairly simple, the first parameter is the position, in this case 12: on page 2 of the inventory. The reason that we use that method is because without it, we would have incompatibility problems. With this we have a working creative inventory tab, all you have to do now is go to your item classes and add them to the tab by changing the setCreativeTab(CreativeTabs.tabMaterial) method to setCreativeTab(TutorialMain.tabGems). Feel free to check it out ingame, and keep an eye on this thread for more updates :)

    Creating your first basic block:
    In this tutorial I will show you how to make your first basic block with forge:


    To start, let's make our block class:
    package deverionx.tutorial.common.blocks; //The location of the class
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    public class BlockRuby extends Block {
    public BlockRuby(int ID) {
    super(ID, Material.iron); //The ID and material (The material defines what tools are better on it)
    setTextureFile("/TutorialGFX/Blocks.png"); //The texture file
    setBlockName("DeverionXBlockRuby"); //The incode name of the block
    setHardness(5.0F); //How hard the block is to break
    setResistance(10.0F); //How well the block resists explosions
    setStepSound(super.soundMetalFootstep); //The sound the block makes when you walk on it as well as place or break it
    setCreativeTab(TutorialMain.tabGems); //The tab it appears in
    }
    
    @SideOnly(Side.CLIENT)
    public int getBlockTextureFromSide(int i){ //What texture it uses
    return 1;
    }
    }


    I've explained it all in the code and apart from that it really is very simple. Next we need an object for it in the mod class:

    public static Block blockRuby = new BlockRuby(250); //The block object


    And then we need to register the block, which allows it to render without crashing the game. Put this line before the other proxy calls:

    proxy.registerBlocks(); //Calls the registerBlocks method


    When that's done, we need to register the block in the proxy method like this:

    GameRegistry.registerBlock(TutorialMain.blockRuby, "DevXTutorialRuby"); //Register the block


    Simple enough, then add the block ingame name:

    LanguageRegistry.addName(TutorialMain.blockRuby, "Ruby Block");


    And the recipe:

    GameRegistry.addRecipe(new ItemStack(TutorialMain.blockRuby,1), "XXX","XXX","XXX", Character.valueOf('X'), TutorialMain.ruby);


    And with that, feel free to check it out ingame and keep an eye out for new tutorials ;)

    Creating blocks with metadata:
    In this tutorial I will be explaining how to make metadata blocks with forge:


    To start, we once again need our block class, which is slightly longer than the last one:
    package deverionx.tutorial.common.blocks;
    import java.util.ArrayList;
    import java.util.List;
    
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.item.ItemStack;
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    public class BlockMetaGem extends Block{
    public BlockMetaGem(int ID){
    	 super(ID,Material.rock); //The ID and material
    	
    	 setBlockName("DeverionXOdedBlockOre"); //The incode name
    	 setHardness(3.0F); //How hard the block is
    	 setResistance(5.0F); //How well the block resists explosions
    	 setStepSound(Block.soundStoneFootstep); //The sounds the block makes
    	 setCreativeTab(TutorialMain.tabGems); //The tab it appears in
    	 setTextureFile("/TutorialGFX/Blocks.png"); //The texture file
    }
    
    public int getBlockTextureFromSideAndMetadata(int i, int j){ //The different textures fo different metadatas
    switch(j){
    case 0:return 2; //For sapphire
    case 1:return 3; //For amethyst
    case 2:return 4; //For topaz
    default:return 0;
    }
    }
    
    public int damageDropped(int i){ //Tells it what block it drops and also for creative mode pick block
    return i;
    }
    
    @SideOnly(Side.CLIENT)
    public void getSubBlocks(int par1, CreativeTabs par2CreativeTabs, List par3List) //Adds the metadata blocks to the creative inventory
    {
    	 for (int var4 = 0; var4 < 3; ++var4)
    	 {
    		 par3List.add(new ItemStack(par1, 1, var4));
    	 }
    }
    }


    Everything is explained in the comments like always. For metadata blocks, just having the block class isn't enough, we also need an item for it:

    package deverionx.tutorial.common.item;
    import java.util.List;
    
    import net.minecraft.item.ItemBlock;
    import net.minecraft.item.ItemStack;
    
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemBlockMetaGem extends ItemBlock
    {
    public ItemBlockMetaGem(int par1)
    {
    	 super(par1);
    	 this.setMaxDamage(0); //Stops bad things from happening
    	 this.setHasSubtypes(true); //Tells it that it has metadata versions
    }
    @SideOnly(Side.CLIENT)
    public int getIconFromDamage(int par1) //Gets the texture
    {
    	 return TutorialMain.metaBlock.getBlockTextureFromSideAndMetadata(2, par1);
    }
    public int getMetadata(int par1) //Returns the metadata value
    {
    	 return par1;
    }
    public String getItemNameIS(ItemStack is) //Get's the item incode name from an itemstack
    {
    	 String[] types = {"Sapphire","Amethyst","Topaz"};
    	 return "DeverionXBlock" + types[is.getItemDamage()];
    }
    }


    With that done, we can make the block object in the mod class:

    public static Block metaBlock = new BlockMetaGem(251);


    And then we need to register it, this is slightly different from a basic block:

    GameRegistry.registerBlock(TutorialMain.metaBlock, ItemBlockMetaGem.class,"DevXTutorialRuby");


    This time it registers the block together with the itemblock. Now all we need are the names and recipes:

    For the names, we need to use itemstacks like when we made metadata items:

    LanguageRegistry.addName(new ItemStack(TutorialMain.metaBlock,1,0), "Sapphire Block");
    LanguageRegistry.addName(new ItemStack(TutorialMain.metaBlock,1,1), "Amethyst Block");
    LanguageRegistry.addName(new ItemStack(TutorialMain.metaBlock,1,2), "Topaz Block");


    And then for the recipes I'll use a for loop:

    for(int i = 0;i < 3;i++){
    GameRegistry.addRecipe(new ItemStack(TutorialMain.metaBlock,1,i), "XXX","XXX","XXX", Character.valueOf('X'), new ItemStack(TutorialMain.metaGem,1,i));
    }


    And with that, you can check out your block's ingame and keep an eye out for new tutorials :)

    Ore Generation:
    In this tutorial, I will be showing you how to generate custom ores in the world:

    To start, download this texture. Once that's done, we need a block class:

    package deverionx.tutorial.common.blocks;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import deverionx.tutorial.common.TutorialMain;
    public class BlockOre extends Block {
    public BlockOre(int ID){
    super(ID,Material.rock); //Parameters: Block ID, Block material
    setTextureFile("/TutorialGFX/Blocks.png"); //The texture file used
    setBlockName("DeverionXBlockOre"); //The incode block name
    setHardness(3.0F); //The block hardness
    setResistance(5.0F); //The explosion resistance
    setCreativeTab(TutorialMain.tabGems); //The tab it appears in
    }
    
    public int getBlockTextureFromSideAndMetadata(int i,int j){ //Gets the texture from metadata
    switch(j){
    case 0:return 5;
    case 1:return 6;
    case 2:return 7;
    case 3:return 8;
    default:return 0;
    }
    }
    
    public int damageDropped(int i){ //Makes sure pick block works right
    return i;
    }
    
    public void getSubBlocks(int i, CreativeTabs tab, List l){ //Puts all sub blocks into the creative inventory
    l.add(new ItemStack(i,1,0));
    l.add(new ItemStack(i,1,1));
    l.add(new ItemStack(i,1,2));
    l.add(new ItemStack(i,1,3));
    }
    
    
    public ArrayList<ItemStack> getBlockDropped(World w, int x, int y, int z, int meta, int fortune){ //Specifies the block drop
    ArrayList<ItemStack> list = new ArrayList<ItemStack>(); //The list of items
    
    list.add(new ItemStack(meta == 0 ? TutorialMain.ruby : TutorialMain.metaGem,1,meta == 0 ? 0 : meta-1)); //One guaranteed
    
    for(int i=0;i<2+fortune;i++){ //A loop for drops, increased by fortune enchant
    if(w.rand.nextInt(101) > 49){ //50% chance
    list.add(new ItemStack(meta == 0 ? TutorialMain.ruby : TutorialMain.metaGem,1,meta == 0 ? 0 : meta-1)); //Adds the gem
    }
    }
    
    return list; //Returns the finished list :)
    }
    }



    Then make the item block:

    package deverionx.tutorial.common.item;
    import net.minecraft.item.ItemBlock;
    import net.minecraft.item.ItemStack;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemBlockOre extends ItemBlock {
    public ItemBlockOre(int i){
    super(i);
    }
    
    public int getMetadata(int i){
    return i;
    }
    
    public String getItemNameIS(ItemStack is){
    switch(is.getItemDamage()){
    case 0:return "DeverionXBlockRubyOre";
    case 1:return "DeverionXBlockSapphireOre";
    case 2:return "DeverionXBlockAmethystOre";
    case 3:return "DeverionXBlockTopazOre";
    default:return "";
    }
    }
    
    public int getIconFromDamage(int i){
    return TutorialMain.ore.getBlockTextureFromSideAndMetadata(2,i);
    }
    }



    We're nearly at the world gen part, first we need to make the block object:

    public static Block ore = new BlockOre(252);


    Register the block:

    GameRegistry.registerBlock(TutorialMain.ore, ItemBlockOre.class, "DevXTutorialOre");


    And name the blocks:

    LanguageRegistry.addName(new ItemStack(TutorialMain.ore,1,0), "Ruby Ore");
    LanguageRegistry.addName(new ItemStack(TutorialMain.ore,1,1), "Sapphire Ore");
    LanguageRegistry.addName(new ItemStack(TutorialMain.ore,1,2), "Amethyst Ore");
    LanguageRegistry.addName(new ItemStack(TutorialMain.ore,1,3), "Topaz Ore");


    With that, we can start on the world gen part:

    First, make the class WorldGenHandle in deverionx.tutorial.common.core.handlers, implementing IWorldGenerator:

    package deverionx.tutorial.common.core.handlers;
    import java.util.Random;
    import net.minecraft.world.World;
    import net.minecraft.world.chunk.IChunkProvider;
    import net.minecraft.world.gen.feature.WorldGenMinable;
    import cpw.mods.fml.common.IWorldGenerator;
    import deverionx.tutorial.common.TutorialMain;
    public class WorldGenHandler implements IWorldGenerator { //Implements IWorldGenerator
    @Override
    public void generate(Random random, int chunkX, int chunkZ, World world, //This is the base generate method
    IChunkProvider chunkGenerator, IChunkProvider chunkProvider) {
    
    if (world.provider.isSurfaceWorld()){
    
    generateSurface(random,chunkX*16,chunkZ*16,world); //This makes it gen overworld (the *16 is important)
    
    }
    
    }
    
    public void generateSurface(Random random, int x, int z, World w){
    for(int i = 0;i<4;i++){ //This goes through the ore metadata
    for(int ii=0;ii<20;ii++){ //This makes it gen multiple times in each chunk
    int posX = x + random.nextInt(16); //X coordinate to gen at
    int posY = random.nextInt(40); //Y coordinate less than 40 to gen at
    int posZ = z + random.nextInt(16); //Z coordinate to gen at
    new WorldGenMinable(TutorialMain.ore.blockID,i,random.nextInt(9)).generate(w, random, posX, posY, posZ); //The gen call
    }
    }
    }
    }


    Let me explain in more detail:

    The generate method is an override from the interface, and inside it we get what world type it is. If we do it this way, we'll achieve Mystcraft compatibility, which is a good thing :) , if it's one: We generate the overworld, and call generateSurface

    In generate surface, the first for loop makes it go through the different metas
    The second loop is rarity, the number of veins in a chunk
    The x variable is the exact x coordinate for the ore
    The y variable is a random number less than 40
    The z variable is the exact z coordinate for the ore

    WorldGenMinable is the prewritten world gen for ores:

    The first parameter is the block ID
    The second parameter is the metadata
    The third parameter is the vein size

    Then we tell our GenMinable to generate with our three coordinates, our world object and our random

    Finally, all we have to do is register the world gen handler in our mod class:

    GameRegistry.registerWorldGenerator(new WorldGenHandler());


    And with that, the ores will generate in the world, so feel free to check it out ingame and keep an eye out for new tutorials :)

    Updating past 1.4.5
    In this tutorial, I will be helping you update your mod to 1.4.6:


    With the 1.4.6 update, the code in Minecraft has been completely reorganized into separate packages, which has killed imports, so to start we have to fix them:

    First move your code from your 1.4.5 mod to your 1.4.6 folder, and receive a lot of errors. Then you need to go through all of your classes fixing imports:

    The MC code was organized into packages like net.minecraft.block and net.minecraft.client.render, much like our mod, so the fixing shouldn't be too hard, it'll just take a while, and I personally recommend *erasing all of your imports and let eclipse help you import the new classes :)

    *Most of the *Forge imports should still be fine
    **The Side and SideOnly classes have been moved to cpw.mods.fml.relauncher.*';
    **The GameRegistry.registerBlock method has changed, give it a String parameter at the end for the mod specific name, this helps the block avoid conflicts :D (Do the same for metadata block registers)


    When your imports are fixed, just go ingame and see if everything still works, if it doesn't just ask for help here and I'll do my best to help!


    Special item effects:
    In this tutorial, I will be showing you how to add special effects to your items:

    First, get this texture, then we need an item class:

    ItemRubyStaff:
    package deverionx.tutorial.common.item;
    import java.util.List;
    import net.minecraft.block.Block;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.EnumRarity;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemRubyStaff extends Item {
    public ItemRubyStaff(int par1) {
    super(par1);
    setTextureFile("/TutorialGFX/Items.png"); //Texture File
    setItemName("DeverionXRubyStaff"); //Incode item name
    setCreativeTab(TutorialMain.tabGems); //Tab it appears in
    }
    
    public int getIconFromDamage(int i){ //Gets the icon to display
    return 4;
    }
    
    public boolean onItemUse(ItemStack is, EntityPlayer player, World w, int x, int y, int z, int l, float f, float f1, float f3){ //Called when an item is right clicked on a block
    if(w.getBlockId(x, y, z) == Block.planks.blockID){ //If blockId at x y z is planks:
    w.setBlockMetadataWithNotify(x, y, z, w.getBlockMetadata(x, y, z)+1); //Increase the metadata
    
    if(w.getBlockMetadata(x, y, z) == 4){ //If metadata is 4
    w.setBlockMetadata(x, y, z, 0); //Reset to 0
    }
    
    }else if(w.getBlockId(x, y, z) == Block.plantRed.blockID){ //If block id is red plant
    w.setBlockWithNotify(x, y, z, Block.plantYellow.blockID); //Changing block to yellow plant
    
    }else if(w.getBlockId(x, y, z) == Block.plantYellow.blockID){ //Vice Versa
    w.setBlockWithNotify(x, y, z, Block.plantRed.blockID);
    }else if(w.getBlockId(x, y, z) == Block.cobblestone.blockID){ //If block is cobble
    w.setBlockWithNotify(x, y, z, Block.cobblestoneMossy.blockID); //Set to mossy
    }else if(w.getBlockId(x, y, z) == Block.cobblestoneMossy.blockID){ //Vice versa
    w.setBlockWithNotify(x, y, z, Block.cobblestone.blockID);
    }
    return false;
    }
    
    @Override
    public void addInformation(ItemStack is, EntityPlayer player, List l, boolean B){ //Additional info (eg. the names of music discs)
    l.add("This staff is magical!");
    }
    
    public EnumRarity getRarity(ItemStack is){ //The colour of the item name (eg. with golden apples)
    return EnumRarity.epic;
    }
    
    @Override
    public int getDamageVsEntity(Entity e){ //The amount of damage dealt to an entity when using this item as a weapon
    return 0;
    }
    
    public boolean hasEffect(ItemStack is){ //Adds an effect to the item (eg. golden apples)
    return true;
    }
    }


    Everything is explained in the comments, mostly:

    In onItemUse:

    Parameter one is itemstack
    two is player
    three is world
    four to six are coordinates
    seven is block side

    In addInformation:

    Parameter one is itemstack
    two is player
    three is the info list

    In getRarity:

    Parameter one is the itemstack

    In getDamageVsEntity:

    Parameter one is the entity being hit

    In hasEffect:

    Parameter one is the itemstack

    Note that the itemstack parameters can be used to add different info/effects depending on metadata

    After that, we just need the usual, an object, name and recipe:

    public static Item rubyStaff = new ItemRubyStaff(15002);


    LanguageRegistry.addName(TutorialMain.rubyStaff, "Ruby Staff");


    GameRegistry.addRecipe(new ItemStack(TutorialMain.rubyStaff,1), " X"," X ","X ", Character.valueOf('X'), TutorialMain.ruby);


    And with that, you can go ingame and try out the item, keep an eye out for new tutorials, and I hope you enjoyed! :)
    Using the ore dictionary:
    In this tutorial, I will be showing you how to use the ore dictionary on your items and blocks:

    To start, I will explain the ore dictionary: The ore dictionary is a tool added by forge that allows your items to be used in recipes from other mods. For example, say you have a copper item, and another mod using the ore dictionary adds a recipe with their own copper bar, your copper will be able to be used in that recipe alongside the other mod's copper, so the ore dictionary provides basic integration between mods.

    To start, add the registerOre method to your commonproxy:

    public void registerOre(){ //Ore dictionary
    
    }


    Then add this line to the method:
    OreDictionary.registerOre("gemRuby", TutorialMain.ruby); //Basic item registration


    For metadata items, do this:
    OreDictionary.registerOre("gemSapphire", new ItemStack(TutorialMain.metaGem,1,0)); //Metadata item registration
    OreDictionary.registerOre("gemAmethyst", new ItemStack(TutorialMain.metaGem,1,1)); //^
    OreDictionary.registerOre("gemTopaz", new ItemStack(TutorialMain.metaGem,1,2)); //^


    Just like with names and recipes, you need to use itemstacks for metadata items.

    To register blocks to the ore dictionary, it is identical, just with the blocks instead.

    Remember this though: When you name something in the ore dictionary, it should always have this format so as to match other mods:

    "typeItem", eg: "gemRuby", or "ingotSteel"

    The last thing we need to do before we're done is call the method in our mod class after all the other's in our init method:

    proxy.registerOre();


    And with that, you can try recompiling your mod and testing it alongside another mod, I recommend Redpower, because it adds rubies and sapphires. Keep an eye out for new tutorials, and I hope you enjoyed!
    Distributing your mod!:
    In this tutorial, I will be showing you everything you need to do to distribute your mod:

    Step 1: Open your mod folder
    Step 2: Run the recompile.bat there (if on windows)
    Step 3: When that finishes, run reobfuscate.bat
    Step 4: Navigate to reobf/Minecraft
    Step 5: Copy your mod package (for me deverionx)
    Step 6: Create a zip file back in your mod folder named *yourmod*
    Step 7: Paste the mod package inside it
    Step 8: Paste your GFX folder inside it
    Step 9: Upload the zip file to Mediafire/Your preferred cloud storage site
    Step 10: If you want to, create an adf.ly link
    Step 11: Create your mod thread! Keep in mind to refer to the following rules:

    Your thread title must include the following in square brackets:
    Minecraft version for mod
    Forge
    Mod version (optional) (I recommend putting this one after mod name)
    Download count (optional)

    Then put the name of your mod.

    In the thread, you need:
    A full description of what the mod contains
    You NEED to have pictures
    You NEED a direct link for download
    You can have an adf.ly link
    Installation instructions
    A todo list (optional)

    If you get mod spotlights from youtubers, you can show them on your page like this:
    [media]thespotlight[/media]


    Remember to put screenshots and videos in spoilers most of the time

    I recommend having a changelog as well as an archive of previous mod versions.

    You can get copyrights here.

    NOTE: If your mod is incomplete (below version 1) It belongs in the WIP forum. If it is an addon for other mods, it belongs in content packs, otherwise, just put it in the general mod section

    And with that, your mod has been distributed and is available to the public, make sure to take critiscm as you should, and keep an eye out for more tutorials :) If you have any questions, send me a PM

    Using metadata items for tab icon:
    In this tutorial I will show you how to use metadata items for creative tab icons:

    To do this, simply replace the getTabIconIndex method with this:

    @SideOnly(Side.CLIENT)
    public ItemStack getIconItemStack(){
    return new ItemStack(TutorialMain.metaGem,1,2);
    }


    This will make the gem tab icon become the topaz

    I hope you enjoyed this quick tutorial, and remember to keep an eye out for more

    Using the ore dictionary, pt 2:
    In this tutorial, I will show you how to finish adding compatibility through the ore dictionary,

    This is fairly simple, so far, with what we've implemented, our items that are registered will be usable in other mod's recipes, but not the other way round. To fix this, we need to change our recipes:

    For shaped recipes, you need to do this:
    CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(new ItemStack(TutorialMain.rubyStaff,1)," X"," X ","X ",
    Character.valueOf('X'), "gemRuby")); //A shaped ore dictionary recipe


    As you can see, it's pretty similar to the regular shaped recipe, but instead of giving a item, block, or Itemstack, you give a string, that string being the ore dictionary name of your item. For shapeless recipes, it's pretty much the same:

    CraftingManager.getInstance().getRecipeList().add(new ShapelessOreRecipe(new ItemStack(TutorialMain.metaGem,1,1),"gemRuby",
    "gemAmethyst"));


    And with that, you can begin converting your recipes to ore recipes, and remember to keep an eye out for new tutorials :)

    Updating to 1.4.7
    In this short tutorial, I will be showing you what to do to update to 1.4.7:

    To start, update your forge and your MCP, and when they're set up, copy your code over to the new workspace.

    When that's done, there's minor tweaking to do:
    • you have to do is change every shiftedIndex to itemID.
    • Change the getItemIconFromDamage methods to getIconFromDamage
    • Change the getTabIconItemStack methods to getIconItemStack
    With that,you can go ingame and check if everything works, if it doesn't, send me a message and I'll help you out ;)

    Using the ore dictionary pt.3: Other methods:

    In this very short tutorial, I will be showing you other methods in the forge ore dictionary:

    The first is the getOres method, which looks like this:

    OreDictionary.getOres("gemRuby"); //Gets an arraylist of valid items


    The parameter is the ore name, and as the comment explains, the method returns an arraylist of items and blocks matching that name. You can use this for adding compatible recipes in custom machines/tile entities

    The second is the getOreNames method, which looks like this:

    OreDictionary.getOreNames(); //Returns an arraylist of ore names


    This method takes no parameters, and as the comment explains, returns an arraylist of all the ore names, an example of uses for this is the mod Twilight Forest, which uses this to find ores to generate in that dimension.

    The third is the getOreID method, like so:

    OreDictionary.getOreID("gemRuby"); //Gets a unique int ID for the ore type
    OreDictionary.getOreID(new ItemStack(xxx,1)); //Gets the unique ore ID from an itemstack, returns -1 if there isn't one


    This method can either use the ore name or an itemstack, and returns a unique int ID for the ore name.

    The fourth is the getOres method, which uses the unique int ID to return an arraylist of valid items:

    OreDictionary.getOres(0); //Returns an arraylist of valid items from the ore ID


    And there you have it, a few special methods using the ore dictionary that you can use for adding compatibility, hope you enjoyed and keep an eye out for new tutorials ;)

    Making items get damaged when used in crafting:
    In this tutorial, I will be showing you how to make items that get damaged when used in crafting. To start, we need our textures:

    When you have that, we need to make the item we'll be using as a tool:

    package deverionx.tutorial.common.item;
    import net.minecraft.item.Item;
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemFirestone extends Item {
    public ItemFirestone(int par1) {
    super(par1);
    setTextureFile("/TutorialGFX/Items.png");
    setItemName("DeverionXItemFireStone");
    setCreativeTab(TutorialMain.tabGems);
    setMaxDamage(30); //Sets the item's max damage
    setMaxStackSize(1); //Sets the maximum size of an itemstack for this item
    }
    
    @SideOnly(Side.CLIENT)
    public int getIconFromDamage(int i){
    return 5;
    }
    }


    As you can see, pretty much identical to a basic item, but for the setMaxDamage and setMaxStackSize, which you'll see in use later.

    Now we need to set up the other basics for the item:

    In the mod class:
    public static Item firestone = new ItemFirestone(15003);


    In proxy.addNames:
    LanguageRegistry.addName(TutorialMain.firestone, "Firestone");


    In proxy.addRecipes:
    GameRegistry.addRecipe(new ItemStack(TutorialMain.firestone,1), "XAX", Character.valueOf('X'), Item.flintAndSteel, Character.valueOf('A'), TutorialMain.ruby);


    Now for the special part, in your mod class, add this line to your init method:

    GameRegistry.registerCraftingHandler(new CraftingHandler());


    You will get an error, but we'll fix that in a moment:

    Create the class CraftingHandler in yourmod.common.core.handlers:

    package deverionx.tutorial.common.core.handlers;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.item.ItemStack;
    import cpw.mods.fml.common.ICraftingHandler;
    public class CraftingHandler implements ICraftingHandler {
    @Override
    public void onCrafting(EntityPlayer player, ItemStack item,
    IInventory craftMatrix) {
    }
    @Override
    public void onSmelting(EntityPlayer player, ItemStack item) {
    }
    }


    The onCrafting method is called when you take stuff out of a crafting table
    The onSmelting method is called when an item gets smelted

    Then add this to the onCrafting method:

    for(int i=0; i < craftMatrix.getSizeInventory(); i++) //Checks all the slots
    {		
    if(craftMatrix.getStackInSlot(i) != null) //If there is an item
    {
    ItemStack j = craftMatrix.getStackInSlot(i); //Gets the item
    if(j.getItem() != null && j.getItem() == TutorialMain.firestone) //If it's a firestone
    {
    	 ItemStack k = new ItemStack(TutorialMain.firestone, 2, (j.getItemDamage() + 1)); //Makes a new itemstack that's been damaged and has 2 items
    	 if(k.getItemDamage() >= k.getMaxDamage()){ //If it is destroyed
    	 k.stackSize--; //Removes the added item
    	 }
    	 craftMatrix.setInventorySlotContents(i, k); //Sets the slot to the new item
    }
    }
    }


    This may seem complicated at first, but it's actually really simple:

    What it does is it looks through the crafting slots, and if one of the items is the firestone, then it makes the itemstack be larger and be damaged.

    Then we can make another item, which will be the different things we can craft:

    package deverionx.tutorial.common.item;
    import java.util.List;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import cpw.mods.fml.relauncher.*;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemFiredGem extends Item {
    public ItemFiredGem(int par1) {
    super(par1);
    setTextureFile("/TutorialGFX/Items.png");
    setItemName("DeverionXItemFiredGem");
    setCreativeTab(TutorialMain.tabGems);
    setHasSubtypes(true);
    }
    
    @SideOnly(Side.CLIENT)
    public int getIconFromDamage(int i){
    switch(i){
    case 0:return 6;
    case 1:return 7;
    }
    
    return 0;
    }
    
    public String getItemNameIS(ItemStack is){
    switch(is.getItemDamage()){
    case 0:return "DeverionXItemStormStone";
    case 1:return "DeverionXItemLushStone";
    }
    return "itemUnknown";
    }
    
    @SideOnly(Side.CLIENT)
    public void getSubItems(int itemID, CreativeTabs tab, List itemList) //Adds the metadata items to the creative inventory
    {
    for(int i=0;i<2;i++){
    itemList.add(new ItemStack(itemID,1,i)); //Adds all the metadatas
    }
    }
    }


    Then make the object in your mod class. When that's done, add the names:

    LanguageRegistry.addName(new ItemStack(TutorialMain.firedGem,1,0), "Stormstone");
    LanguageRegistry.addName(new ItemStack(TutorialMain.firedGem,1,1), "Lushstone");


    The recipes are, despite what you might expect, completely normal, ish:

    GameRegistry.addShapelessRecipe(new ItemStack(TutorialMain.firedGem,1,0), new ItemStack(TutorialMain.metaGem,1,1), new ItemStack(TutorialMain.firestone,1,-1));


    As you can see, the only difference is the the firestone uses the metadata -1. which basically means that any metadata can be used. Then just do the same for the other gem:

    GameRegistry.addShapelessRecipe(new ItemStack(TutorialMain.firedGem,1,1), Item.emerald, new ItemStack(TutorialMain.firestone,1,-1));


    And with that, you should be done! Feel free to check it out ingame, and keep an eye out for new tutorial :)

    Creating transparent blocks:
    In this tutorial I will be showing you how to create transparent blocks, so to start, download this texture

    When you have that, we can make our first block class:

    BlockRubyGlass:
    package deverionx.tutorial.common.blocks;
    import java.util.Random;
    import cpw.mods.fml.relauncher.Side;
    import cpw.mods.fml.relauncher.SideOnly;
    import deverionx.tutorial.common.TutorialMain;
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import net.minecraft.world.IBlockAccess;
    public class BlockRubyGlass extends Block {
    public BlockRubyGlass(int i){
    super(i,Material.glass);
    setStepSound(soundGlassFootstep);
    setTextureFile("/TutorialGFX/Blocks.png");
    setHardness(0.3F);
    setResistance(0.0F);
    setCreativeTab(TutorialMain.tabGems);
    setBlockName("DeverionXBlockRubyGlass");
    }
    
    public int getBlockTextureFromSideAndMetadata(int i,int j){
    return 9;
    }
    
    public int quantityDropped(Random r){ //This will stop the block from dropping
    return 0;
    }
    
    @SideOnly(Side.CLIENT)
    public int getRenderBlockPass() //Put 0 for fully transparent or opaque blocks, and 1 for semi-transparent
    {
    	 return 1;
    }
    
    public boolean isOpaqueCube() //Tells the game if the block is transparent
    {
    	 return false;
    }
    
    public boolean renderAsNormalBlock() //Tells the game how to render the block
    {
    	 return false;
    }
    
    protected boolean canSilkHarvest() //Tells the game if silk touch can harvest the block
    {
    	 return true;
    }
    
    public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) //Renders neighbouring blocks
    {
    
    int i = par1IBlockAccess.getBlockId(par2, par3, par4);
    
    return i == blockID ? false:true;
    }
    }


    Quite a few different methods from normal, but everything is explained in the comments :)

    Next, we need to do the normal stuff:

    In the mod class:
    public static Block rubyGlass = new BlockRubyGlass(253);


    In proxy.registerBlocks():
    GameRegistry.registerBlock(TutorialMain.rubyGlass, "DevXTutorialRubyGlass");


    In proxy.addNames():
    LanguageRegistry.addName(TutorialMain.rubyGlass, "Ruby Glass");


    In proxy.addRecipes():
    GameRegistry.addShapelessRecipe(new ItemStack(TutorialMain.rubyGlass,1), TutorialMain.ruby, Block.glass);


    And with that, you can test it out ingame :) I have included a fully clear texture, so if you want to try that just change the settings as explained in the comments, and change the texture :)

    I hope you enjoyed, and remember to keep an eye out for new tutorials :D

    Creating custom swords
    In this tutorial, I will be showing you how to create a basic custom sword:

    To start, get this texture. When you have that, we can make our material, which goes in your mod class:

    public static EnumToolMaterial rubyMat = EnumHelper.addToolMaterial("Ruby", 3, 64, 100.0F, 3, 15); //The material


    When you have that, we need our item class, like so:

    package deverionx.tutorial.common.item;
    
    import cpw.mods.fml.relauncher.Side;
    import cpw.mods.fml.relauncher.SideOnly;
    import deverionx.tutorial.common.TutorialMain;
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityLiving;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.EnumAction;
    import net.minecraft.item.EnumToolMaterial;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    
    public class ItemTutorialSword extends Item
    {
    private int weaponDamage;
    private final EnumToolMaterial toolMaterial;
    
    public ItemTutorialSword(int ID, EnumToolMaterial material, int tex, String name)
    {
    super(ID); //The super constructor
    this.toolMaterial = material; //The material to be used
    this.maxStackSize = 1; //The max size of the itemstack
    this.setMaxDamage(material.getMaxUses()); //The durability
    this.setCreativeTab(TutorialMain.tabGems);
    this.weaponDamage = 4 + toolMaterial.getDamageVsEntity(); //How strong it is on enemies
    setTextureFile("/TutorialGFX/Items.png");
    this.setIconIndex(tex); //Sets the texture
    setItemName(name);
    }
    
    public int func_82803_g()
    {
    return this.toolMaterial.getDamageVsEntity();
    }
    
    //Gets how well it works on the block
    public float getStrVsBlock(ItemStack par1ItemStack, Block par2Block)
    {
    if (par2Block.blockID == Block.web.blockID)
    {
    return 15.0F;
    }
    else
    {
    Material var3 = par2Block.blockMaterial;
    return var3 != Material.plants && var3 != Material.vine && var3 != Material.coral && var3 != Material.leaves && var3 != Material.pumpkin ? 1.0F : 1.5F;
    }
    }
    
    //What must happen when you hit an entity
    public boolean hitEntity(ItemStack par1ItemStack, EntityLiving par2EntityLiving, EntityLiving par3EntityLiving)
    {
    par1ItemStack.damageItem(1, par3EntityLiving);
    return true;
    }
    
    //Called when you break a block
    public boolean onBlockDestroyed(ItemStack par1ItemStack, World par2World, int par3, int par4, int par5, int par6, EntityLiving par7EntityLiving)
    {
    if ((double)Block.blocksList[par3].getBlockHardness(par2World, par4, par5, par6) != 0.0D)
    {
    par1ItemStack.damageItem(2, par7EntityLiving);
    }
    
    return true;
    }
    
    //How much damage the sword deals
    public int getDamageVsEntity(Entity par1Entity)
    {
    return this.weaponDamage;
    }
    
    @SideOnly(Side.CLIENT)
    
    //Makes it render nicely
    public boolean isFull3D()
    {
    return true;
    }
    
    //Allows you to block on right click
    public EnumAction getItemUseAction(ItemStack par1ItemStack)
    {
    return EnumAction.block;
    }
    
    //The max use time of the action
    public int getMaxItemUseDuration(ItemStack par1ItemStack)
    {
    return 72000;
    }
    
    //Called on right clicking anywhere
    public ItemStack onItemRightClick(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
    {
    par3EntityPlayer.setItemInUse(par1ItemStack, this.getMaxItemUseDuration(par1ItemStack));
    return par1ItemStack;
    }
    
    //Can it harvest the block type?
    public boolean canHarvestBlock(Block par1Block)
    {
    return par1Block.blockID == Block.web.blockID;
    }
    
    //How easy it is to enchant
    public int getItemEnchantability()
    {
    return this.toolMaterial.getEnchantability();
    }
    
    //Returns the java name of the material
    public String func_77825_f()
    {
    return this.toolMaterial.toString();
    }
    
    //If it can be repaired
    public boolean getIsRepairable(ItemStack par1ItemStack, ItemStack par2ItemStack)
    {
    return TutorialMain.ruby.itemID == par2ItemStack.itemID ? true : super.getIsRepairable(par1ItemStack, par2ItemStack);
    }
    }


    The same as a normal item, except for all the methods that handle the speed on different blocks, how much damage it does and what is used to repair it in an anvil :) If you want to figure out what everything does, you can go through at your own speed.

    When that's done, we just need the basics:

    In your mod class:
    public static Item rubySword = new ItemTutorialSword(16001, rubyMat, 8, "DeverionXRubySword");


    In proxy.addNames():
    LanguageRegistry.addName(TutorialMain.rubySword, "Ruby Sword");


    In proxy.addRecipes():

    GameRegistry.addRecipe(new ItemStack(TutorialMain.rubySword, 1), "X","X","A", Character.valueOf('X'), TutorialMain.ruby,
    Character.valueOf('A'), Item.stick);


    And with that, you can try it out ingame :) It should do the same damage as a diamond sword, and have 64 durability. You should also be able to repair it in an anvil using rubies.

    If you enjoyed the tutorial, remember to follow and keep an eye on the thread ;)

    Creating custom tools:
    In this tutorial, I will be showing you how to create custom tools.

    NOTE: You need to have the material from the sword tutorial for this!

    To start, get this texture. When you have that, we'll create our base tool class:

    package deverionx.tutorial.common.item;
    import cpw.mods.fml.relauncher.Side;
    import cpw.mods.fml.relauncher.SideOnly;
    import deverionx.tutorial.common.EnumToolTutorial;
    import net.minecraft.block.Block;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityLiving;
    import net.minecraft.item.EnumToolMaterial;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import net.minecraftforge.common.ForgeHooks;
    public class ItemToolTutorial extends Item
    {
    private Block[] blocksEffectiveAgainst; //What it's good against
    public float efficiencyOnProperMaterial = 4.0F; //How fast it is
    public int damageVsEntity;
    //The material
    protected EnumToolMaterial toolMaterial;
    protected ItemToolTutorial(int ID, int Damage, EnumToolMaterial m, Block[] ea)
    {
    	 super(ID);
    	 this.toolMaterial = m; //The material
    	 this.blocksEffectiveAgainst = ea; //What it's good against
    	 this.maxStackSize = 1; //The max stack size
    	 this.setMaxDamage(m.getMaxUses()); //The max damage
    	 this.efficiencyOnProperMaterial = m.getEfficiencyOnProperMaterial();
    	 this.damageVsEntity = Damage + m.getDamageVsEntity();
    	 this.setCreativeTab(CreativeTabs.tabTools);
    }
    //How well it mines a block
    public float getStrVsBlock(ItemStack par1ItemStack, Block par2Block)
    {
    	 for (int var3 = 0; var3 < this.blocksEffectiveAgainst.length; ++var3)
    	 {
    		 if (this.blocksEffectiveAgainst[var3] == par2Block)
    		 {
    			 return this.efficiencyOnProperMaterial;
    		 }
    	 }
    	 return 1.0F;
    }
    //What happens when you hit an entity
    public boolean hitEntity(ItemStack par1ItemStack, EntityLiving par2EntityLiving, EntityLiving par3EntityLiving)
    {
    	 par1ItemStack.damageItem(2, par3EntityLiving);
    	 return true;
    }
    //What happens when you break a block
    public boolean onBlockDestroyed(ItemStack par1ItemStack, World par2World, int par3, int par4, int par5, int par6, EntityLiving par7EntityLiving)
    {
    	 if ((double)Block.blocksList[par3].getBlockHardness(par2World, par4, par5, par6) != 0.0D)
    	 {
    		 par1ItemStack.damageItem(1, par7EntityLiving);
    	 }
    	 return true;
    }
    //How much damage it does
    public int getDamageVsEntity(Entity par1Entity)
    {
    	 return this.damageVsEntity;
    }
    @SideOnly(Side.CLIENT)
    //Makes it have a slightly different render
    public boolean isFull3D()
    {
    	 return true;
    }
    //How well it enchants
    public int getItemEnchantability()
    {
    	 return this.toolMaterial.getEnchantability();
    }
    //Java name of the material
    public String getToolMaterialName()
    {
    	 return this.toolMaterial.toString();
    }
    //Allows for repair in an anvil
    public boolean getIsRepairable(ItemStack par1ItemStack, ItemStack par2ItemStack)
    {
    	 return this.toolMaterial.getToolCraftingMaterial() == par2ItemStack.itemID ? true : super.getIsRepairable(par1ItemStack, par2ItemStack);
    }
    //How fast it mines a block (Compatibility edition)
    @Override
    public float getStrVsBlock(ItemStack stack, Block block, int meta)
    {
    	 if (ForgeHooks.isToolEffective(stack, block, meta))
    	 {
    		 return efficiencyOnProperMaterial;
    	 }
    	 return getStrVsBlock(stack, block);
    }
    }


    It's fairly self explanatory, which is good, because now we can make the shovel:

    package deverionx.tutorial.common.item;
    import deverionx.tutorial.common.EnumToolTutorial;
    import deverionx.tutorial.common.TutorialMain;
    import net.minecraft.block.Block;
    import net.minecraft.item.EnumToolMaterial;
    public class ItemShovel extends ItemToolTutorial
    {
    public static final Block[] blocksEffectiveAgainst = new Block[] {Block.grass, Block.dirt, Block.sand, Block.gravel, Block.snow, Block.blockSnow, Block.blockClay, Block.tilledField, Block.slowSand, Block.mycelium};
    public ItemShovel(int ID, EnumToolMaterial m, int tex, String name)
    {
    	 super(ID, 1, m, blocksEffectiveAgainst);
    	 setTextureFile("/TutorialGFX/Items.png");
    	 this.setCreativeTab(TutorialMain.tabGems);
    	 setIconIndex(tex);
    	 setItemName(name);
    }
    public boolean canHarvestBlock(Block par1Block)
    {
    	 return par1Block == Block.snow ? true : par1Block == Block.blockSnow;
    }
    
    
    }


    And then the object in our mod class:

    public static Item rubyShovel = new ItemShovel(16002, rubyMat, 9, "DeverionXRubyShovel");


    In proxy.addNames():
    LanguageRegistry.addName(TutorialMain.rubyShovel, "Ruby Shovel");


    In proxy.addRecipes():
    GameRegistry.addRecipe(new ItemStack(TutorialMain.rubyShovel, 1), "X","A","A", Character.valueOf('X'), TutorialMain.ruby,
    Character.valueOf('A'), Item.stick);


    And when that's done you can check out the shovel ingame :D

    The other's are basically the same, so all you really need are the classes:

    Pickaxe:
    package deverionx.tutorial.common.item;
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import net.minecraft.item.EnumToolMaterial;
    import net.minecraft.item.ItemStack;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemPickaxe extends ItemToolTutorial
    {
    public static final Block[] blocksEffectiveAgainst = new Block[] {Block.cobblestone, Block.stoneDoubleSlab, Block.stoneSingleSlab, Block.stone, Block.sandStone, Block.cobblestoneMossy, Block.oreIron, Block.blockSteel, Block.oreCoal, Block.blockGold, Block.oreGold, Block.oreDiamond, Block.blockDiamond, Block.ice, Block.netherrack, Block.oreLapis, Block.blockLapis, Block.oreRedstone, Block.oreRedstoneGlowing, Block.rail, Block.railDetector, Block.railPowered};
    public ItemPickaxe(int ID, EnumToolMaterial m, int tex, String name)
    {
    	 super(ID, 1, m, blocksEffectiveAgainst);
    	 setTextureFile("/TutorialGFX/Items.png");
    	 setIconIndex(tex);
    	 setItemName(name);
    	 this.setCreativeTab(TutorialMain.tabGems);
    }
    
    public boolean canHarvestBlock(Block par1Block)
    {
    	 return par1Block == Block.obsidian ? this.toolMaterial.getHarvestLevel() == 3 : (par1Block != Block.blockDiamond && par1Block != Block.oreDiamond ? (par1Block != Block.oreEmerald && par1Block != Block.blockEmerald ? (par1Block != Block.blockGold && par1Block != Block.oreGold ? (par1Block != Block.blockSteel && par1Block != Block.oreIron ? (par1Block != Block.blockLapis && par1Block != Block.oreLapis ? (par1Block != Block.oreRedstone && par1Block != Block.oreRedstoneGlowing ? (par1Block.blockMaterial == Material.rock ? true : (par1Block.blockMaterial == Material.iron ? true : par1Block.blockMaterial == Material.anvil)) : this.toolMaterial.getHarvestLevel() >= 2) : this.toolMaterial.getHarvestLevel() >= 1) : this.toolMaterial.getHarvestLevel() >= 1) : this.toolMaterial.getHarvestLevel() >= 2) : this.toolMaterial.getHarvestLevel() >= 2) : this.toolMaterial.getHarvestLevel() >= 2);
    }
    public float getStrVsBlock(ItemStack par1ItemStack, Block par2Block)
    {
    	 return par2Block != null && (par2Block.blockMaterial == Material.iron || par2Block.blockMaterial == Material.anvil || par2Block.blockMaterial == Material.rock) ? this.efficiencyOnProperMaterial : super.getStrVsBlock(par1ItemStack, par2Block);
    }
    }


    Axe:
    package deverionx.tutorial.common.item;
    import net.minecraft.block.Block;
    import net.minecraft.block.material.Material;
    import net.minecraft.item.EnumToolMaterial;
    import net.minecraft.item.ItemStack;
    import deverionx.tutorial.common.TutorialMain;
    public class ItemAxe extends ItemToolTutorial
    {
    public static final Block[] blocksEffectiveAgainst = new Block[] {Block.planks, Block.bookShelf, Block.wood, Block.chest, Block.stoneDoubleSlab, Block.stoneSingleSlab, Block.pumpkin, Block.pumpkinLantern};
    public ItemAxe(int ID, EnumToolMaterial m, int tex, String name)
    {
    	 super(ID, 1, m, blocksEffectiveAgainst);
    	 this.setCreativeTab(TutorialMain.tabGems);
    	 setTextureFile("/TutorialGFX/Items.png");
    	 setIconIndex(tex);
    	 setItemName(name);
    }
    
    public float getStrVsBlock(ItemStack par1ItemStack, Block par2Block)
    {
    	 return par2Block != null && (par2Block.blockMaterial == Material.wood || par2Block.blockMaterial == Material.plants || par2Block.blockMaterial == Material.vine) ? this.efficiencyOnProperMaterial : super.getStrVsBlock(par1ItemStack, par2Block);
    }
    }


    And the hoe:
    package deverionx.tutorial.common.item;
    import cpw.mods.fml.relauncher.Side;
    import cpw.mods.fml.relauncher.SideOnly;
    import deverionx.tutorial.common.EnumToolTutorial;
    import deverionx.tutorial.common.TutorialMain;
    import net.minecraft.block.Block;
    import net.minecraft.creativetab.CreativeTabs;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.EnumToolMaterial;
    import net.minecraft.item.Item;
    import net.minecraft.item.ItemStack;
    import net.minecraft.world.World;
    import net.minecraftforge.common.MinecraftForge;
    import net.minecraftforge.event.Event.Result;
    import net.minecraftforge.event.entity.player.UseHoeEvent;
    public class ItemHoe extends Item
    {
    protected EnumToolMaterial theToolMaterial;
    public ItemHoe(int par1, EnumToolMaterial rubyMat, int tex, String name)
    {
    	 super(par1);
    	 this.theToolMaterial = rubyMat;
    	 this.maxStackSize = 1;
    	 this.setMaxDamage(rubyMat.getMaxUses());
    	 this.setCreativeTab(TutorialMain.tabGems);
    	 setIconIndex(tex);
    	 setItemName(name);
    	 setTextureFile("/TutorialGFX/Items.png");
    	
    }
    
    public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
    {
    	 if (!par2EntityPlayer.canPlayerEdit(par4, par5, par6, par7, par1ItemStack))
    	 {
    		 return false;
    	 }
    	 else
    	 {
    		 UseHoeEvent event = new UseHoeEvent(par2EntityPlayer, par1ItemStack, par3World, par4, par5, par6);
    		 if (MinecraftForge.EVENT_BUS.post(event))
    		 {
    			 return false;
    		 }
    		 if (event.getResult() == Result.ALLOW)
    		 {
    			 par1ItemStack.damageItem(1, par2EntityPlayer);
    			 return true;
    		 }
    		 int var11 = par3World.getBlockId(par4, par5, par6);
    		 int var12 = par3World.getBlockId(par4, par5 + 1, par6);
    		 if ((par7 == 0 || var12 != 0 || var11 != Block.grass.blockID) && var11 != Block.dirt.blockID)
    		 {
    			 return false;
    		 }
    		 else
    		 {
    			 Block var13 = Block.tilledField;
    			 par3World.playSoundEffect((double)((float)par4 + 0.5F), (double)((float)par5 + 0.5F), (double)((float)par6 + 0.5F), var13.stepSound.getStepSound(), (var13.stepSound.getVolume() + 1.0F) / 2.0F, var13.stepSound.getPitch() * 0.8F);
    			 if (par3World.isRemote)
    			 {
    				 return true;
    			 }
    			 else
    			 {
    				 par3World.setBlockWithNotify(par4, par5, par6, var13.blockID);
    				 par1ItemStack.damageItem(1, par2EntityPlayer);
    				 return true;
    			 }
    		 }
    	 }
    }
    @SideOnly(Side.CLIENT)
    public boolean isFull3D()
    {
    	 return true;
    }
    public String func_77842_f()
    {
    	 return this.theToolMaterial.toString();
    }
    }


    And when you have those setup, you have a full set of working tools ;)

    I hope you enjoyed, and don't forget to keep an eye out for new tutorials :D

    Making your ores get broken by a specific mining level:
    In this short tutorial, I will be showing you how to make your ores only get broken by a certain mining level and above.

    What this means, is that you'll be able to stop your ores from getting mined by wood level, stone level, iron level, or even diamond level if you've made a higher one.

    To do this, add these lines to proxy.registerBlocks():
    MinecraftForge.setBlockHarvestLevel(TutorialMain.ore, 0, "pickaxe", 2); //Sets the required harvest level and tool
    MinecraftForge.setBlockHarvestLevel(TutorialMain.ore, 1, "pickaxe", 2); //0 is wood, 1 is stone
    MinecraftForge.setBlockHarvestLevel(TutorialMain.ore, 2, "pickaxe", 2); //2 is iron
    MinecraftForge.setBlockHarvestLevel(TutorialMain.ore, 3, "pickaxe", 2); //3 is diamond


    This is the metadata sensitive version, and the parameters are as so:

    The first is the block.
    The second is the metadata.
    The third is the tool type, which can be "pickaxe"; "axe"; or "shovel"
    The last parameter is the harvest level, the different vanilla levels are explained in the comments.

    And with that, your ores will only be mineable be iron or higher. If you enjoyed this tutorial, remember to follow the thread, and keep an eye out for new tutorials :D

    Creating configuration files:
    In this tutorial, I will be showing you how to create your own configuration files :)

    To start, we'll be making our class. For the sake of this tutorial, ConfigCore:

    package deverionx.tutorial.common;
    
    import net.minecraftforge.common.Configuration;
    import net.minecraftforge.common.Property;
    import cpw.mods.fml.common.event.FMLPreInitializationEvent;
    
    public class ConfigCore {
    
    //Items
    public static int itemRubyID;
    public static int itemMetagemID;
    public static int itemRubystaffID;
    public static int itemFirestoneID;
    public static int itemFiredgemID;
    
    //Tools
    public static int toolRubyShovelID;
    public static int toolRubyPickID;
    public static int toolRubyAxeID;
    public static int toolRubySwordID;
    public static int toolRubyHoeID;
    
    //Blocks
    public static int blockRubyID;
    public static int blockMetablockID;
    public static int blockOreID;
    public static int blockRubyGlassID;
    
    //General
    public static boolean isAwesome;
    
    public static void loadConfig(FMLPreInitializationEvent e){
    Configuration config = new Configuration(e.getSuggestedConfigurationFile()); //Gets the file
    
    config.load(); //Loads it
    
    Property rubyItem; //This is a property, see below
    rubyItem = config.getItem("Ruby", 15000); //This gets the property
    rubyItem.comment = "The base ruby item"; //This adds a comment
    itemRubyID = rubyItem.getInt(); //This gets the value
    
    //Item ID's
    itemMetagemID = config.getItem("Meta Gem", 15001).getInt();
    itemRubystaffID = config.getItem("Ruby Staff", 15002).getInt();
    itemFirestoneID = config.getItem("Firestone", 15003).getInt();
    itemFiredgemID = config.getItem("Firedgem", 15004).getInt();
    
    //Tool ID's
    toolRubyShovelID = config.getItem("Ruby Shovel", 16001).getInt();
    toolRubyPickID = config.getItem("Ruby Pick", 16002).getInt();
    toolRubyAxeID = config.getItem("Ruby Axe", 16003).getInt();
    toolRubySwordID = config.getItem("Ruby Sword", 16004).getInt();
    toolRubyHoeID = config.getItem("Ruby Hoe", 16005).getInt();
    
    //Block ID's
    blockRubyID = config.getBlock("Ruby Block", 300).getInt();
    blockMetablockID = config.getBlock("Meta Block", 301).getInt();
    blockOreID = config.getBlock("Ore Block", 302).getInt();
    blockRubyGlassID = config.getBlock("Ruby Glass Block", 303).getInt();
    
    //General
    isAwesome = config.get(config.CATEGORY_GENERAL, "Is the mod awesome", true).getBoolean(true);
    
    config.save(); //Saves the file
    
    }
    
    }


    What we do is make an int for every ID, then, in loadConfig, which has FMLPreInitializationEvent as a parameter, we retrieve them. For that, we get the file from the event, and then load it. The first parameter of the config.getItem is the name that appears in the file, the second is the default ID. This method returns a property object, so we call getInt() to get the ID.

    If you getting an item, call config.getItem, this will group it with other items.


    If you are getting a block, call config.getBlock, this will group it with other blocks

    If you are getting something other than an ID, call config.get, with the first parameter as config.CATAGORY_GENERAL, the second as the name, and the third as the default. We then need to call getBoolean in this case, give that a default for if it gets an invalid boolean.

    Note that unless you are generating your block before the chunk is generated, ie. with biomes, make sure your ID is less than 256 with the config.getTerrainBlock method.

    We then need to remake all of our items' and blocks' objects in the preinit method like so, in the mod class:

    First, we change our objects to this:

    public static Item ruby;
    public static Item metaGem;
    public static Item rubyStaff;
    public static Item firestone;
    public static Item firedGem;
    
    public static EnumToolMaterial rubyMat = EnumHelper.addToolMaterial("Ruby", 3, 64, 100.0F, 3, 15); //The material
    
    public static Item rubySword;
    public static Item rubyShovel;
    public static Item rubyPickaxe;
    public static Item rubyAxe;
    public static Item rubyHoe;
    
    public static Block blockRuby;
    public static Block metaBlock;
    public static Block ore;
    public static Block rubyGlass;


    And then we add the preinit method, which gets called before the init:

    @PreInit()
    public void PreInitTutorial(FMLPreInitializationEvent e){
    ConfigCore cc = new ConfigCore();
    
    ConfigCore.loadConfig(e);
    
    ruby = new ItemRuby(cc.itemRubyID);
    metaGem = new ItemMetaGem(cc.itemMetagemID);
    rubyStaff = new ItemRubyStaff(cc.itemRubystaffID);
    firestone = new ItemFirestone(cc.itemFirestoneID);
    firedGem = new ItemFiredGem(cc.itemFiredgemID);
    
    
    rubySword = new ItemTutorialSword(cc.toolRubySwordID, rubyMat, 8, "DeverionXRubySword");
    rubyShovel = new ItemShovel(cc.toolRubyShovelID, rubyMat, 9, "DeverionXRubyShovel");
    rubyPickaxe = new ItemPickaxe(cc.toolRubyPickID, rubyMat, 10, "DeverionXRubyPickaxe");
    rubyAxe = new ItemAxe(cc.toolRubyAxeID, rubyMat, 11, "DeverionXRubyAxe");
    rubyHoe = new ItemHoe(cc.toolRubyHoeID, rubyMat, 12, "DeverionXRubyHoe");
    
    blockRuby = new BlockRuby(cc.blockRubyID);
    metaBlock = new BlockMetaGem(cc.blockMetablockID);
    ore = new BlockOre(cc.blockOreID);
    rubyGlass = new BlockRubyGlass(cc.blockRubyGlassID);
    }


    This is fairly simple, but it's also the reason why you should have a config going from the beginning, because changing everything when you have hundreds of items can be tedious.

    Also note that this can be used to disable sets of items, if you are diligent with all of your registering.

    And with that, you have a working config file, I hope you enjoyed, and remember to keep an eye out for new tutorials :D


    [represent]
  • #2
    On another note, I'm hoping to have at least 2-3 tutorials out per day, so keep an eye on the thread
  • #3
    liiike it! Keep it up for sure!
    You don't know whom you're dealing with.
  • #4
    Quote from DarkElfAlbain

    liiike it! Keep it up for sure!


    I have no plans of stopping any time soon :)
  • #5
    Great tutorial so far! I managed to get your example mod to compile and I'm able to see the item in game. I did notice a couple things though that could have stopped people less experienced with Eclipse.

    When I loaded the Eclipse folder for the first time, all the imports were messed up. I believe the build path variable "MCP_LOC" was not set and it defaulted to my home directory. (I'm using Linux so I'm not sure if it does that in other systems.) Since I couldn't figure out how to set the build path variable correctly, I ended up hard-coding all the relative paths to absolute ones.
    (In Eclipse's Java Build Path, there is a tab named "Source" and "Libraries". Everything listed in those two tabs were not pointing to the right path.)

    I know but one freedom, and that is the freedom of the mind. - Antoine de Saint-Exupery
  • #6
    Quote from Apostolique

    Great tutorial so far! I managed to get your example mod to compile and I'm able to see the item in game. I did notice a couple things though that could have stopped people less experienced with Eclipse.

    When I loaded the Eclipse folder for the first time, all the imports were messed up. I believe the build path variable "MCP_LOC" was not set and it defaulted to my home directory. (I'm using Linux so I'm not sure if it does that in other systems.) Since I couldn't figure out how to set the build path variable correctly, I ended up hard-coding all the relative paths to absolute ones.
    (In Eclipse's Java Build Path, there is a tab named "Source" and "Libraries". Everything listed in those two tabs were not pointing to the right path.)


    OK, that is very strange, right now I can't do much, but I'll investigate it more later on a Linux system :)

    EDIT: I can't actually find an MCP_LOC...
  • #7
    Excellent work, hope there is more soon, thanks! :D
  • #8
    Quote from OtakuD

    Excellent work, hope there is more soon, thanks! :D


    Sure thing :) Putting up a tutorial now
  • #9
    Tutorial 4:Items with metadata is now up, take a look :)
  • #10
    Tutorial 5: Adding shaped recipes, shapeless recipes and smelting has been added
  • #11
    I tested everything in tutorial 4 and 5 and it all works in game. Kudo for making a written tutorial that's easy to follow. :D

    Quote from DeverionX

    OK, that is very strange, right now I can't do much, but I'll investigate it more later on a Linux system :)

    EDIT: I can't actually find an MCP_LOC...

    Don't worry about it, it must have been an error on my part.

    Edit: I was wondering, I noticed that I was able to stack Sapphire, Amethyst and Topaz in the same pile. Is that because they share the same id number? and is it the downside with "Items with Metadata"?

    Also, what does "better compatibility" mean in "Metadata allows you to have multiple items/blocks in one ID, which allows for better compatibility"?

    I know but one freedom, and that is the freedom of the mind. - Antoine de Saint-Exupery
  • #12
    Quote from Apostolique

    I tested everything in tutorial 4 and 5 and it all works in game. Kudo for making a written tutorial that's easy to follow. :D


    Don't worry about it, it must have been an error on my part.

    Edit: I was wondering, I noticed that I was able to stack Sapphire, Amethyst and Topaz in the same pile. Is that because they share the same id number? and is it the downside with "Items with Metadata"?

    Also, what does "better compatibility" mean in "Metadata allows you to have multiple items/blocks in one ID, which allows for better compatibility"?


    The gems stacking is something I forgot to add in the tutorial, but I've put it in now, just add setHasSubtypes(true); in the constructor

    By better compatibility I mean that it will take up less ID's used by other mods, this isn't really such a big issue with items considering how many available item ID's there are, but it is a problem with the very limited number of block ID's (though forge does add 4096 block id fix, they still run out pretty quick) and also if you don't have a config file (tutorial coming soon :P )
  • #13
    Quote from DeverionX

    The gems stacking is something I forgot to add in the tutorial, but I've put it in now, just add setHasSubtypes(true); in the constructor


    That was fast! :Ham: And it works! :)

    I know but one freedom, and that is the freedom of the mind. - Antoine de Saint-Exupery
  • #14
    Quote from Apostolique

    That was fast! :Ham: And it works! :)


    :P No problem, I noticed a new email in my inbox and checked it out :)
  • #15
    Part 6: Your first block with Forge's infinite sprite indexes is now up, take a look :)
  • #16
    I noticed a typo in your latest tutorial ("Your first block with Forge's infinite sprite index"):

    There is an extra comma after the last "new" keyword:

    GameRegistry.addRecipe(new ItemStack(gemBlock,1), "ZXC","ZVC","ZXC", Character.valueOf('Z'), ruby, Character.valueOf('X'), new ItemStack(metaGem,1,1),Character.valueOf('C'), new ItemStack(metaGem,1,0), Character.valueOf('V'),new,ItemStack(metaGem,1,2));


    Otherwise, everything works well and I was able to craft the block.

    I know but one freedom, and that is the freedom of the mind. - Antoine de Saint-Exupery
  • #17
    Hey following your forge modding tutorials, looking great! Its great to see someone do a forge modding tutorial instead of just mod loader. 1 Question, for the meta-data tutorial, the instructions there are different than the source from tutorials 5 and 6 which have the same class's. There is no "Private string" line in the source's of tutorials 5 and 6 and a couple of other different things. Which should I follow the code from, the source from tutorials 5 and 6 or the tutorial itself, since the source from 5 and 6 is more recent than tutorial 4 i'm going to assume the source from the more recent tutorials is correct unless you reply to this.

    Thanks again,
    Brennan
  • #18
    Quote from Apostolique

    I noticed a typo in your latest tutorial ("Your first block with Forge's infinite sprite index"):

    There is an extra comma after the last "new" keyword:


    Otherwise, everything works well and I was able to craft the block.


    Oops, the forum was doing weird things with displaying the code and I accidentally messed it up, will fix now



    Hey following your forge modding tutorials, looking great! Its great to see someone do a forge modding tutorial instead of just mod loader. 1 Question, for the meta-data tutorial, the instructions there are different than the source from tutorials 5 and 6 which have the same class's. There is no "Private string" line in the source's of tutorials 5 and 6 and a couple of other different things. Which should I follow the code from, the source from tutorials 5 and 6 or the tutorial itself, since the source from 5 and 6 is more recent than tutorial 4 i'm going to assume the source from the more recent tutorials is correct unless you reply to this.

    Thanks again,
    Brennan


    It doesn't really matter which one you do, I'll take it out of the tutorial for consistency's sake, but it doesn't really matter, I just prefer the method that I've used in the 5+6 source code :)
  • #19
    Quote from DeverionX

    On another note, I'm hoping to have at least 2-3 tutorials out per day, so keep an eye on the thread


    this is god send, i can teach myself java and learn to mod minecraft at the same time, i'll be following your posts.
  • #20
    Please keep up these tuts! You help me a lot!
  • To post a comment, please or register a new account.
Posts Quoted:
Reply
Clear All Quotes