Wuppy’s Minecraft Forge Modding Tutorials for 1.6.2: Overworld Ore Generation

In this tutorial I’m going to show you how to add custom ore generation to the overworld. Some of the code for that is done in the mod file. This is the file I will start with.


package tutorial;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = Tutorial.modid, name = “Mod Name”, version = “1.0”)
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class Tutorial
{
       public static final String modid = “YourName_ModName”;
      
       public static Block tutorialBlock;
      
       public static Item tutorialItem;
      
       @Init
       public void load(FMLInitializationEvent event)
       {
             tutorialBlock = new BlockTutorialBlock(500, Material.rock).setUnlocalizedName(“tutorialBlock”);
            
             GameRegistry.registerBlock(tutorialBlock, ItemTutorialBlock.classmodid + (tutorialBlock.getUnlocalizedName().substring(5)));
            
             LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 0), “Tutorial Block”);
             LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 1), “Nether Tutorial Block”);
            
             tutorialItem = new ItemTutorial(5000).setUnlocalizedName(“tutorialItem”);
            
             LanguageRegistry.addName(tutorialItem“Tutorial Item”);
            
             TutorialCrafting.addRecipes();
       }
}

There are a couple of ways to add your ore to generation. In this tutorial I’m going to show the way I prefer it, but there are always other ways you can do it.
In my opinion the best way to do it is with an EventManager. A lot of things in Forge are done with events. If you want to see different kinds of events you should take a look at net.minecraftforge.event. In later tutorials I will show you how to use these events. Another way certain events are done is through interfaces. Those also contain methods that get run when the event happens. One of those events are for ore generation. However, most forge mods will contain more than just a single type of Event. That is why we won’t be creating a different file for every single Event, but for all of them in one.

To do this you should create a file that will handle all the events. For the tutorial I’m going to call it EventManager. Then make an object of it in the mod file. You should register that object as a World Generator using this code.


GameRegistry.registerWorldGenerator(eventmanager);


And now the whole mod file should look like this.


package tutorial;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = Tutorial.modid, name = “Mod Name”, version = “1.0”)
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class Tutorial
{
       public static final String modid = “YourName_ModName”;
      
       public static Block tutorialBlock;
      
       public static Item tutorialItem;
      
       EventManager eventmanager = new EventManager();
      
       @Init
       public void load(FMLInitializationEvent event)
       {
             tutorialBlock = new BlockTutorialBlock(500, Material.rock).setUnlocalizedName(“tutorialBlock”);
            
             GameRegistry.registerBlock(tutorialBlock, ItemTutorialBlock.classmodid + (tutorialBlock.getUnlocalizedName().substring(5)));
            
             LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 0), “Tutorial Block”);
             LanguageRegistry.addName(new ItemStack(tutorialBlock, 1, 1), “Nether Tutorial Block”);
            
             tutorialItem = new ItemTutorial(5000).setUnlocalizedName(“tutorialItem”);
            
             LanguageRegistry.addName(tutorialItem“Tutorial Item”);
            
             GameRegistry.registerWorldGenerator(eventmanager);
            
             TutorialCrafting.addRecipes();
       }
}

If you haven’t created the EventManager file just yet you will get an error under registerWorldManager. If you did you will also get an error under there. To fix the error you will have to make the EventManager implement IWorldGenerator. Make sure you implement and not extend or it will give you errors. When you do that you need to import the file. After that you will get an error under EventManager which you can fix by adding the unimplemented methods. Then the file should look like this.


package tutorial;

import java.util.Random;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import cpw.mods.fml.common.IWorldGenerator;
public class EventManager implements IWorldGenerator
{
       public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
       {
            
       }
}

Almost every mod will have multiple ores to generate. There are quite a few lines of code you need to write so that is why we will make a method that will write all the code for you. The only thing you need to do is paste it in the file and call it with the block and locations you want it to generate. This is the method you can use for that.


/**

 * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in your IWorldGeneration extending Class
 *
 * @param The Block to spawn
 * @param The World to spawn in
 * @param A Random object for retrieving random positions within the world to spawn the Block
 * @param An int for passing the XCoordinate for the Generation method
 * @param An int for passing the ZCoordinate for the Generation method
 * @param An int for setting the maximum XCoordinate values for spawning on the XAxis on a PerChunk basis
 * @param An int for setting the maximum ZCoordinate values for spawning on the ZAxis on a PerChunk basis
 * @param An int for setting the maximum size of a vein
 * @param An int for the Number of chances available for the Block to spawn perchunk
 * @param An int for the minimum YCoordinate height at which this block may spawn
 * @param An int for the maximum YCoordinate height at which this block may spawn
 **/
public void addOreSpawn(Block block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY)
{
       int maxPossY = minY + (maxY – 1);
       assert maxY > minY: “The maximum Y must be greater than the Minimum Y”;
       assert maxX > 0 && maxX <= 16: “addOreSpawn: The Maximum X must be greater than 0 and less than 16″;
       assert minY > 0: “addOreSpawn: The Minimum Y must be greater than 0″;
       assert maxY < 256 && maxY > 0: “addOreSpawn: The Maximum Y must be less than 256 but greater than 0″;
       assert maxZ > 0 && maxZ <= 16: “addOreSpawn: The Maximum Z must be greater than 0 and less than 16″;
      
       int diffBtwnMinMaxY = maxY – minY;
       for(int x = 0; x < chancesToSpawn; x++)
       {
             int posX = blockXPos + random.nextInt(maxX);
             int posY = minY + random.nextInt(diffBtwnMinMaxY);
             int posZ = blockZPos + random.nextInt(maxZ);
             (new WorldGenMinable(block.blockID, maxVeinSize)).generate(world, random, posX, posY, posZ);
       }
}

This method takes a lot of parameters and they are all explained in the comment above it. This method will use the vanilla WorldGenMinable and then use all of the variables you put in to generate the ore.
Now that we have a way to generate the ores there is one more thing we have to do before we can actually use it. When you are generating ores you usually only want it to generate in a single dimension. To make sure it only goes in one dimension you will have to add a switch and 3 methods to the file. One for each dimension. Once that is done the file should look like this.


package tutorial;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import cpw.mods.fml.common.IWorldGenerator;
public class EventManager implements IWorldGenerator
{
       public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
       {
             switch(world.provider.dimensionId)
             {
                    case -1: generateNether(world, random, chunkX * 16, chunkZ * 16);
                    case 0: generateSurface(world, random, chunkX * 16, chunkZ * 16);
                    case 1: generateEnd(world, random, chunkX * 16, chunkZ * 16);
             }
       }
      
       private void generateEnd(World world, Random random, int x, int z)
       {
            
       }
       private void generateSurface(World world, Random random, int x, int z)
       {
            
       }
       private void generateNether(World world, Random random, int x, int z)
       {
            
       }
       /**
        * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in your IWorldGeneration extending Class
        *
        * @param The Block to spawn
        * @param The World to spawn in
        * @param A Random object for retrieving random positions within the world to spawn the Block
        * @param An int for passing the XCoordinate for the Generation method
        * @param An int for passing the ZCoordinate for the Generation method
        * @param An int for setting the maximum XCoordinate values for spawning on the XAxis on a PerChunk basis
        * @param An int for setting the maximum ZCoordinate values for spawning on the ZAxis on a PerChunk basis
        * @param An int for setting the maximum size of a vein
        * @param An int for the Number of chances available for the Block to spawn perchunk
        * @param An int for the minimum YCoordinate height at which this block may spawn
        * @param An int for the maximum YCoordinate height at which this block may spawn
        **/
       public void addOreSpawn(Block block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY)
       {
             int maxPossY = minY + (maxY – 1);
             assert maxY > minY: “The maximum Y must be greater than the Minimum Y”;
             assert maxX > 0 && maxX <= 16: “addOreSpawn: The Maximum X must be greater than 0 and less than 16″;
             assert minY > 0: “addOreSpawn: The Minimum Y must be greater than 0″;
             assert maxY < 256 && maxY > 0: “addOreSpawn: The Maximum Y must be less than 256 but greater than 0″;
             assert maxZ > 0 && maxZ <= 16: “addOreSpawn: The Maximum Z must be greater than 0 and less than 16″;
            
             int diffBtwnMinMaxY = maxY – minY;
             for(int x = 0; x < chancesToSpawn; x++)
             {
                    int posX = blockXPos + random.nextInt(maxX);
                    int posY = minY + random.nextInt(diffBtwnMinMaxY);
                    int posZ = blockZPos + random.nextInt(maxZ);
                    (new WorldGenMinable(block.blockID, maxVeinSize)).generate(world, random, posX, posY, posZ);
             }
       }
}

So we now have a method to generate the ores and a separate method for each dimension to make sure it generate the ores in the right dimension. Of course if you don’t want to generate ores in a certain dimension you can simply remove that part of the switch and remove the method.
Now we will have to call addOreSpawn in generateSurface which has to be done like this.


private void generateSurface(World world, Random random, int x, int z)

{
       this.addOreSpawn(Tutorial.tutorialBlock, world, random, x, z, 16, 16, 4 + random.nextInt(3), 5, 15, 50);
}

A big part of the parameters in here have to be exactly the same. world, random, x and z can’t be changed.
The first parameter is the block that will be generated.
The 2 16’s make sure that the blocks can spawn in the whole chunk. If you want blocks to only generate in the first 5 blocks of a chunk for some reason you can change one of those variables.
The 8th variable is the size of the vein and the one after that is how many of the veins will be made in a single chunk. The last 2 variables are the lowest and the highest height those veins will appear.

The whole file should now look something like this.


package tutorial;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import cpw.mods.fml.common.IWorldGenerator;
public class EventManager implements IWorldGenerator
{
       public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider)
       {
             switch(world.provider.dimensionId)
             {
                    case -1: generateNether(world, random, chunkX * 16, chunkZ * 16);
                    case 0: generateSurface(world, random, chunkX * 16, chunkZ * 16);
                    case 1: generateEnd(world, random, chunkX * 16, chunkZ * 16);
             }
       }
      
       private void generateEnd(World world, Random random, int x, int z)
       {
            
       }
       private void generateSurface(World world, Random random, int x, int z)
       {
             this.addOreSpawn(Tutorial.tutorialBlock, world, random, x, z, 16, 16, 4 + random.nextInt(3), 5, 15, 50);
       }
       private void generateNether(World world, Random random, int x, int z)
       {
            
       }
       /**
        * Adds an Ore Spawn to Minecraft. Simply register all Ores to spawn with this method in your Generation method in your IWorldGeneration extending Class
        *
        * @param The Block to spawn
        * @param The World to spawn in
        * @param A Random object for retrieving random positions within the world to spawn the Block
        * @param An int for passing the XCoordinate for the Generation method
        * @param An int for passing the ZCoordinate for the Generation method
        * @param An int for setting the maximum XCoordinate values for spawning on the XAxis on a PerChunk basis
        * @param An int for setting the maximum ZCoordinate values for spawning on the ZAxis on a PerChunk basis
        * @param An int for setting the maximum size of a vein
        * @param An int for the Number of chances available for the Block to spawn perchunk
        * @param An int for the minimum YCoordinate height at which this block may spawn
        * @param An int for the maximum YCoordinate height at which this block may spawn
        **/
       public void addOreSpawn(Block block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chancesToSpawn, int minY, int maxY)
       {
             int maxPossY = minY + (maxY – 1);
             assert maxY > minY: “The maximum Y must be greater than the Minimum Y”;
             assert maxX > 0 && maxX <= 16: “addOreSpawn: The Maximum X must be greater than 0 and less than 16″;
             assert minY > 0: “addOreSpawn: The Minimum Y must be greater than 0″;
             assert maxY < 256 && maxY > 0: “addOreSpawn: The Maximum Y must be less than 256 but greater than 0″;
             assert maxZ > 0 && maxZ <= 16: “addOreSpawn: The Maximum Z must be greater than 0 and less than 16″;
            
             int diffBtwnMinMaxY = maxY – minY;
             for(int x = 0; x < chancesToSpawn; x++)
             {
                    int posX = blockXPos + random.nextInt(maxX);
                    int posY = minY + random.nextInt(diffBtwnMinMaxY);
                    int posZ = blockZPos + random.nextInt(maxZ);
                    (new WorldGenMinable(block.blockID, maxVeinSize)).generate(world, random, posX, posY, posZ);
             }
       }
}

In the next tutorial I will show you how to add Ore generation to the nether.

You can download the source code and the assets folder over here.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">