Creating a custom item in Minecraft is very easy, if a little picky on the requirements. However, if all of these simple requirements are met then we will have a custom item to use!
First, let's add the few lines of code needed to register our item with the game. Granted, we haven't even made our item yet, but we'll just go ahead and add it for now. We will do this within the preInit
event handler, instead of just init
.
Either create a new mod file, or use the one from the previous example. Add the following code below the property definitions, but before the init
method:
public static final Item key;
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
key = new ItemKey();
GameRegistry.registerItem(key, "Key");
}
Now, we have to make our actual item's class, which we'll spend a majority of the remaining example within. The most basic item possible is shown below, and will serve as a template for all of our custom items:
package edu.govschool.minecraft.example.items;
import net.minecraft.item.Item;
public class ItemKey extends Item
{
private static final String name = "key";
public ItemKey()
{
}
}
Now, we've gotten rid of all of the errors in Eclipse, but if we were to try to play the game we wouldn't be able to find our item! That is because we haven't set its unlocalized name. This name is the name of the item before it has been translated for the interface language picked by the player. Each item in the game, mods and all, need custom unlocalized name. Additionally, we need to set the tab that the item will appear in during Creative Mode, so we can find it! Therefore, we can utilize the following code snippet to do both of these objectives:
setUnlocalizedName(ItemsExample.MODID + "_" + name);
setCreativeTab(CreativeTabs.tabMisc);
Now, if we fire up the game and grab an instance of our new item, we see that it does work, but the texture is purple and black squares and the item's name is something like item.mrdavis_items_key.name
. The reason for this is that we have not specified the texture, nor localised our mod at all! This includes English, we cannot assume that the default name will work. Therefore, we need to both localise our mod and add textures.
Within the src/main/resources
folder within Eclipse, you need to create an assets
folder (NOT package!!). Within this, a folder named with your Mod ID (in this example, mrdavis_items
). Next, you need two folders within the Mod ID folder, one called lang
, and the other called textures
. Finally, within the textures
folder make a folder called items
. We now have the entire directory structure needed for our mod to be localized and have textured items.
Make a new file called en_US.lang
within the assets/mod_id/lang
folder you just created. This file will contain the localisations for our mod, when the user has chosen US English as the game language. In this file, paste the following line, changing the Mod ID as necessary:
item.mrdavis_items_key.name=Key
This will set the localised name of our new item for US English. If we wanted to localise our mod for other languages as well, we could simply create different lang
files with the correct language and country code. For example, German localisation would be in a file called de_DE.lang
and contain:
item.mrdavis_items_key.name=Schlüssel
'Schlüssel' is the German word for key, so we use it here. Now, if any Germans use our mod, the key object will be correctly localised!
Now, we need to add a texture for our item. As long as we provide a 16x16px png
image with transparency, the Minecraft engine will create the object model automatically for us! I have provided an image to use here.
Right-click the assets/mod_id/textures/items
folder and select Show In > System Explorer. This will open the folder in the default file explorer, so copy the key image to this folder. Add the following line to the constructor of your new item:
setTextureName(ItemsExample.MODID + ":greyKey");
Now, launch the game and you'll be able to spawn your item! It doesn't do much, but it's there!
package edu.govschool.pm.minecraft;
import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid=ItemsExample.MODID, version=ItemsExample.VERSION)
public class ItemsExample {
public static final String MODID = "mrdavis_items";
public static final String VERSION = "1.0";
// Property to hold our custom item
public static Item key;
@EventHandler
public void preInit(FMLPreInitializationEvent e)
{
// Create our custom item
key = new ItemKey();
// Register (or add) our item with the game
GameRegistry.registerItem(key, "Key");
}
@EventHandler
public void init(FMLInitializationEvent e)
{
}
}
package edu.govschool.pm.minecraft;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
public class ItemKey extends Item
{
// The internal name of our item
public static final String name = "key";
public ItemKey()
{
// Set the unlocalised name
// [modid]_key
setUnlocalizedName(ItemsExample.MODID + "_" + name);
// Set the tab in creative mode where our item will be
// found
setCreativeTab(CreativeTabs.tabMisc);
// Set the name of the texture file
// [modid]/textures/items/greyKey.png -> [modid]:greyKey
setTextureName(ItemsExample.MODID + ":greyKey");
}
}
Let's refactor this item slightly, so we can have different colored keys! With our code now, we basically hardcode the information for our grey key. Let's update the ItemKey
class slightly:
package edu.govschool.pm.minecraft;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
public class ItemKey extends Item
{
public ItemKey(String name)
{
setUnlocalizedName(ItemsExample.MODID + "_" + name);
setCreativeTab(CreativeTabs.tabMisc);
setTextureName(ItemsExample.MODID + ":" + name);
}
}
Since we've changed the constructor code, we'll need to update the ItemsExample
class pre-initializer where we register our item. While we're here, we'll also add the code for a red key:
// public static Item key;
public static Item greyKey;
public static Item redKey;
@EventHandler
public void preInit(FMLPreInitializationEvent e)
{
// key = new ItemKey();
greyKey = new ItemKey("greyKey");
redKey = new ItemKey("redKey");
// GameRegistry.registerItem(key, "Key");
GameRegistry.registerItem(greyKey, "greyKey");
GameRegistry.registerItem(redKey, "redKey");
}
Next, we need to update our localisation file:
item.mrdavis_items_greyKey.name=Grey Key
item.mrdavis_items_redKey.name=Red Key
Lastly, we need a texture for our red key. We can use a texture that's red-tinted
Make sure to save it in the src/main/resources/assets/[modid]/textures/items
directory, and launch the game to see your new items!
package edu.govschool.pm.minecraft;
import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid=ItemsExample.MODID, version=ItemsExample.VERSION)
public class ItemsExample {
public static final String MODID = "mrdavis_items";
public static final String VERSION = "1.0";
// Properties to hold our custom items
public static Item greyKey;
public static Item redKey;
@EventHandler
public void preInit(FMLPreInitializationEvent e)
{
// Create our custom items
greyKey = new ItemKey("greyKey");
redKey = new ItemKey("redKey");
// Register our items
GameRegistry.registerItem(greyKey, "greyKey");
GameRegistry.registerItem(redKey, "redKey");
}
@EventHandler
public void init(FMLInitializationEvent e)
{
}
}
package edu.govschool.pm.minecraft;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
public class ItemKey extends Item
{
public ItemKey(String name)
{
// Set the unlocalised name
setUnlocalizedName(ItemsExample.MODID + "_" + name);
// Set the tab in creative mode where our item will be
// found
setCreativeTab(CreativeTabs.tabMisc);
// Set the name of the texture file
// [modid]/textures/items/greyKey.png -> [modid]:greyKey
setTextureName(ItemsExample.MODID + ":" + name);
}
}
This, however, is not the best way of creating items that are essentially the same item, but with different types. Dyed wool in the vanilla game is another example of an item with several types, being each color. We can achieve the same effect with our key item by adding metadata to the item.
In Minecraft, every item when registered is assigned an Item ID, which is used by the game engine to keep track of items. In addition to this ID, which is an integer, we can store another integer as metadata to store subtypes of an item. So, if our item had the Item ID 1234, we could store our greyKey as 1234:0 and the red key as 1234:1, and only use one Item ID! This is a practice that should be utilised as much as possible, so that we don't hit Minecraft's limit of items.
We need to update the constructor of our ItemKey
slightly:
public ItemKey()
{
setUnlocalizedName(ItemsExample.MODID + "_key");
// This will allow us to have metadata
setHasSubtypes(true);
setCreativeTab(CreativeTabs.tabMisc);
}
Notice we call setUnlocalizedName(String)
, so each type of our item will have the same name! We need to change this, by overridding the implementation provided by Item
(our superclass). We're also going to add a String
array property containing the names of each of our separate types. Add this overridden method to the ItemKey
class:
private String[] name = {"grey", "red"};
@Override
public String getUnlocalizedName(ItemStack item)
{
int metadata = MathHelper.clamp_int(item.getItemDamage(), 0, 15);
return super.getUnlocalizedName() + "." + name[metadata];
}
So, what is this method doing? This method will be called by the game engine whenever it needs the name of an ItemKey
. The first thing we get is the metadata on the item, which in the early versions of Minecraft was only used for damage on items. We use the MathHelper
class provided by Minecraft to limit the number to between 0 and 15. Finally, we return our custom unlocalised name in the following format:
[modid]_key.[color]
Note: The call to super.getUnlocalizedName()
will return the name we set in the constructor, namely (puns!) mrdavis_items_key
in this case.
Now, each of our colors of keys will have a custom name! Cool, eh? We still need to fix the textures, however, and this requires a bit more work. We have to manually tell Minecraft what textures correspond to each sub-item. This only requires one property and a new method:
@SideOnly(Side.CLIENT)
private IIcon[] icons;
@SideOnly(Side.CLIENT)
@Override
public void registerIcons(IIconRegister reg)
{
// One icon for each sub-item
icons = new IIcon[name.length];
for (int i = 0; i < icons.length; i++) {
// Register the icon with the game. We can use
// the same convention as manually setting the
// texture of the item
icons[i] = reg.registerIcon(ItemsExample.MODID +
":" + name[i] + "Key");
}
}
We need two more methods to finish setting our textures. We have to dynamically get the texture based on the metadata of the object (e.g., grey Keys need the grey texture), and also put each sub-item in the Creative mode menu:
// Get the texture based on the metadata of
// the item
@Override
public IIcon getIconFromDamage(int meta)
{
return icons[meta];
}
// This method will add each sub-item to the Creative mode
// menu. We iterate using the length of the name array as our
// bounds, so we only add as many items as we have.
//
// The SuppressWarnings annotation is for our sanity, since
// Minecraft doesn't always do the safest thing according to
// the JVM
@SuppressWarnings({ "unchecked", "rawtypes" })
@SideOnly(Side.CLIENT)
@Override
public void getSubItems(Item item, CreativeTabs tabs, List list)
{
for (int i = 0; i < name.length; i++) {
list.add(new ItemStack(this, 1, i));
}
}
Lastly, we need to slightly edit the localisation file to use our new unlocalised names, and we'll be finished:
item.mrdavis_betteritems_key.grey.name=Grey Key
item.mrdavis_betteritems_key.red.name=Red Key
Ok, I lied, we need to do one LAST thing. We have to update our ItemsExample
class to the original listing, since all of the initialization is done by ItemKey
itself.
public static Item key;
@EventHandler
public void preInit(FMLPreInitializationEvent e)
{
key = new ItemKey();
GameRegistry.registerItem(key, "Key");
}
package edu.govschool.minecraft.betteritems;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.item.Item;
@Mod(modid = ItemsExample.MODID, version = ItemsExample.VERSION)
public class ItemsExample
{
public static final String MODID = "mrdavis_items";
public static final String VERSION = "1.0";
// Property to hold our custom item
public static Item key;
// Register our custom item with the game
@EventHandler
public void preInit(FMLPreInitializationEvent e)
{
key = new ItemKey();
GameRegistry.registerItem(key, "Key");
}
@EventHandler
public void init(FMLInitializationEvent e)
{
}
}
package edu.govschool.minecraft.betteritems;
import java.util.List;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
public class ItemKey extends Item
{
private String[] name = {"grey", "red"};
// Property to hold our textures
// The SideOnly annotation ensure this code will only
// be run on the client, since the server doesn't have
// an IIcon class
@SideOnly(Side.CLIENT)
private IIcon[] icons;
public ItemKey()
{
// Set a base unlocalised name
setUnlocalizedName(ItemsExample.MODID + "_key");
// Turn on our metadata
setHasSubtypes(true);
// Set the tab for creative mode
setCreativeTab(CreativeTabs.tabMisc);
}
@Override
public String getUnlocalizedName(ItemStack par1ItemStack)
{
// Get the metadata on our item, bounded to 0-15
int metadata = MathHelper.clamp_int(par1ItemStack.getItemDamage(), 0, 15);
// Return the custom unlocalised name in the format:
// [modid]_key.[color]
return super.getUnlocalizedName() + "." + name[metadata];
}
@SideOnly(Side.CLIENT)
@Override
public void registerIcons(IIconRegister reg)
{
// One icon for each sub-item
icons = new IIcon[name.length];
for (int i = 0; i < icons.length; i++) {
// Register the icon with the game. We can use
// the same convention as manually setting the
// texture of the item
icons[i] = reg.registerIcon(ItemsExample.MODID +
":" + name[i] + "Key");
}
}
// Get the texture based on the metadata of
// the item
@Override
public IIcon getIconFromDamage(int par1)
{
return icons[par1];
}
// This method will add each sub-item to the Creative mode
// menu. We iterate using the length of the name array as our
// bounds, so we only add as many items as we have.
//
// The SuppressWarnings annotation is for our sanity, since
// Minecraft doesn't always do the safest thing according to
// the JVM
@SuppressWarnings({ "unchecked", "rawtypes" })
@SideOnly(Side.CLIENT)
@Override
public void getSubItems(Item par1, CreativeTabs par2CreativeTabs, List par3List)
{
for (int i = 0; i < name.length; i++) {
par3List.add(new ItemStack(this, 1, i));
}
}
}