Basic Modding - Metadata

Goal

I want to show you how to create blocks and items that use the metadata.

Difficulty

3/10 - Relatively Easy

Prerequisites

Forge Version

This Tutorial was created with Forge 10.13.0.1180 for Minecraft 1.7.10. If anything doesn't work with other versions, please contact me!


Metadata for Blocks

How does Minecraft work - Metadata:
Blocks with metadata:
The metadata of a block is a number between 0 and 15 which is stored along with the block when the world is saved. With this metadata you can either give a block several different types (like the different colours of wool) or you can store for example the rotation of the block (like with stairs or pistons).
You should give a block subtypes if you want to create some blocks which are basically the same but with some small differences (like the colour of the wool).

Items with metadata:
The metadata of an item is stored in the itemstack's damage value which is normally used to store the durability of tools. Because metaItems use this value they cannot have a damage value, so you can't make pickaxes (which are damageable) with metadata. The metadata of items is not restricted to 16 numbers, instead it can be any number from -32768 to 32767.

So how do we create blocks with metadata?

Basically its just a normal block, so we start with a normal block class:

MetaBlock.class:
package com.bedrockminer.tutorial.block;

import [...];

public class MetaBlock extends Block { 

    protected MetaBlock(String unlocalizedName, Material material) {
        super(material);
        this.setBlockName(unlocalizedName);
        this.setCreativeTab(CreativeTabs.tabBlock);
        this.setHardness(2.0F);
        this.setResistance(6.0F);
        this.setStepSound(soundTypeGravel);
    }

    @Override
    public void registerBlockIcons(IIconRegister reg) { }
}

I do not set the texture name, because I want to use the same textures as the multi textured block from the last tutorial. For the same reason I override the registerBlockIcons() method so that it does nothing.

 

Now, our block needs to return the right texture for the right metadata. Therefore, we override the method getIcon(int side, int meta);.

MetaBlock.class:
@Override
public IIcon getIcon(int side, int meta) {
    if (meta > 5)
        meta = 0;

    return ModBlocks.multitexture.getIcon(meta, 0);
}

I only want to create six different textures for the metadata 0 to 5. To ensure that minecraft doesn't crash if anyone places the block with another metadata (maybe via the /setblock command), I added an if-structure which sets the passed value to 0 if it was higher than 5. After that, the method can access the getIcon() method of our multitexture block and use the metadata of this block as the passed side for the multitexture block.

 

The next thing to do is to override the method damageDropped(int oldMeta). This method is called when the block gets destroyed. It returns the metadata of the dropped item based on the old metadata of the block. Normally it just returns 0 so we need to change it in order to return the old metadata without modifying the value:

MetaBlock.class:
@Override
public int damageDropped(int meta) {
    return meta;
}

Now if we looked for our block in the creativeTab (it would be not there because its not registered) there would only be one type of the block: the one with the metadata of zero. To change this we need to override getSubBlocks(Item item, CreativeTabs tab, List list);. In this method we need to add all different types of our block as ItemStacks of the passed item to the list. If you have multiple types you should use a for-loop:

MetaBlock.class:
@Override
public void getSubBlocks(Item item, CreativeTabs tab, List list) {
    for (int i = 0; i < 6; i ++) {
        list.add(new ItemStack(item, 1, i));
    }
}

Now our block class is finished. But if we placed our block in the world it would always have metadata 0, no matter which Item we choose. Also, all the different Items have the same name.

Therefore we need to define an item for our block which supports, unlike the default item, different metadata values for the block. To do this, we create a new class called "ItemBlockMetaBlock". This class should extend "ItemBlockWithMetadata". This does everything for us, we just need to add a constructor.

ItemBlockMetaBlock.class:
package com.bedrockminer.tutorial.block.itemblock;

import [...];

public class ItemBlockMetaBlock extends ItemBlockWithMetadata {

        public ItemBlockMetaBlock(Block block) {
                super(block, block);
        }
}

Please ensure that the constructor you create only has one argument (Block) otherwise the game will crash on startup.

 

If we now register our block we have a fully functional metadata block, but still the different types of the block have the same name. To change this we override the method getUnlocalizedName(ItemStack stack); in the ItemBlockMetaBlock class. Inside this method we create a switch statement. We use stack.getItemDamage() as the argument to check for. Then we can add several case-arguments which return the unlocalizedName of the block followed by a metadata specific postfix.

The best way is the following, because with this code you can use the ItemBlock for every metadata Block you need.

return getUnlocalizedName() + "_" + metadata;

ItemBlockMetaBlock.class:
@Override
public String getUnlocalizedName(ItemStack stack) {
    return this.getUnlocalizedName() + "_" + stack.getItemDamage();
}

Now our block with metadata is finished. We now need to register it together with the ItemBlockMetaBlock class:

ModBlocks.class:
GameRegistry.registerBlock(metablock = new MetaBlock("metablock", Material.cloth), ItemBlockMetaBlock.class, "metablock");

If we now run Minecraft and go to the "Blocks" tab in creative mode, we see six different blocks with the textures of the multitexture block. We can place them and break them and we will always get the right Item.

 

Here is a possible language file for the metablock:

en_US.lang:
tile.metablock_0.name=Metablock 0 (White)
tile.metablock_1.name=Metablock 1 (Black)
tile.metablock_2.name=Metablock 2 (Red)
tile.metablock_3.name=Metablock 3 (Green)
tile.metablock_4.name=Metablock 4 (Yellow)
tile.metablock_5.name=Metablock 5 (Blue)

Metadata for Items

Creating items which use metadata is nearly the same as we did before with blocks, except that everything is in one class.

I want to create an item with six subtypes which use the textures of the multitexture block.

First we create the item class:

MetaItem.class:
package com.bedrockminer.tutorial.item;

import [...];

public class MetaItem extends Item {

        public MetaItem(String unlocalizedName) {
                super();
                this.setHasSubtypes(true);
                this.setUnlocalizedName(unlocalizedName);
                this.setCreativeTab(CreativeTabs.tabMaterials);
        }
}

The setHasSubtypes method is used to tell Minecraft that Items with different metadata may not be stacked. For Blocks it is not needed because it's included in the ItemBlockWithMetadata class.


One important thing is that an Item can not automatically use textures a block uses, so we have to copy the texture filed multitexture_0.png to multitexture_5.png from the assets/textures/blocks to the assets/textures/items folder. Once we have done this, the item can register its icons:

MetaItem.class:
public IIcon[] icons = new IIcon[6];

//...

@Override
public void registerIcons(IIconRegister reg) {
    for (int i = 0; i < 6; i ++) {
        this.icons[i] = reg.registerIcon(Main.MODID + ":multitexture_" + i);
    }
}

The other things we need to do are exactly the same as we did with the block, so I'll just write the code here.

The only difference now is, that the item doesn't use getIcon(side, meta); but getIconFromDamage(meta); and not getSubBlocks(...) but getSubItems(...).

MetaItem.class:
@Override
public IIcon getIconFromDamage(int meta) {
    if (meta > 5)
        meta = 0;

    return this.icons[meta];
}

@Override
public void getSubItems(Item item, CreativeTabs tab, List list) {
    for (int i = 0; i < 6; i ++) {
        list.add(new ItemStack(item, 1, i));
    }
}

@Override
public String getUnlocalizedName(ItemStack stack) {
    return this.getUnlocalizedName() + "_" + stack.getItemDamage();
}

To register the Item you have to write this into the init method of the ModItems class:

ModItems.class:
GameRegistry.registerItem(metaitem = new MetaItem("metaitem"), "metaitem");

We now created both block and item which use the metadata.

Picture - Show

This is an example language file for the metaItem we created:

en_US.lang:
item.metaitem_0.name=Metaitem 0 (White)
item.metaitem_1.name=Metaitem 1 (Black)
item.metaitem_2.name=Metaitem 2 (Red)
item.metaitem_3.name=Metaitem 3 (Green)
item.metaitem_4.name=Metaitem 4 (Yellow)
item.metaitem_5.name=Metaitem 5 (Blue)

Usage of metadata items/blocks

So, how do we use these items or blocks for example in crafting recipes? If we just write a reference to the item in the recipe, it works for all items of this type, no matter what their metadata is. If we want to have a metadata specific recipe, we need to create an ItemStack and use this instead of the item itself.

 

An example can be the usage of ink sacs in crafting recipes. An ink sac is, like laips lazuli, bonemeal or cocoa beans, based on the item Items.dye. If we want to create a recipe to craft a coal block out of an ink sac, we need to use an ItemStack instead of the item:

Crafting Recipe.class:
GameRegistry.addShapelessRecipe(new ItemStack(Blocks.coal_block), new Object[]{new ItemStack(Items.dye, 1, 0)});

The ItemStack has three arguments: first the Item, then the count of this item (in crafting recipes this should always be 1) and finally the metadata (0 for an ink sac).

 

If you don't know which metadata you need, take a look at the corresponding article of the Minecraft wiki.


As always, you can download the code used in this tutorial as a .zip file from here.


Recommended tutorials to continue with

Take a look at the tutorial overview and find out what you want to do next!


Comments and Questions:

If you want to report modding problems, please make sure to include the code in a pastebin link or something else! Don't just write "It doesn't work", otherwise your post will be deleted. For more complicated problems, please use the troubleshooter form.