Basic Blocks

From Minecraft Forge
Jump to: navigation, search


How-To Icon.png

This is a How-To guide or Tutorial detailing a practice or process for Minecraft Forge or related software.

Generic Mod

Havvy Generic Mod Banner Final.png

October 9, 2014 Added metadata support in localising tutorial --SkylordJoel

March 27, 2014 Updated Basic Items to 1.7.x --Jwosty

February 13, 2014 1.7 update happen and I fix up some of the stuff so far:

  • Basic Blocks

But it has one part not working yet

--Chibill

July 5, 2013

1.6.1 came out so I have fixed up some of the basic tutorials to go with it.

Ones that are updated include:

-- Mew

March 13, 2013

1.5 came out, so I fixed the methods to account for this (mostly the Icons/Textures tutorial).

--Squawkers13

December 13th, 2012

Alright, Forge made their installation process really simple and also made proper packages, removing the common/src distinction. I rewrote most of Basic Modding to account for this update. Overall though, this simplifies the explanations, but imports changed in all tutorials. Next up, I need to finish the world gen tutorial.

With the Basic Modding tutorial being mostly rewritten, if anything is confusing about it now, please tell me ASAP!

December 3rd, 2012

I finally finished the tutorial on Plants I started a month ago. I also fixed a minor compilation bug in Packet Handling. I reorganized the Generic Ore section by adding a Dropping Ore section. I'm starting to use a General Knowledge template where the background is grey. The knowledge in those boxes are general facts that are not specific to whatever thing we are implementing. I updated the Textures and Icons section to say that the image can be any scalar of 16x16 pixels where 256x256 will have each icon be 16x16 in size.




Contents

Goal

  • To learn the basics of adding new blocks to Minecraft
    • To add blocks similar to Dirt, Stone, and Glowstone
  • To understand how to use the following methods on Block
    • setStepSound
    • setResistance
    • setHardness
    • setCreativeTab
  • To understand how to override the following methods on Block
    • quantityDropped

Prerequisites

Basics

Blocks consist of the majority of the Minecraft world. Other than the players, mobs, paintings, and item entities, everything in the Minecraft world is a block.

Creating simple blocks is easier than items, since the Block constructors are public by default. On the other hand, blocks have more that has to be configured. Every block has the following properties:

Icon 
Block icon to show to the user.
Material 
Materials set various properties described in the next section.
Blast Resistance 
How resistant to blasts, such as from creepers or TNT, a block is.
Luminance 
How bright the block is.
Hardness 
How long it takes to mine a block.
Creative Tab 
Which creative tab the block is under.
Sounds 
What sounds are heard when entities walk over the block. The list is in the Block class, prefixed with sound.

Materials

Compared to the rest of the properties, materials are complex in what is set. The good news though, is that you'll probably not need to create a material. Materials can set the following properties:

  • Whether a block can burn.
  • Whether a block drops itself.
  • Whether a block can be pushed, i.e. by a piston.
  • Color on maps
  • Whether a block is translucent (like leaves and snow)
  • Whether a block is a ground cover (like snow)

The entire list can be found at net.minecraft.block.material.Material. Picking which one you want shouldn't be that difficult. If none of them match what you want, you can create your own Material, and use that.

GenericBlock

While it is possible to create Blocks without subclassing Block, it helps when using custom textures. As such, add the following class to the tutorial.generic package.

package tutorial.generic;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;

public class GenericBlock extends Block
{

        public GenericBlock (Material material)
        {
                super(material);
        }

}

The constructor just passes up to Block's constructor. The only modification from Block is overriding registerIcons so as to load from our texture file. The rest of the settings will be done using method chaining in the base mod.

NOTE: If you need help with shapeless recipes, check out this video tutorial: http://www.youtube.com/watch?v=JtBBhhw6Y4Y

Generic Dirt

Looking at the Block class, dirt has a hardness of 0.5F, and the same sound as gravel. It also uses Material.ground for its material. There are quite a few methods that can help us here.

For 1.6

public final static Block genericDirt = new GenericBlock(Material.ground)
        .setHardness(0.5F).setStepSound(Block.soundGravelFootstep)
        .setUnlocalizedName("genericDirt").setCreativeTab(CreativeTabs.tabBlock);

For 1.7

public final static Block genericDirt = new GenericBlock(Material.ground)
        .setHardness(0.5F).setStepSound(Block.soundTypeGravel)
        .setBlockName("genericDirt").setCreativeTab(CreativeTabs.tabBlock);

As you can see, this will use the ground material.

setHardness
Takes a floating point number where 0.5F is dirt and obsidian is 50F. Hardness is best described on the Minecraft Wiki.
setStepSound
Takes a sound. As said earlier, all sounds you'll want to use are fields on the Block class.
setUnlocalizedName/setBlockName(1.7)
Sets an internal name for the block. This is the name of the block in unlocalized state. It will be localized by minecraft/forge code auto-magically.
setCreativeTab
Sets the tab the item will be found in for the creative inventory. In this case, the block tab is used.

All other properties are set by default.

NOTE: Material requires importing the following class net.minecraft.block.material.Material

Block Registration

Blocks need to be registered to Forge. To do so, use GameRegistry.registerBlock(Block block, String internalName). Add this to the load method.

GameRegistry.registerBlock(genericDirt, "genericDirt");

This internal name has to be unique compared to other blocks in your mod. Since it's a good idea to keep block names unique anyways, the name will be the same as the one used in Block.setUnlocalizedName(). This string value is the string mapping that will eventually replace the current id->block mapping.

Public Names

Notice that setUnlocalizedName doesn't take a human readable name. If you hovered over this block in inventory, you'll get no name for the block. To fix this, we have to a language if in my case en_US.lang it should be in assets/yourname_modname/lang so for here it is assets/generic/lang (for 1.7.10 its found in '[your_forge_folder]\src\main\resources\assets\[your_modname]\lang')

FROM WUPPY'S TUT


A .lang file works very easily. You simply put the unlocalized name first, then directly follow it by an = and then directly after that add the localized name. Make sure there are no spaces between the unlocalized name, the = sign and the localized name or it will not work for you. You can, of course, have names in the unlocalized and localized name. This is what you have to add for the different types of localizations.


For us it is tile.genericDirt.name=Generic Dirt


Now when people pick up generic dirt, the tooltip will show "Generic Dirt".

Effective Tools

For 1.6

At this point, the block is created, but if you try to mine it with anything (except swords), it'll take 1.5 seconds to mine. Even with a shovel. It's not like dirt yet. To make blocks effectively able to be mined we use setBlockHarvestLevel, a static method on MinecraftForge.

MinecraftForge.setBlockHarvestLevel(Block block, String toolClass, int tier);

The toolClass is one of "pickaxe", "shovel", and "axe", or if you are adding a new tool class, you can use a custom toolClass name. The tier is 0 for wood, 1 for stone, 2 for iron, and 3 for diamond.

Let's use this method to make genericDirt harvested by wooden shovels or better more effectively.

MinecraftForge.setBlockHarvestLevel(genericDirt, "shovel", 0);

This method is called against MinecraftForge which needs to be added with the following import net.minecraftforge.common.MinecraftForge

NOTE: If you need help with custom blocks, check out this video tutorial: http://www.youtube.com/watch?v=uzCpTD5aVRY

For 1.7

This function in now built into the main block class. To set the harvest level, call
setHarvestLevel("shovel",0);
in your blocks constructor.

Textures

For textures, since Items and Blocks share a lot in common, see Icons and Textures.

Generic Ore

Now that generic dirt has replicated dirt, it's time to move onto the next block to create. Now's a good time to take a break if you haven't had one yet.

GenericOre is an ore that will drop Generic Ingots created in the Basic items tutorial. If you haven't gone through that tutorial yet, replace all instances of Generic.genericIngot with Item.ingotIron. Or you could go through it right now. Your choice.

Generic Ore is stronger than diamond. It will be the next tier higher, and require a diamond pickaxe to properly mine.

Now that we know what GenericOre is, let's create the GenericOre class.

package tutorial.generic;

import net.minecraft.block.material.Material;
import net.minecraft.block.Block;

public class GenericOre extends Block
{
        public GenericOre(Material material)
        {
                super(material);
        }
}
Subclassing
Say, that looks just like GenericBlock, but with a new name. Why didn't you just subclass GenericBlock? Well, if I was going to use GenericBlock in future tutorials, I would have done so, but I want to minimize the amount of classes that need to be dragged into future tutorials.

Instead of configuring this block in Generic via subclassing, the configuration will happen in the constructor itself. Add the following configuration to the constructor.

For 1.6

setHardness(4.0F); // 33% harder than diamond
setStepSound(Block.soundStoneFootstep);
setUnlocalizedName("genericOre");
setCreativeTab(CreativeTabs.tabBlock);

For 1.7

setHardness(4.0F); // 33% harder than diamond
setStepSound(Block.soundTypePiston); // sounds got renamed, look in Block class for what blocks have what sounds
setBlockName("genericOre"); // changed in 1.7
setCreativeTab(CreativeTabs.tabBlock);


Then, go into the Generic base mod class, and insert the following field.

public final static Block genericOre = new GenericOre(Material.rock);

Then add the following three method calls to the load method of the Generic base mod class.

MinecraftForge.setBlockHarvestLevel(genericOre, "pickaxe", 3);
GameRegistry.registerBlock(genericOre, "genericOre");

If you don't understand any parts of this, reread the GenericDirt section.

Dropping Ore

The material we choose says not to drop items when destroyed. While this seems counter-intuitive to what we want, it actually means that only items of the same or better harvest level set can harvest them. As such, a diamond pickaxe or better is required to mine generic ingots. Using any lesser tools will break the block and drop nothing.

We don't always want to drop the block when it breaks. Sometimes we want to drop items, like diamonds and redstone and generic ingots. Blocks have a method, getItemDropped that says which item to drop. It has the following signature.
public Item getItemDropped(int metadata, Random random, int fortune);
The first parameter is the metadata of the block. For this block, it will always be zero. The second parameter is a random for when you want to have a randomness effect such as IndustrialCraft machines possibly dropping either themselves or a machine block. The third parameter is the fortune level of the tool. You should always return the itemID field of the item or block you want to drop. If you don't want to drop any item, return null.

Generic Ore is one such block that does not drop itself. It should drop itself, and then need to be smelted if we were following any of the other ingots in Minecraft, but then we'd need yet another example block, and you don't want to read that. So this block will drop Generic Ingots.

Add one of the belows methods to the GenericOre class:

       
        //If the block's drop is an item.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Generic.genericIngot;
        }
       
        //If the block's drop is a block.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Item.getItemFromBlock(Generic.genericBlock);
        }
       
        //If the block's drop is a vanilla item.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Item.getItemById(Id);
        }
       
        //If the block's drop is a vanilla block.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Item.getItemFromBlock(Block.getBlockById(id));
        }

NOTE: You will need to import java.util.Random and make the genericIngot variable in the Generic class Public. The Basic Items tutorial had this as Private.

Finishing Up

Generic Class

package tutorial.generic;

// This Import list will grow longer with each additional tutorial.
// It's not pruned between full class postings, unlike other tutorial code.
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.block.material.Material;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
//import cpw.mods.fml.common.Mod.Init;     //Used in 1.5.2 and before
import cpw.mods.fml.common.Mod.Instance;
//import cpw.mods.fml.common.Mod.PostInit; //Used in 1.5.2 and before
//import cpw.mods.fml.common.Mod.PreInit;  //Used in 1.5.2 and before
import cpw.mods.fml.common.SidedProxy;
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.network.NetworkMod;        //Used in 1.6.4 and before
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry; //Used in 1.6.4 and before

@Mod(modid="generic", name="Generic", version="0.0.0")
//@NetworkMod(clientSideRequired=true, serverSideRequired=false) //Used in 1.6.4 and before
public class Generic
{
        // See Basic items tutorial for Generic Ingot
        public static Item genericIngot;
       
        public static Block genericDirt;
        public static Block genericOre;
       
        @Instance(value="generic")
        public static Generic instance;
       
        @SidedProxy(clientSide="tutorial.generic.client.ClientProxy",
                        serverSide="tutorial.generic.CommonProxy")
        public static CommonProxy proxy;
       
        @EventHandler
        public void preInit(FMLPreInitializationEvent event)
        {
                genericDirt = new GenericBlock(Material.ground)
                .setHardness(0.5F).setStepSound(Block.soundGravelFootstep)
                .setUnlocalizedName("genericDirt").setCreativeTab(CreativeTabs.tabBlock);
                genericOre = new GenericOre(Material.rock);
                MinecraftForge.setBlockHarvestLevel(genericDirt, "shovel", 0);
                GameRegistry.registerBlock(genericDirt, "genericDirt");
                MinecraftForge.setBlockHarvestLevel(genericOre, "pickaxe", 3);
                GameRegistry.registerBlock(genericOre, "genericOre");
                // End Basic Blocks
               
                proxy.registerRenderers();
        }
         
        @EventHandler
        public void init(FMLInitializationEvent event) {
        }

        @EventHandler
        public void postInit(FMLPostInitializationEvent event) {
                // Stub Method
        }
}

GenericBlock Class

package tutorial.generic;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;

public class GenericBlock extends Block
{

        public GenericBlock (Material material)
        {
                super(material);
        }
}

GenericOre Class

package tutorial.generic;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockOre;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.block.material.Material;

public class GenericOre extends Block
{
         public GenericOre(int id, Material material)
     {
             super(id, material);
               
                setHardness(4.0F); // 33% harder than diamond
                setStepSound(Block.soundStoneFootstep);
                setUnlocalizedName("genericOre");
                setCreativeTab(CreativeTabs.tabBlock);
        }
       

        //If the block's drop is an item.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Generic.genericIngot;
        }
       
        //If the block's drop is a block.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Item.getItemFromBlock(Generic.genericBlock);
        }
       
        //If the block's drop is a vanilla item.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Item.getItemById(Id);
        }
       
        //If the block's drop is a vanilla block.
        @Override
        public Item getItemDropped(int metadata, Random random, int fortune) {
            return Item.getItemFromBlock(Block.getBlockById(id));
        }

}

What's Next?

Once those are finished, you can continue along the path with one of the following:

Personal tools
Namespaces
Variants
Actions
Navigation
tutorials
Toolbox