Minecraft Forge: Tips On Modding Items

Introduction



Items have changed a lot in 1.8 with respect to models and textures, as well as some changed method names.

Armor and weapons are commonly modded, so I have created additional pages of tips for those types of item:


But before you check out the armor and weapons, make sure you read all the item tips below because they will also apply!

Items In The Game Are Really ItemStack Instances


Java is an object-oriented language, so you need to pay attention to how instances of a class are used. In Minecraft, there is only one main instance for each item -- even if there was 50 iron ores in your inventory, there is still only one ore item instance. Instead, the fact that there are 50 iron ores is handled by another class called ItemStack. So if you have one item, you have an ItemStack with quantity one.

Key Point: In most cases you process items, you will need to handle the ItemStack instance.


Items On The Ground Are Really EntityItem Instances


Because an item on the ground needs to "do things", like keep track of how long its been since it was tossed, or rendering, they are actually a type of entity called EntityItem. The EntityItem class extends the Entity class, and so you can modify its behavior by @Override of the onUpdate() method.

Key Point: However, if you want to make a special behavior for your item when tossed, you need to understand that the vanilla EntityItem class is generic and associated with ItemStack directly. In other words there is not a separate class for every type of item, but rather the EntityItem has a field containing the ItemStack.

That means that the vanilla EntityItem class isn't directly useful if you want to make special behavior -- for that you should create your own custom class that extends EntityItem and in your custom Item class you should @Override the createEntity() method to return your custom EntityItem.

Key Point: The EntityItem instance is created by the createEntity() method of the associated item class.

Note: If you look at the code for how items are dropped, you'll see that an instance of EntityItem is created at the time of the drop (like in the dropFewItems() method). You'd be tempted to believe that this means that the createEntity() method isn't called (because the EntityItem is already created). However, I guess they realized that they needed to vector all entity items through the associated Item class to better control behavior. So as soon as a dropped EntityItem joins the world, it is immediately replaced with the value returned by the item's createEntity() method.

Converting Items From 1.7.x to 1.8



I have some tips for converting in my Tips For Converting From 1.7.x To 1.8 Tutorial.

Get A List Of All Items In The Game


You can get a list of all items using:
List<Item> list = ImmutableList.copyOf(Item.itemRegistry);

How To Detect If Item Is Being Held By Player


If it is your own custom item, you probably are writing code for the onUpdate() method. In that method, the last parameter is a boolean that represents whether the item is in the player's hands.

If you're writing code to detect whether a vanilla item is held, then you can use EntityPlayer#getCurrentEquippedItem().

Changing A Player Attribute Based On Held Item


Thanks to CoolAlias for this tip.

Attributes are things like max health, attack damage, knock-back resistance and are used on most entities in the game, including players. These are embodied with the SharedMonsterAttributes class.

If you want to modify an attribute based on equipped / held items, then Item#getAttributeModifiers is the method you want. By @Override that method you can return a multimap with as many attribute modifiers as you want, and they will be applied and removed accordingly.

ItemSword provides an example that increases the player's attack damage, but it is easy to modify to apply it to other attributes like max health instead.

If you want to modify something other than an existing attribute, then you should instead handle the LivingUpdateEvent and check for the equipped weapon as explained in the section "How To Detect If Item Is Being Held By Player" above.

Changing The 3D Model Of An Item Based On Property Values


There is now an ability to "override" the item model by using the IPropertyGetter interface system. This is how items like ItemCompass work. I explain this system in detail on my model tips page.

Giving Different Texture Or Colors To Item Subtypes


Thanks to Choonster for this tip.

You may want several variations of an item and want to render them with different texture colors. You can do this as follows.

If all that changes is the color of the contents, use a model that extends builtin/generated (e.g. item/generated or item/handheld) with the unchanging texture as one layer and second white texture for areas you will want to change color.

To color the contents at runtime, you need to create an implementation of IItemColor and register it for your Item by calling ItemColors#registerItemColorHandler on Minecraft#getItemColors in init.

IItemColor#getColorFromItemstack gives you the ItemStack and the tint index, which tells you the part of the model that's being coloured. For models that extend builtin/generated, the tint index is the layer index (e.g. "layer0" is tint index 0). For the layer you want to change color, return the color in 0xRRGGBB format and for the unchanging layer return -1 (white).

If the contents actually have separate textures, you'll need to generate the textures and model at runtime. See ModelDynBucket for an example of this.

Adding NBT Data To Items


Most modders are aware that items have a "damage value" that can act as metadata. For example, different color wool would have different metadata values. The problem with metadata though is that it is only 4 bits of information so is limited to 16 possible values. The good news is that you can actually attach NBT data to an ItemStack.

Thanks to Epoxide for this tip!

An Item on its own is a singleton so there is ever only one instance of each Item, and the fields it contains. This is why if you were to have a method in your item that would change the field value, it will change that variable for all items in the world/game.

Luckily, Minecraft has a wrapper object which holds basic information about items, they are called ItemStack's. By default an ItemStack only keeps track of itemID, stack size, and meta data, however you can write additional data to the ItemStack, this is how Minecraft handled enchantments, item renames, and color values on leather armor, or on fire works.

Here is an example (from Expoxide) which shows different ItemStacks being created and added to the creative tab. The items will each have different variables for the "brain type", and the example will also show how to read that variable, by changing item name based on it, and the example will show how to write variables, by adding multiple instances of the item to the creative tab, each with a unique value. The example also is showing unique tooltip descriptions and showing how to do your own language translations.

public class ItemTestBrain extends Item 
{
    // This is an array of all the types I am going to be adding.
    String[] brainTypes = { "dead", "preserved", "fresh", "tasty" };

    // This method allows us to have different language translation keys for 
    // each item we add.
    @Override
    public String getUnlocalizedName(ItemStack stack) 
    {
        // This makes sure that the stack has a tag compound. This is how data 
        // is stored on items.
        if (stack.hasTagCompound()) 
        {
            // This is the object holding all of the item data.
            NBTTagCompound itemData = stack.getTagCompound();
            // This checks to see if the item has data stored under the 
            // brainType key.
            if (itemData.hasKey("brainType"))
            {
                // This retrieves data from the brainType key and uses it in
                // the return value
                return "item." + itemData.getString("brainType");
            }
        }
        // This will be used if the item is obtained without nbt data on it.
        return "item.nullBrain";
     }

    // This is a fun method which allows us to run some code when our item is
    // shown in a creative tab. I am going to use it to add all the brain 
    // types.
    @SideOnly(Side.CLIENT)
    public void getSubItems(Item item, CreativeTabs tab, List itemList) 
    {
        // This creates a loop with a counter. It will go through once for
        // every listing in brainTypes,  and gives us a number associated 
        // with each listing.
        for (int pos = 0; pos < brainTypes.length; pos++) 
        {
            // This creates a new ItemStack instance. The item parameter 
            // supplied is this item.
            ItemStack brainStack = new ItemStack(item);
            // By default, a new ItemStack does not have any nbt compound data. 
            // We need to give it some.
            brainStack.setTagCompound(new NBTTagCompound());
            // Now we set the type of the item, brainType is the key, and 
            // brainTypes[pos] is grabbing a
            // entry from the brainTypes array.
            brainStack.getTagCompound().setString("brainType", 
                  brainTypes[pos]);
            // And this adds it to the itemList, which is a list of all items
            // in the creative tab.
            itemList.add(brainStack);
        }
    }
 
    // This code will allow us to tell the items apart in game. You can change 
    // texture based on nbt data, but I won't be covering that.
    @SideOnly(Side.CLIENT)
    public void addInformation(ItemStack stack, EntityPlayer player, 
          List tooltip, boolean isAdvanced) 
    {
        if ( stack.hasTagCompound() 
              && stack.getTagCompound().hasKey("brainType"))
        {
            // StatCollector is a class which allows us to handle string
            // language translation. This requires that you fill out the
            // translation in you language class.
            tooltip.add(StatCollector.translateToLocal("tooltip.yourmod." 
                  + stack.getTagCompound().getString("brainType") + ".desc"));
        }
        else // If the brain does not have valid tag data, a default message
        {
          tooltip.add(StatCollector.translateToLocal(
                  "tooltip.yourmod.nullbrain.desc"));
        }
    }
}

Key Point: You can access the NBT compound data from the Item class (in those methods that pass an ItemStack), but the NBT compound can only be set on an ItemStack.

The steps to add NBT data to an ItemStack:

  1. Create or otherwise get an ItemStack of the desired item
  2. Create an NBTTagCompound and fill it with the appropriate data
  3. Call ItemStack#setTagCompound() method to set it.

Setting Up Item Models And Textures



This topic is already well covered by other tutorials. Check out TheGreyGhost's Item Rendering Tutorial.

Getting And Drawing Texture Of An Item


Thanks to larsgerrits for this information.

Warning: This is only for 1.7.10.  I haven't figured out what the equivalent for 1.8 is yet.

You may want to draw the texture of an Item in a custom GuiScreen.  Items don't have directly have a ResourceLocation for their texture. Instead, they have an IIcon object which holds the UV-coordinates of the texture on a giant image which holds all the Item textures.  The ResourceLocation is located at TextureMap.locationItemsTexture. If you want to use this in a GUI, you have to get the IIcon of the Item first, bind the TextureMap.locationItemsTexture, and then call the drawTexturedModelRectFromIcon() method to draw the IIcon of the item.

Adding Color To An Item Name


Thanks to Hugo_the_Dwarf for this tip.

For most text, like chat or display names, there is a class called EnumChatFormatting that has several build in color codes that can be added to strings.

In the case of item names, you just need to @Overrride the getItemStackDisplayName() method to include a color.  You can of course do fancier formatting or parsing of the string if desired.


@Override
public String getItemStackDisplayName(ItemStack par1ItemStack) 
{
    String size = UtilityNBTHelper.getString(par1ItemStack,
          UtilityWeaponNBTKeyNames.size);
    if ((size == "normal") || (size == "")) 
    {
        return ("" + StatCollector.translateToLocal(this
              .getUnlocalizedNameInefficiently(par1ItemStack) + ".name"))
              .trim();
  
    } 
    else 
    {
        return (size.substring(0, 1).toUpperCase()+size.substring(1)
              +EnumChatFormatting.RED 
              +" "
              +StatCollector.translateToLocal(getUnlocalizedNameInefficiently(
                    par1ItemStack)
              +".name")).trim();
    }
}

Subtypes On The Creative Tab


If you want your your custom item to show up on a creative tab you need to check that the getSubItems() method is appropriate.  If your class directly extends Item, you'll need to @Override the getSubItems() method otherwise (regardless of whether you setHasSubTypes() to true or false) 16 of the item will appear in the creative tab.  Code like this works:

@Override
@SideOnly(Side.CLIENT)
public void getSubItems(Item parItem, CreativeTabs parTab, List parListSubItems)
{
      parListSubItems.add(new ItemStack(this, 1));
}

And if you wanted more subtypes to display of course you'd just add them to the list.  I expect you can control the order by the order you add them, although I haven't tested that specifically.

Making Tooltips For Your Custom Item

You can simply @Override the addInformation() method in your custom item.

Making Custom Food Items


There is a really good tutorial by BedRockMiner here: http://bedrockminer.jimdo.com/modding-tutorials/basic-modding/custom-food/

Making Something Happen When Item Goes Into Water


I've noticed it is fairly common for people to want to have a mod item that does something special when tossed into water.

As mentioned above, when an Item is dropped it is turned into an EntityItem. An EntityItem extends the Entity class, so you can @Override the onUpdate() method for your custom EntityItem to check for whether it is in contact with water. Since EntityItem extends the Entity class are two possible methods to check for contact with water. If you want rain to also cause some effect, then use the isWet() method. If you only want it to have effect when submerged in water use the isInWater() method.

Custom Item Actions (EnumAction)


Thanks to Choonster for this info.

EnumAction are used to control animations for items that are used over time. Like the swinging of a sword.

If you want similar behaviour to swords (hold right click to play an EnumAction) @Override Item#getitemUseAction to return the appropriate action and call EntityPlayer#setItemInUse in Item#onItemRightClick like ItemSword does.

Choonster has made a working example.

No comments:

Post a Comment