Modding 1.5.2: Nether, End and Metadata Ore Generation

In this tutorial I’m going to show you how to add ore generation to the nether. If you haven’t already read through the tutorial for overworld generation. I’m not going over the basics again in this tutorial. For this tutorial all you will have to do is create a new file and edit the EventManager file. This is the file I will start with.


package tutorial;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.world.World;
importnet.minecraft.world.chunk.IChunkProvider;
importnet.minecraft.world.gen.feature.WorldGenMinable;
importcpw.mods.fml.common.IWorldGenerator;
publicclass EventManager implements IWorldGenerator
{
       publicvoid 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);
             }
       }
      
       privatevoid generateEnd(World world, Random random, int x, int z)
       {
            
       }
       privatevoid 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);
       }
       privatevoid 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
        **/
       publicvoid 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);
                    (newWorldGenMinable(block.blockID, maxVeinSize)).generate(world, random, posX, posY, posZ);
             }
       }
}

For overworld ore generation we have been using WorldGenMinable. However, that only works when you are generating in stone. This time you have to generate in nether rack so we will have to use a custom WorldGen file. I use a template file for this. That file looks like this.


package tutorial;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
importnet.minecraft.world.gen.feature.WorldGenerator;
publicclass WorldGenNetherMinable extendsWorldGenerator
{
    /** The block ID of the ore to be placed using this generator. */
    privateintminableBlockId;
    /** The number of blocks to generate. */
    privateintnumberOfBlocks;
    public WorldGenNetherMinable(int par1, int par2)
    {
        minableBlockId = par1;
        numberOfBlocks = par2;
    }
    publicboolean generate(World par1World, Random par2Random, int par3, int par4, int par5)
    {
        float f = par2Random.nextFloat() * (float)Math.PI;
        double d = (float)(par3 + 8) + (MathHelper.sin(f) * (float)numberOfBlocks) / 8F;
        double d1 = (float)(par3 + 8) – (MathHelper.sin(f) * (float)numberOfBlocks) / 8F;
        double d2 = (float)(par5 + 8) + (MathHelper.cos(f) * (float)numberOfBlocks) / 8F;
        double d3 = (float)(par5 + 8) – (MathHelper.cos(f) * (float)numberOfBlocks) / 8F;
        double d4 = (par4 + par2Random.nextInt(3)) – 2;
        double d5 = (par4 + par2Random.nextInt(3)) – 2;
        for (int i = 0; i <= numberOfBlocks; i++)
        {
            double d6 = d + ((d1 – d) * (double)i) / (double)numberOfBlocks;
            double d7 = d4 + ((d5 – d4) * (double)i) / (double)numberOfBlocks;
            double d8 = d2 + ((d3 – d2) * (double)i) / (double)numberOfBlocks;
            double d9 = (par2Random.nextDouble() * (double)numberOfBlocks) / 16D;
            double d10 = (double)(MathHelper.sin(((float)i * (float)Math.PI) / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
            double d11 = (double)(MathHelper.sin(((float)i * (float)Math.PI) / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
            int j = MathHelper.floor_double(d6 – d10 / 2D);
            int k = MathHelper.floor_double(d7 – d11 / 2D);
            int l = MathHelper.floor_double(d8 – d10 / 2D);
            int i1 = MathHelper.floor_double(d6 + d10 / 2D);
            int j1 = MathHelper.floor_double(d7 + d11 / 2D);
            int k1 = MathHelper.floor_double(d8 + d10 / 2D);
            for (int l1 = j; l1 <= i1; l1++)
            {
                double d12 = (((double)l1 + 0.5D) – d6) / (d10 / 2D);
                if (d12 * d12 >= 1.0D)
                {
                    continue;
                }
                for (int i2 = k; i2 <= j1; i2++)
                {
                    double d13 = (((double)i2 + 0.5D) – d7) / (d11 / 2D);
                    if (d12 * d12 + d13 * d13 >= 1.0D)
                    {
                        continue;
                    }
                    for (int j2 = l; j2 <= k1; j2++)
                    {
                        double d14 = (((double)j2 + 0.5D) – d8) / (d10 / 2D);
                        if (d12 * d12 + d13 * d13 + d14 * d14 < 1.0D && par1World.getBlockId(l1, i2, j2) == Block.netherrack.blockID)
                        {
                            par1World.setBlock(l1, i2, j2, minableBlockId);
                        }
                    }
                }
            }
        }
        returntrue;
    }
}

Now to use this file you will have to add some code to the generateNether method. That code should look like this.


int Xcoord = x + random.nextInt(16);

int Ycoord = 10 + random.nextInt(128);
int Zcoord = z + random.nextInt(16);
(new WorldGenNetherMinable(Tutorial.tutorialBlock.blockID, 15)).generate(world, random, Xcoord, Ycoord, Zcoord);

This code does exactly the same as the addOreSpawn method. The only difference is that it uses WorldGenNetherMinable instead of WorldGenMinable. You can choose this code style for your overworld ores as well, but I prefer the method, because it can get really messy when you have several blocks.
The whole file should now look like this.


package tutorial;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.world.World;
importnet.minecraft.world.chunk.IChunkProvider;
importnet.minecraft.world.gen.feature.WorldGenMinable;
importcpw.mods.fml.common.IWorldGenerator;
publicclass EventManager implements IWorldGenerator
{
       publicvoid 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);
             }
       }
      
       privatevoid generateEnd(World world, Random random, int x, int z)
       {
            
       }
       privatevoid 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);
       }
       privatevoid generateNether(World world, Random random, int x, int z)
       {
             int Xcoord = x + random.nextInt(16);
             int Ycoord = 10 + random.nextInt(128);
             int Zcoord = z + random.nextInt(16);
             (newWorldGenNetherMinable(Tutorial.tutorialBlock.blockID, 15)).generate(world, random, Xcoord, Ycoord, Zcoord);
       }
       /**
        * 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
        **/
       publicvoid 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);
                    (newWorldGenMinable(block.blockID, maxVeinSize)).generate(world, random, posX, posY, posZ);
             }
       }
}

However, the nether ore for the tutorial block has metadata. That is why we have to make a little change to the WorldGenNetherMinable. The thing you need to do is add a new parameter to the constructor which is metadata. The constructor and variables above should then look like this.


/** The block ID of the ore to be placed using this generator. */

privateintminableBlockId;
   
privateintmetadata;
/** The number of blocks to generate. */
privateintnumberOfBlocks;
public WorldGenNetherMinable(int par1, int par2, int par3)
{
     minableBlockId = par1;
     metadata = par2;
     numberOfBlocks = par3;
}

Now we need to make sure that the metadata variable is used when placing the block. That is done by changing the par1World.setBlock line. That line has to look like this now.


par1World.setBlock(l1, i2, j2, minableBlockId, metadata, 2);


There are 2 new parameters in here. The first one being the metadata and the second being 2. You don’t really have to understand the 2. It’s just how the setBlock method works when you don’t set a metadata or this value like you do here.
The whole file should now look like this.


package tutorial;

import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
importnet.minecraft.world.gen.feature.WorldGenerator;
publicclass WorldGenNetherMinable extendsWorldGenerator
{
    /** The block ID of the ore to be placed using this generator. */
    privateintminableBlockId;
   
    privateintmetadata;
    /** The number of blocks to generate. */
    privateintnumberOfBlocks;
    public WorldGenNetherMinable(int par1, int par2, int par3)
    {
        minableBlockId = par1;
        metadata = par2;
        numberOfBlocks = par3;
    }
    publicboolean generate(World par1World, Random par2Random, int par3, int par4, int par5)
    {
        float f = par2Random.nextFloat() * (float)Math.PI;
        double d = (float)(par3 + 8) + (MathHelper.sin(f) * (float)numberOfBlocks) / 8F;
        double d1 = (float)(par3 + 8) – (MathHelper.sin(f) * (float)numberOfBlocks) / 8F;
        double d2 = (float)(par5 + 8) + (MathHelper.cos(f) * (float)numberOfBlocks) / 8F;
        double d3 = (float)(par5 + 8) – (MathHelper.cos(f) * (float)numberOfBlocks) / 8F;
        double d4 = (par4 + par2Random.nextInt(3)) – 2;
        double d5 = (par4 + par2Random.nextInt(3)) – 2;
        for (int i = 0; i <= numberOfBlocks; i++)
        {
            double d6 = d + ((d1 – d) * (double)i) / (double)numberOfBlocks;
            double d7 = d4 + ((d5 – d4) * (double)i) / (double)numberOfBlocks;
            double d8 = d2 + ((d3 – d2) * (double)i) / (double)numberOfBlocks;
            double d9 = (par2Random.nextDouble() * (double)numberOfBlocks) / 16D;
            double d10 = (double)(MathHelper.sin(((float)i * (float)Math.PI) / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
            double d11 = (double)(MathHelper.sin(((float)i * (float)Math.PI) / (float)numberOfBlocks) + 1.0F) * d9 + 1.0D;
            int j = MathHelper.floor_double(d6 – d10 / 2D);
            int k = MathHelper.floor_double(d7 – d11 / 2D);
            int l = MathHelper.floor_double(d8 – d10 / 2D);
            int i1 = MathHelper.floor_double(d6 + d10 / 2D);
            int j1 = MathHelper.floor_double(d7 + d11 / 2D);
            int k1 = MathHelper.floor_double(d8 + d10 / 2D);
            for (int l1 = j; l1 <= i1; l1++)
            {
                double d12 = (((double)l1 + 0.5D) – d6) / (d10 / 2D);
                if (d12 * d12 >= 1.0D)
                {
                    continue;
                }
                for (int i2 = k; i2 <= j1; i2++)
                {
                    double d13 = (((double)i2 + 0.5D) – d7) / (d11 / 2D);
                    if (d12 * d12 + d13 * d13 >= 1.0D)
                    {
                        continue;
                    }
                    for (int j2 = l; j2 <= k1; j2++)
                    {
                        double d14 = (((double)j2 + 0.5D) – d8) / (d10 / 2D);
                        if (d12 * d12 + d13 * d13 + d14 * d14 < 1.0D && par1World.getBlockId(l1, i2, j2) == Block.netherrack.blockID)
                        {
                            par1World.setBlock(l1, i2, j2, minableBlockId, metadata, 2);
                        }
                    }
                }
            }
        }
        returntrue;
    }
}

Now you will get an error under the code in generateNether. To fix that add the metadata value in between the 2 already existing variables. That method should then look like this when you use a metadata of 1.


privatevoid generateNether(World world, Random random, int x, int z)

{
       int Xcoord = x + random.nextInt(16);
       int Ycoord = 10 + random.nextInt(128);
       int Zcoord = z + random.nextInt(16);
       (new WorldGenNetherMinable(Tutorial.tutorialBlock.blockID, 1, 15)).generate(world, random, Xcoord, Ycoord, Zcoord);
}

Making your ores generate in the end is very much the same as in the nether. You just change netherrack into endstone and make sure you call the generation code for the end dimension and not for any other ones.

You can look at the source code 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="">