Wuppy’s Minecraft Forge Modding Tutorials for 1.6.2: Metadata Blocks

In this tutorial I’m going to show you how to add metadata to a block. This can be useful when you have a lot of blocks that are mostly the same, like ores, and you don’t want your mod to take up too many ids. To change a normal block into a metadata Block you will have to change the mod file, block file and also add a new file that handles the metadata for the Block. This is the mod file I will start with.


package tutorial;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = Tutorial.modid, name = “Mod Name”, version = “1.0”)
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class Tutorial
{
       public static final String modid = “YourName_ModName”;
      
       public static Block tutorialBlock;
      
       public static Item tutorialItem;
      
       @Init
       public void load(FMLInitializationEvent event)
       {
             tutorialBlock = new BlockTutorialBlock(500, Material.rock).setUnlocalizedName(“tutorialBlock”);
            
             GameRegistry.registerBlock(tutorialBlockmodid + tutorialBlock.getUnlocalizedName2());
            
             LanguageRegistry.addName(tutorialBlock“Tutorial Block”);
            
             tutorialItem = new ItemTutorial(5000).setUnlocalizedName(“tutorialItem”);
            
             LanguageRegistry.addName(tutorialItem“Tutorial Item”);
            
             TutorialCrafting.addRecipes();
       }
}

And this is the Block file.


package tutorial;

import net.minecraft.block.material.Material;
public class BlockTutorialBlock extends BlockGeneralTutorial
{
       public BlockTutorialBlock(int id, Material par2Material)
       {
             super(id, par2Material);
       }
}

So when you are going to add metadata to your Block there are some things you have to take care of. First of you will need to make different names for your blocks. Then you also need to get different textures for both, make them both show up in the menus and make sure the right metadata gets placed when you use the block.
We will start with different names for the metadatas. It’s very simple to do this. You have to replace the LanguageRegistry line with something like this.


LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 0), “Tutorial Block”);

LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 1), “Nether Tutorial Block”);

The code is pretty much the same, but instead of using the Block or Item you use an ItemStack. Then in the ItemStack you use the Block or Item you want with a stack size of 1 and then the metadata of the Block or Item. Even though you only set the name for a stack size of one it will work for every size.

Next up we are going to make sure that the block has different textures for each metadata.
To make different textures for metadata blocks you will have to add quite some new code. Normally you used the blockIcon variable in Block, but you can’t now since there are multiple Icons for the Block. To fix that you will have to make an Icon array. Also make sure that it is Client side only.
Since you now need multiple Icons you will also have to register multiple ones. That is why you will have to make the Icon[] the size of the amount of metadata blocks you are going to have. Then you need to make a for loop that cycles through the size of the Icon[] and registers the Icon. The code should look something like this.


@SideOnly(Side.CLIENT)

private Icon[] icons;
      
@SideOnly(Side.CLIENT)
public void registerIcons(IconRegister par1IconRegister)
{
       icons = new Icon[2];
            
       for(int i = 0; i < icons.length; i++)
       {
        icons[i] = par1IconRegister.registerIcon(Tutorial.modid “:” + (this.getUnlocalizedName().substring(5)) + i);
       }
}

So first you create a Client only icons variable. Then in the normal registerIcons method you set the Icons array to the amount of metadata blocks you will have. After that a simple for loop with int i that keeps going untill it is larger than the icon length. Then you set the icon at position i of the Icon array to the registered Icon. Most of the register code is the same except for that you have to add the i add the end. You need to do that to make sure you can use multiple images. The image for metadata 0 should be called: “unlocalizedname0″ then metadata 1 should be “unlocalizedname1″ etc.
Right now you have to set the right icon for the metadata. Do that with this method.


@SideOnly(Side.CLIENT)

public Icon getIcon(int par1, int par2)
{
       return icons[par2];
}

Now it will return the icon in the Icon arrray at the metadata value. This means that when you have a block of metadata 0 it will return the Icon at icons[0] which should be “unlocalizedname0″ for one it is the same, but with number 1 instead of 0.
If you were to start the game right now you will still only see 1 Block in the creative inventory. To fix this problem you will have to add this method to the Block file.


@SideOnly(Side.CLIENT)

public void getSubBlocks(int par1, CreativeTabs par2CreativeTabs, List par3List)
{
    for (int var4 = 0; var4 < 2; ++var4)
    {
        par3List.add(new ItemStack(par1, 1, var4));
    }
}

This method will add an ItemStack with the Block id, size 1 and metadata of var4 to the Creative tab list. Since var4 can be 0 and 1 it will add both of those metadatas to the Creative tab.
There is one last method you will have to add to the Block file to make sure that the metadata dropped is the metadata the block has. The method you need for that looks like this.


publicint damageDropped(int par1)
{
    return par1;
}

This simply gets the metadata of the block that is being dropped and will drop that metadata.
The Block file should now look like this.


package tutorial;
import java.util.List;
importnet.minecraft.block.Block;
importnet.minecraft.block.material.Material;
importnet.minecraft.client.renderer.texture.IconRegister;
importnet.minecraft.creativetab.CreativeTabs;
importnet.minecraft.item.ItemStack;
importnet.minecraft.util.Icon;
importcpw.mods.fml.relauncher.Side;
importcpw.mods.fml.relauncher.SideOnly;
publicclass BlockTutorialBlock extends Block
{
       public BlockTutorialBlock(int id, Material material)
       {
              super(id, material);
              this.setCreativeTab(CreativeTabs.tabBlock);
       }
      
       publicint damageDropped(int par1)
    {
        return par1;
    }
      
       @SideOnly(Side.CLIENT)
    private Icon[] icons;
  
    @SideOnly(Side.CLIENT)
    publicvoidregisterIcons(IconRegister par1IconRegister)
    {
        icons = new Icon[4];
        
        for(int i = 0; i < icons.length; i++)
        {
            icons[i] = par1IconRegister.registerIcon(Tutorial.modid + “:” + (this.getUnlocalizedName().substring(5)) + i);
        }
    }
  
    @SideOnly(Side.CLIENT)
    public Icon getIcon(int par1, int par2)
    {
        switch(par2)
        {
            case 0:
              returnicons[0];
            case 1:
            {
              switch(par1)
                {
                     case 0:
                           returnicons[1];
                    case 1:
                        returnicons[2];
                    default:
                        returnicons[3];
                }
            }
            default:
            {
              System.out.println(“Invalid metadata for “ + this.getUnlocalizedName());
                returnicons[0];
            }
        }
    }
  
    @SideOnly(Side.CLIENT)
    publicvoid getSubBlocks(int par1, CreativeTabs par2CreativeTabs, List par3List)
    {
          for(int i = 0; i < 2; i++)
          {
                 par3List.add(new ItemStack(par1, 1, i));
          }
    }
}

So right now you may think you have taken care of everything. However, there is still one very big problem. When you place metadata 1 of the Block it will actually still use metadata 0. To fix that you will have to make a small change to the mod file and add a new file. The method you have to change is the registerBlock method. Once changed it should look like this.


GameRegistry.registerBlock(tutorialBlock, ItemTutorialBlock.classmodid + (tutorialBlock.getUnlocalizedName().substring(5)));


As you can see there is one new parameter in this method. It is the ItemTutorialBlock.class. The mod file should now look something like this.


package tutorial;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = Tutorial.modid, name = “Mod Name”, version = “1.0”)
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class Tutorial
{
       public static final String modid = “YourName_ModName”;
      
       public static Block tutorialBlock;
      
       public static Item tutorialItem;
      
       @Init
       public void load(FMLInitializationEvent event)
       {
             tutorialBlock = new BlockTutorialBlock(500, Material.rock).setUnlocalizedName(“tutorialBlock”);
            
             GameRegistry.registerBlock(tutorialBlock, ItemTutorialBlock.classmodid + (tutorialBlock.getUnlocalizedName().substring(5)));
            
             LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 0), “Tutorial Block”);
             LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 1), “Nether Tutorial Block”);
            
             tutorialItem = new ItemTutorial(5000).setUnlocalizedName(“tutorialItem”);
            
             LanguageRegistry.addName(tutorialItem“Tutorial Item”);
            
             TutorialCrafting.addRecipes();
       }
}

When you add this to your code you will get an error under that, because you haven’t made the file yet. To do that hover your mouse over it and create the class. Now make sure the file extends ItemBlock.
The file should look something like this.


package tutorial;

import net.minecraft.item.ItemBlock;
public class ItemTutorialBlock extends ItemBlock
{
}

When you have this you will get an error under ItemTutorialBlock which tells you to add a constructor.
Let Eclipse make the constructor by hovering over it and selecting the add constructor option. Now in there you will have to add one line after the super(par1); which is setHasSubtypes(true); This will make sure that it can have multiple metadata values.
As you may know Minecraft will start screwing up when there are 2 Items or Blocks with the same Unlocalized name. That is why you should add a method like this to the Item file.


public String getUnlocalizedName(ItemStack itemstack)

{
       String name = “”;
       switch(itemstack.getItemDamage())
       {
             case 0:
             {
                    name = “world”;
                    break;
             }
             case 1:
             {
                    name = “nether”;
                    break;
             }
             default: name = “broken”;
       }
       return getUnlocalizedName() + “.” + name;
}

If the metadata is 0 it will add world behind the unlocalized name. For metadata it is nether. If for some reason the metadata is above 1 it will just add broken making sure it doesn’t crash.
So now you have taken care of pretty much everything for your metadata Block. There is just one last method you will have to add which has to be exactly the same as this one.


public int getMetadata(int par1)

{
      return par1;
}

The whole ItemTutorialBlock file should now look like this.


package tutorial;

import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
public class ItemTutorialBlock extends ItemBlock
{
       public ItemTutorialBlock(int par1)
       {
             super(par1);
             setHasSubtypes(true);
       }
      
       public String getUnlocalizedName(ItemStack itemstack)
       {
             String name = “”;
             switch(itemstack.getItemDamage())
             {
                    case 0:
                    {
                           name = “world”;
                           break;
                    }
                    case 1:
                    {
                           name = “nether”;
                           break;
                    }
                    default: name = “broken”;
             }
             return getUnlocalizedName() + “.” + name;
       }
      
       public int getMetadata(int par1)
       {
             return par1;
       }
}

Now you have a fully working metadata Block in your mod. In the next tutorial I will show you sided textures.

You can download the source code and the assets folder over here.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">