Showing posts with label item. Show all posts
Showing posts with label item. Show all posts

Thursday, March 5, 2015

Minecraft Tutorials: The Ore Dictionary

Time for another installment of my tutorial series on modding Minecraft.  This time I will discuss using the ore dictionary provided by Forge.

This tutorial will assume that you understand how to create a block or item, and how to add a new crafting recipe to your mod.  The code examples I present are from code written as this series progresses, so some of my code my be different from yours, unless you're following the whole series.

Anywho, suppose you have this mod, to which you've added a new ore, gem, type of wood, or what have you.  For example in this series we added copper.  There are a metric ton of mods that add copper as an ore.  Wouldn't it be nice if our copper ingots worked in there recipes and their copper ingots worked in ours?  This is where the ore dictionary comes in.  The ore dictionary stores a map of different ores, gems, etc, that are registered with the same String name and allows modders to add shaped and shapeless recipes using String names instead of ItemStacks.  With this you can make your mod's ores and other items compatible with other mods you don't even know exist!  Without it adding that kind of compatibility would require extra code for any and every mod you thought might maybe be used at the same time as your mod!

Before we get started there one important thing you should know: the ore dictionary relies on modders all following the same naming convention when registering their ores to the dictionary.  This convention is typeName for example oreCopper, ingotCopper, gemSapphire, dustGold, etc.
There's a nice article on common names in the ore dictionary on the Forge wiki and I highly recommend taking a look at it.

Now that we get how useful it is, let's use it.  I'll use the copper ore and ingot we created in previous tutorials for these examples.  First we want to make it possible for other mods to use our copper in their recipes.  I will do this with a call to the registerOre method from the OreDictionary class, which takes two parameters, a String name which ought to follow the convention I mentioned earlier, and an Item or Block which is the ore, or ingot or whatever that we are registering.  I am placing this call in ModItems.init() for the copper ingot and ModBlocks.init() for copper ore.  You could also place them directly in the preInit method of your main mod class.  My ModItems and ModBlocks classes now look like this (changes are highlighted):
package me.codasylph.grindermod.items;

import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.item.Item;
import net.minecraft.item.Item.ToolMaterial;
import net.minecraftforge.common.util.EnumHelper;
import net.minecraftforge.oredict.OreDictionary;

public class ModItems
{
       public static ToolMaterial COPPER = EnumHelper.addToolMaterial("COPPER", 2, 160, 8.0F, 1.0F, 10);
      
       public static Item copperIngot = new CopperIngot();
       public static Item copperPickaxe = new CopperPickaxe();
       public static Item copperAxe = new CopperAxe();
       public static Item copperShovel = new CopperShovel();
       public static Item copperHoe = new CopperHoe();
       public static Item copperSword = new CopperSword();
      
       public static void init()
       {
              GameRegistry.registerItem(copperIngot, copperIngot.getUnlocalizedName());
              GameRegistry.registerItem(copperPickaxe, copperPickaxe.getUnlocalizedName());
              GameRegistry.registerItem(copperAxe,copperAxe.getUnlocalizedName());
              GameRegistry.registerItem(copperShovel,copperShovel.getUnlocalizedName());
              GameRegistry.registerItem(copperHoe,copperHoe.getUnlocalizedName());
              GameRegistry.registerItem(copperSword,copperSword.getUnlocalizedName());
             
              OreDictionary.registerOre("ingotCopper", copperIngot);
       }

}

package me.codasylph.grindermod.blocks;

import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.block.Block;
import net.minecraftforge.oredict.OreDictionary;

public class ModBlocks
{
       public static Block copperOre = new CopperOre();
      
       public static void init()
       {
              GameRegistry.registerBlock(copperOre, copperOre.getUnlocalizedName());
             
              OreDictionary.registerOre("oreCopper", copperOre);
       }
}

Our copper ingots and ore can now be used in other mods recipes (assuming they actually use the ore dictionary, most do).  If you would like to test this you could either build the mod and install it with other forge compatible mods or if you're using eclipse, place another mod's jar file in the eclipse/mods folder and run your testing environment.  *You may also need to include something like CodeChickenCore if you get errors because the mod is obfuscated.

We're halfway done.  Now we want to be able to use other mods' copper in our recipes.  This we do with a call to the method GameRegistry.addRecipe.  addRecipe() takes one parameter that is an instance of IRecipe, the ore dictionary adds two new classes ShapedOreRecipe and ShapelessOreRecipes which both implement IRecipe.  Conveniently these two classes also take the same parameters as GameRegistry.addShapedRecipe and GameRegistry.addShapelessRecipe respectively, except that they can take a String name of an ore in place of an ItemStack. The line to add a our copper pickaxe would therefore be this:
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(ModItems.copperPickaxe), new Object[]{"CCC"," S "," S ",'C', "ingotCopper", 'S', stickStack}));
Since vanilla items are part of the ore dictionary I could even replace stickStack with "stickWood" allowing sticks from mods to work in this recipe.  Lastly, since our copper ingot is registered to the dictionary, I can remove the recipe I made in Crafting and Smelting Recipes as this one is sufficient.  Having done all that my ModRecipes class now looks like this: 
package me.codasylph.grindermod;

import me.codasylph.grindermod.blocks.ModBlocks;
import me.codasylph.grindermod.items.ModItems;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapedOreRecipe;
import cpw.mods.fml.common.registry.GameRegistry;

public class ModRecipes
{
       private static ItemStack copperIngotStacknew ItemStack(ModItems.copperIngot);
       private static ItemStack stickStacknew ItemStack(Items.stick);
      
       public static void init()
       {
              //Shapeless Recipes
              GameRegistry.addShapelessRecipe(new ItemStack(Items.slime_ball), new ItemStack(Items.dye,1,10), new ItemStack(Items.egg), new ItemStack(Items.sugar));
              //Shaped Recipes
              GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(ModItems.copperPickaxe), new Object[]{"CCC"," S "," S ",'C', "ingotCopper", 'S', stickStack}));
             
              //Smelting Recipes
              GameRegistry.addSmelting(ModBlocks.copperOre, copperIngotStack, 0.5F);
       }
}

A final thought, there's still more functionality in the ore dictionary than what was covered here.  I highly recommend checking out the declaration of OreDictionary, it is extremely useful and also extremely well commented!

To return to the table of contents click here.

Wednesday, March 4, 2015

Minecraft Tutorials: Crafting And Smelting Recipes

Another Minecraft modding tutorial.  In this tutorial I will discuss adding your own crafting and smelting recipes to a mod.  This tutorial assumes an understanding of block and item creation, as well as the main mod file.  As always, the code I'll be showing is built on code from all the tutorials thus far, and if you haven't been following allow exactly, your code is going to be a little bit different.

Minecraft has three standard types of recipes: Shapeless, Shaped, and Smelting. I'll go over each of them in turn, but first I'll make a class to handle all of them.  Let's call it ModRecipes and place it in the main mod package. All of our recipes will be registered in a new init() method.  Right now my ModRecipes class looks like this:
package me.codasylph.grindermod;

public class ModRecipes
{
       public static void init()
       {
             
       }
}

At this point we should also go ahead and call ModRecipes.init() in the init() method of the main mod class so that we can test the recipes as we go. For reference my main mod class looks like this now:
package me.codasylph.grindermod;

import me.codasylph.grindermod.blocks.CopperOre;
import me.codasylph.grindermod.blocks.ModBlocks;
import me.codasylph.grindermod.items.ModItems;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;

@Mod(modid = "grindermod", name = "Grinder Mod", version = "1.0")

public class GrinderMod
{     
       @Mod.EventHandler
       public void preInit(FMLPreInitializationEvent event)
       {
              GameRegistry.registerWorldGenerator(new WorldGenGinderMod(), 0);
              ModBlocks.init();
              ModItems.init();
       }

       @Mod.EventHandler
       public void init(FMLInitializationEvent event)
       {
              ModRecipes.init();
       }

       @Mod.EventHandler
       public void postInit(FMLPostInitializationEvent event)
       {
             
       }
}

Now then, recipes! Actually first: ItemStacks
The way Minecraft works there's only one instance of a given Item.  You register that instance and it is the only instance of that item. What you end up with in your inventory is an ItemStack.  An ItemStack is a separate class with several properties, including what it's a stack of and how big it is. The constructor takes three parameters, an Item, an int that determines the size, and finally an int that determines the damage on the item (also known as the meta data). The constructor is overloaded so you may also pass just the Item for a stack of one undamaged item, or the Item and the size for a stack of the given size in which the items are undamaged. You can have an ItemStack of item. More importantly can and will have many many instances of the ItemStack class, include many stacks with the same item.  ItemStacks have more properties but none we need to understand right now.

So now the recipes!

Shapeless recipes are those that require a amount of certain items to be placed in a crafting grid to produce a given item, but the arrangement doesn't matter.  Vanilla examples of shapeless recipes include turning a block of iron or gold into nine ingots or turning dye and a block of wool into wool of that color.  In this example I will add a shapeless recipe that makes a slime ball out of an egg, some sugar, and lime dye.  The line looks like this:
GameRegistry.addShapelessRecipe(new ItemStack(Items.slime_ball), new ItemStack(Items.dye,1,10), new ItemStack(Items.egg), new ItemStack(Items.sugar));
addShapelessRecipe takes a variable number of parameters of the type ItemStack.  The first parameter dictates the output and all the following parameters dictate the ingredients. If you run your testing environment at this point you should be able to throw lime dye, an egg, and a pile of sugar in to a crafting grid and get yourself a brand spanking new ball o' slime.  Yum! :p

Shaped recipes require items in a specified arrangement on the crafting grid to produce a particular product.  Vanilla examples include all the the tools in Minecraft.  In this example I will add a shaped recipe that uses sticks and the copper ingot we created in A Basic Item to create the pickaxe we created in A Basic Tool. It will look like this:
GameRegistry.addShapedRecipe(new ItemStack(ModItems.copperPickaxe), new Object[]{
       "CCC",
       " S ",
       " S ", 'C', new ItemStack(ModItems.copperIngot), 'S', new ItemStack(Items.stick)});

This takes two parameters (kinda), the first is the output.  The second is an array of Objects with the recipe.  The first three objects are strings of three characters each, that represent each row the the crafting grid. The remaining objects are the characters and what ItemStack they represent. Spaces always mean any empty slot and do not need to be defined. 
Here's another example that makes a vanilla furnace out of sandstone instead of cobblestone.
GameRegistry.addShapedRecipe(new ItemStack(Blocks.furnace), new Object[]{
       "SSS",
       "S S",
       "SSS"'S'new ItemStack(Blocks.sandstone)});
Again you should be able to try either of these recipes out in the testing environment now.

Smelting recipes are those that convert one Item or Block into another inside a furnace.  Presumably by the judicious application of heat.  Most smelting recipes are of the ore into ingot variety, but other vanilla examples include turning logs into charcoal or raw food into cooked food. In this example I will add a smelting recipe to turn the copper ore we created in A Basic Block into the ingot we made in A Basic Item. The line looks like this:
GameRegistry.addSmelting(ModBlocks.copperOre, new ItemStack(ModItems.copperIngot), 0.5F);
This method takes three parameters, unlike the previous methods the first parameter is the input instead of the output, and may be an instance of Block, Item, or ItemStack.  The second parameter is the output and must be and instance of ItemStack.  The final parameter is a float that dictates how much experience the player receives for smelting the item.  0.5 is slightly less than the amount received for smelting iron and a little more than that received for cooking a food item.

A final thought, you'll notice we used ModItems.copperIngot several times, if we went in and added shaped recipes for all the copper tools we'd use it quite a few more times.  It can be beneficial, there for, to declare an instance of ItemStack for each item you'll be using in multiple recipes so you're not calling the constructor over and over again for no reason.  After taking this advice my ModRecipes class looks like this:
package me.codasylph.grindermod;

import me.codasylph.grindermod.blocks.ModBlocks;
import me.codasylph.grindermod.items.ModItems;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.registry.GameRegistry;

public class ModRecipes
{
       private static ItemStack copperIngotStacknew ItemStack(ModItems.copperIngot);
       private static ItemStack stickStacknew ItemStack(Items.stick);
      
       public static void init()
       {
              //Shapeless Recipes
              GameRegistry.addShapelessRecipe(new ItemStack(Items.slime_ball), new ItemStack(Items.dye,1,10), new ItemStack(Items.egg), new ItemStack(Items.sugar));
              //Shaped Recipes
              GameRegistry.addShapedRecipe(new ItemStack(ModItems.copperPickaxe), new Object[]{
                     "CCC",
                     " S ",
                     " S ", 'C'copperIngotStack, 'S', stickStack});
             
              //Smelting Recipes
              GameRegistry.addSmelting(ModBlocks.copperOrecopperIngotStack, 0.5F);
       }
}

That's all folks!  To return to the table of contents click here.

Monday, March 2, 2015

Minecraft Tutorials: A Basic Tool

In this installation of my Minecraft modding tutorial series I will discuss creating custom pickaxes, swords, shovels, etc.  This tutorial assumes you have an understanding of how to create a basic mod file, and a basic item.  Oh, and a basic understanding of java also important, I keep forgetting to mention that one.  The code I'll show is built off of all previous tutorials so if you did not follow all the tutorials your code may be slightly different, that's ok.

The example I'll use is a Copper Pickaxe.
Most of the stats of a Minecraft tool (this includes swords) actually come from the ToolMaterial. This provides the tool's harvest level, durability, mining speed, damage, and enchant-ability.  If you wish these stats to be the same as a preexisting material like wood, or diamond, then you don't need to create a new material (although you might ask yourself why you're creating a new tool at all).

ToolMaterial is an enum and not a class so we can't create a new class that extends it.  Instead we will use forge's EnumHelper class to add our new material to the list.

To do this I will edit my ModItems.class to add the line
public static ToolMaterial COPPER = EnumHelper.addToolMaterial("COPPER", 2, 160, 8.0F, 1.0F, 10);

If you're not following along exactly with the tutorial series you can initialize your new ToolMaterial in your main mod file, or in a new class all its own.

addToolMaterials takes 6 parameters:
String Name is just the String name of the material.

int harvestLevel indicates the harvest level of tools made of this material. For reference vanilla harvest levels are as follows:
  • 0 Wood or Gold
  • 1 Stone
  • 2 Iron
  • 3 Diamond
copper tools will be able to harvest the same things as iron ones.  If we wanted we could give our new material a harvest level of 4, which would allow it to harvest anything diamond can, plus some things it can't! (which is nothing in vanilla minecraft)

int maxUses indicates number of time the tool can be used before it breaks, also known as the durability. For reference vanilla durabilities are as follows
  • Gold 32
  • Wood 59
  • Stone 131
  • Iron 250
  • Diamond 1561
So our tools made from our material are less durable than iron, but moreso than stone.

float efficiency indicates the speed at which the tool mines, digs, swings, or whatever it does.
Vanilla efficiency levels are:
  • Wood 2.0
  • Stone 4.0
  • Iron 6.0
  • Diamond 8.0
  • Gold 12.0
Making copper as speedy as diamond!
float damage indicates how much damage is done to entities that are attacked with a tool made from this material, although it should be noted that certain tools, such as swords have a higher base damage.
Vanilla damage levels are:
  • Wood or Gold 0.0
  • Stone 1.0
  • Iron 2.0
  • Diamond 3.0
So copper tools are as effective as stone for dealing damage.

int enchantability indicates the natural enchantability factor for the material.
Vanilla enchantability levels are:
  • Wood 15
  • Stone 5
  • Iron 14
  • Diamond 10
  • Gold 22
This means our copper tools will take enchantments about as well as diamond tools.  All in all this makes copper a little better than iron for tools (except maybe swords) but significantly less durable, which I think balances it out some.

Now that we have a ToolMaterial, we need to use it on something!  I will start with a new pickaxe.  I do this by creating a new class in me.codasylph.grindermod.items.  I will name it CopperPickaxe and have it extend ItemPickaxe. My class looks like this:
package me.codasylph.grindermod.items;

import net.minecraft.item.ItemPickaxe;

public class CopperPickaxe extends ItemPickaxe
{

}

Right now I have an error because I need to write an explicit constructor, so I'll write one that calls the super constructor and passes my newly created material ModItems.COPPER, then I'll flush it out with the same sorts of things that I put in my CopperIngot item, an unlocalized name, a texture, and a creative tab to find it in.  Now my class looks like this:
package me.codasylph.grindermod.items;

import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemPickaxe;

public class CopperPickaxe extends ItemPickaxe
{
       private final String unlocalizedName = "copperPickaxe";

       public CopperPickaxe()
       {
              super(ModItems.COPPER);
              this.setUnlocalizedName(unlocalizedName);
              this.setTextureName("grindermod:"+unlocalizedName);
              this.setCreativeTab(CreativeTabs.tabTools);
       }

}
This is the texture I used: 

If anything in the above code doesn't make sense to you, you should probably refer to the A Basic Item tutorial.

Now, the item needs to be registered, this is done exactly the same way one would for any other item, with a call to GameRegistry.registerItem().  I will place this in my pre-existing init method of my ModItems class, so that class now looks like this:
package me.codasylph.grindermod.items;

import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.item.Item;
import net.minecraft.item.Item.ToolMaterial;
import net.minecraftforge.common.util.EnumHelper;

public class ModItems
{
       public static ToolMaterial COPPER = EnumHelper.addToolMaterial("COPPER", 2, 160, 8.0F, 1.0F, 10);
      
       public static Item copperIngot = new CopperIngot();
       public static Item copperPickaxe = new CopperPickaxe();
      
       public static void init()
       {
              GameRegistry.registerItem(copperIngot, copperIngot.getUnlocalizedName());
              GameRegistry.registerItem(copperPickaxe, copperPickaxe.getUnlocalizedName());
       }
}

You can use this procedure will all the different tool types, the classes to extend are as follows:
  • Pickaxe = ItemPickaxe
  • Axe = ItemAxe
  • Shovel = ItemSpade
  • Hoe = ItemHoe
  • Sword = ItemSword
And here are some unimpressive textures to play with:

Don't forget to update your language file!

To return to the table of contents click here.