Wuppy’s Minecraft Forge Modding Tutorials for 1.6.2: Dimensions Part 2: ChunkProvider

In this tutorial series I will show you how to add a dimension to Minecraft. At first this will be the most basic possible dimension, but after that there will be some customization. In this tutorial I will show you how to add a basic ChunkProvider to the dimension. In the last tutorial we ended up with this code.


package tutorial;
importnet.minecraft.world.WorldProvider;
importnet.minecraft.world.biome.BiomeGenBase;
importnet.minecraft.world.biome.WorldChunkManagerHell;
importnet.minecraft.world.chunk.IChunkProvider;
publicclassWorldProviderTutorial extends WorldProvider
{
       publicvoidregisterWorldChunkManager()
       {
              this.worldChunkMgr = newWorldChunkManagerHell(BiomeGenBase.desertHills, 0.8F, 0.1F);
              this.dimensionId = Tutorial.dimensionId;
       }
      
       public IChunkProvider createChunkGenerator()
       {
              returnnew ChunkProviderTutorial(worldObj, worldObj.getSeed(), true);
       }
      
       @Override
       public String getDimensionName()
       {
              return“Tutorial”;
       }
}

Right now you will have an error under ChunkProviderTutorial, because we haven’t created that file just yet. Let’s do this right now by hovering your mouse over it and clicking create class. When you do this you will get a file that looks like this.


package tutorial;
import java.util.List;
importnet.minecraft.entity.EnumCreatureType;
importnet.minecraft.util.IProgressUpdate;
importnet.minecraft.world.ChunkPosition;
importnet.minecraft.world.World;
importnet.minecraft.world.chunk.Chunk;
importnet.minecraft.world.chunk.IChunkProvider;
publicclassChunkProviderTutorial implements IChunkProvider
{
       @Override
       publicboolean chunkExists(int i, int j)
       {
              // TODO Auto-generated method stub
              returnfalse;
       }
       @Override
       public Chunk provideChunk(int i, int j)
       {
              // TODO Auto-generated method stub
              returnnull;
       }
       @Override
       public Chunk loadChunk(int i, int j)
       {
              // TODO Auto-generated method stub
              returnnull;
       }
       @Override
       publicvoidpopulate(IChunkProvider ichunkprovider, int i, int j)
       {
              // TODO Auto-generated method stub
       }
       @Override
       publicboolean saveChunks(boolean flag, IProgressUpdate iprogressupdate)
       {
              // TODO Auto-generated method stub
              returnfalse;
       }
       @Override
       publicboolean unloadQueuedChunks()
       {
              // TODO Auto-generated method stub
              returnfalse;
       }
       @Override
       publicboolean canSave()
       {
              // TODO Auto-generated method stub
              returnfalse;
       }
       @Override
       public String makeString()
       {
              // TODO Auto-generated method stub
              returnnull;
       }
       @Override
       public List getPossibleCreatures(EnumCreatureType enumcreaturetype, int i, int j, int k)
       {
              // TODO Auto-generated method stub
              returnnull;
       }
       @Override
       public ChunkPosition findClosestStructure(World world, String s, int i, int j, int k)
       {
              // TODO Auto-generated method stub
              returnnull;
       }
       @Override
       publicintgetLoadedChunkCount()
       {
              // TODO Auto-generated method stub
              return 0;
       }
       @Override
       publicvoid recreateStructures(int i, int j)
       {
              // TODO Auto-generated method stub
       }
       @Override
       publicvoid func_104112_b()
       {
              // TODO Auto-generated method stub
       }
}

You could go and fill in all of these methods, but that would take weeks. The easiest thing to do is just copy over the code from ChunkProviderGenerate and edit that later. When you copy over the code there are a few things you have to do. First of all go to the top where there will be an error under the package line. Fix this by hovering over it and clicking “change package declaration to ‘your package name'”. Then go to the public class line and fix the error under ChunkProviderGenerate by clicking “rename type to ‘your file name'”. Finally use Ctrl, Shift, O to import all the required files and all the errors should be gone.
The file should now look something like this.


package tutorial;
importstaticnet.minecraftforge.event.terraingen.InitMapGenEvent.EventType.CAVE;
importstaticnet.minecraftforge.event.terraingen.InitMapGenEvent.EventType.MINESHAFT;
importstaticnet.minecraftforge.event.terraingen.InitMapGenEvent.EventType.RAVINE;
importstaticnet.minecraftforge.event.terraingen.InitMapGenEvent.EventType.SCATTERED_FEATURE;
importstaticnet.minecraftforge.event.terraingen.InitMapGenEvent.EventType.STRONGHOLD;
importstaticnet.minecraftforge.event.terraingen.InitMapGenEvent.EventType.VILLAGE;
importstaticnet.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.DUNGEON;
importstaticnet.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.ICE;
importstaticnet.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.LAKE;
importstaticnet.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.LAVA;
import java.util.List;
import java.util.Random;
importnet.minecraft.block.Block;
importnet.minecraft.block.BlockSand;
importnet.minecraft.entity.EnumCreatureType;
importnet.minecraft.util.IProgressUpdate;
importnet.minecraft.util.MathHelper;
importnet.minecraft.world.ChunkPosition;
importnet.minecraft.world.SpawnerAnimals;
importnet.minecraft.world.World;
importnet.minecraft.world.biome.BiomeGenBase;
importnet.minecraft.world.chunk.Chunk;
importnet.minecraft.world.chunk.IChunkProvider;
importnet.minecraft.world.gen.MapGenBase;
importnet.minecraft.world.gen.MapGenCaves;
importnet.minecraft.world.gen.MapGenRavine;
importnet.minecraft.world.gen.NoiseGeneratorOctaves;
importnet.minecraft.world.gen.feature.MapGenScatteredFeature;
importnet.minecraft.world.gen.feature.WorldGenDungeons;
importnet.minecraft.world.gen.feature.WorldGenLakes;
import net.minecraft.world.gen.structure.MapGenMineshaft;
importnet.minecraft.world.gen.structure.MapGenStronghold;
importnet.minecraft.world.gen.structure.MapGenVillage;
importnet.minecraftforge.common.MinecraftForge;
importnet.minecraftforge.event.Event.Result;
import net.minecraftforge.event.terraingen.ChunkProviderEvent;
importnet.minecraftforge.event.terraingen.PopulateChunkEvent;
importnet.minecraftforge.event.terraingen.TerrainGen;
publicclassChunkProviderTutorial implements IChunkProvider
{
    /** RNG. */
    private Random rand;
    /** A NoiseGeneratorOctaves used in generating terrain */
    privateNoiseGeneratorOctaves noiseGen1;
    /** A NoiseGeneratorOctaves used in generating terrain */
    privateNoiseGeneratorOctaves noiseGen2;
    /** A NoiseGeneratorOctaves used in generating terrain */
    privateNoiseGeneratorOctaves noiseGen3;
    /** A NoiseGeneratorOctaves used in generating terrain */
    privateNoiseGeneratorOctaves noiseGen4;
    /** A NoiseGeneratorOctaves used in generating terrain */
    publicNoiseGeneratorOctaves noiseGen5;
    /** A NoiseGeneratorOctaves used in generating terrain */
    publicNoiseGeneratorOctaves noiseGen6;
    publicNoiseGeneratorOctaves mobSpawnerNoise;
    /** Reference to the World object. */
    private World worldObj;
    /** are map structures going to be generated (e.g. strongholds) */
    privatefinalbooleanmapFeaturesEnabled;
    /** Holds the overall noise array used in chunk generation */
    privatedouble[] noiseArray;
    privatedouble[] stoneNoise = newdouble[256];
    private MapGenBase caveGenerator = new MapGenCaves();
    /** Holds Stronghold Generator */
    private MapGenStronghold strongholdGenerator = new MapGenStronghold();
    /** Holds Village Generator */
    private MapGenVillage villageGenerator = new MapGenVillage();
    /** Holds Mineshaft Generator */
    private MapGenMineshaft mineshaftGenerator = new MapGenMineshaft();
    privateMapGenScatteredFeature scatteredFeatureGenerator = new MapGenScatteredFeature();
    /** Holds ravine generator */
    private MapGenBase ravineGenerator = new MapGenRavine();
    /** The biomes that are used to generate the chunk */
    private BiomeGenBase[] biomesForGeneration;
    /** A double array that hold terrain noise from noiseGen3 */
    double[] noise3;
    /** A double array that hold terrain noise */
    double[] noise1;
    /** A double array that hold terrain noise from noiseGen2 */
    double[] noise2;
    /** A double array that hold terrain noise from noiseGen5 */
    double[] noise5;
    /** A double array that holds terrain noise from noiseGen6 */
    double[] noise6;
    /**
     * Used to store the 5×5 parabolic field that is used during terrain generation.
     */
    float[] parabolicField;
    int[][] field_73219_j = newint[32][32];
    {
        caveGenerator = TerrainGen.getModdedMapGen(caveGenerator, CAVE);
        strongholdGenerator = (MapGenStronghold) TerrainGen.getModdedMapGen(strongholdGenerator, STRONGHOLD);
        villageGenerator = (MapGenVillage) TerrainGen.getModdedMapGen(villageGenerator, VILLAGE);
        mineshaftGenerator = (MapGenMineshaft) TerrainGen.getModdedMapGen(mineshaftGenerator, MINESHAFT);
        scatteredFeatureGenerator = (MapGenScatteredFeature) TerrainGen.getModdedMapGen(scatteredFeatureGenerator, SCATTERED_FEATURE);
        ravineGenerator = TerrainGen.getModdedMapGen(ravineGenerator, RAVINE);
    }
    publicChunkProviderTutorial(World par1World, long par2, boolean par4)
    {
        this.worldObj = par1World;
        this.mapFeaturesEnabled = par4;
        this.rand = new Random(par2);
        this.noiseGen1 = newNoiseGeneratorOctaves(this.rand, 16);
        this.noiseGen2 = newNoiseGeneratorOctaves(this.rand, 16);
        this.noiseGen3 = newNoiseGeneratorOctaves(this.rand, 8);
        this.noiseGen4 = newNoiseGeneratorOctaves(this.rand, 4);
        this.noiseGen5 = newNoiseGeneratorOctaves(this.rand, 10);
        this.noiseGen6 = newNoiseGeneratorOctaves(this.rand, 16);
        this.mobSpawnerNoise = newNoiseGeneratorOctaves(this.rand, 8);
        NoiseGeneratorOctaves[] noiseGens = {noiseGen1, noiseGen2, noiseGen3, noiseGen4, noiseGen5, noiseGen6, mobSpawnerNoise};
        noiseGens = TerrainGen.getModdedNoiseGenerators(par1World, this.rand, noiseGens);
        this.noiseGen1 = noiseGens[0];
        this.noiseGen2 = noiseGens[1];
        this.noiseGen3 = noiseGens[2];
        this.noiseGen4 = noiseGens[3];
        this.noiseGen5 = noiseGens[4];
        this.noiseGen6 = noiseGens[5];
        this.mobSpawnerNoise = noiseGens[6];
    }
    /**
     * Generates the shape of the terrain for the chunk though its all stone though the water is frozen if the
     * temperature is low enough
     */
    publicvoid generateTerrain(int par1, int par2, byte[] par3ArrayOfByte)
    {
        byte b0 = 4;
        byte b1 = 16;
        byte b2 = 63;
        int k = b0 + 1;
        byte b3 = 17;
        int l = b0 + 1;
        this.biomesForGeneration = this.worldObj.getWorldChunkManager().getBiomesForGeneration(this.biomesForGeneration, par1 * 4 – 2, par2 * 4 – 2, k + 5, l + 5);
        this.noiseArray = this.initializeNoiseField(this.noiseArray, par1 * b0, 0, par2 * b0, k, b3, l);
        for (int i1 = 0; i1 < b0; ++i1)
        {
            for (int j1 = 0; j1 < b0; ++j1)
            {
                for (int k1 = 0; k1 < b1; ++k1)
                {
                    double d0 = 0.125D;
                    double d1 = this.noiseArray[((i1 + 0) * l + j1 + 0) * b3 + k1 + 0];
                    double d2 = this.noiseArray[((i1 + 0) * l + j1 + 1) * b3 + k1 + 0];
                    double d3 = this.noiseArray[((i1 + 1) * l + j1 + 0) * b3 + k1 + 0];
                    double d4 = this.noiseArray[((i1 + 1) * l + j1 + 1) * b3 + k1 + 0];
                    double d5 = (this.noiseArray[((i1 + 0) * l + j1 + 0) * b3 + k1 + 1] – d1) * d0;
                    double d6 = (this.noiseArray[((i1 + 0) * l + j1 + 1) * b3 + k1 + 1] – d2) * d0;
                    double d7 = (this.noiseArray[((i1 + 1) * l + j1 + 0) * b3 + k1 + 1] – d3) * d0;
                    double d8 = (this.noiseArray[((i1 + 1) * l + j1 + 1) * b3 + k1 + 1] – d4) * d0;
                    for (int l1 = 0; l1 < 8; ++l1)
                    {
                        double d9 = 0.25D;
                        double d10 = d1;
                        double d11 = d2;
                        double d12 = (d3 – d1) * d9;
                        double d13 = (d4 – d2) * d9;
                        for (int i2 = 0; i2 < 4; ++i2)
                        {
                            int j2 = i2 + i1 * 4 << 11 | 0 + j1 * 4 << 7 | k1 * 8 + l1;
                            short short1 = 128;
                            j2 -= short1;
                            double d14 = 0.25D;
                            double d15 = (d11 – d10) * d14;
                            double d16 = d10 – d15;
                            for (int k2 = 0; k2 < 4; ++k2)
                            {
                                if ((d16 += d15) > 0.0D)
                                {
                                    par3ArrayOfByte[j2 += short1] = (byte)Block.stone.blockID;
                                }
                                elseif (k1 * 8 + l1 < b2)
                                {
                                    par3ArrayOfByte[j2 += short1] = (byte)Block.waterStill.blockID;
                                }
                                else
                                {
                                    par3ArrayOfByte[j2 += short1] = 0;
                                }
                            }
                            d10 += d12;
                            d11 += d13;
                        }
                        d1 += d5;
                        d2 += d6;
                        d3 += d7;
                        d4 += d8;
                    }
                }
            }
        }
    }
    /**
     * Replaces the stone that was placed in with blocks that match the biome
     */
    publicvoidreplaceBlocksForBiome(int par1, int par2, byte[] par3ArrayOfByte, BiomeGenBase[] par4ArrayOfBiomeGenBase)
    {
        ChunkProviderEvent.ReplaceBiomeBlocks event = newChunkProviderEvent.ReplaceBiomeBlocks(this, par1, par2, par3ArrayOfByte, par4ArrayOfBiomeGenBase);
        MinecraftForge.EVENT_BUS.post(event);
        if (event.getResult() == Result.DENY) return;
        byte b0 = 63;
        double d0 = 0.03125D;
        this.stoneNoise = this.noiseGen4.generateNoiseOctaves(this.stoneNoise, par1 * 16, par2 * 16, 0, 16, 16, 1, d0 * 2.0D, d0 * 2.0D, d0 * 2.0D);
        for (int k = 0; k < 16; ++k)
        {
            for (int l = 0; l < 16; ++l)
            {
                BiomeGenBase biomegenbase = par4ArrayOfBiomeGenBase[l + k * 16];
                float f = biomegenbase.getFloatTemperature();
                int i1 = (int)(this.stoneNoise[k + l * 16] / 3.0D + 3.0D + this.rand.nextDouble() * 0.25D);
                int j1 = -1;
                byte b1 = biomegenbase.topBlock;
                byte b2 = biomegenbase.fillerBlock;
                for (int k1 = 127; k1 >= 0; –k1)
                {
                    int l1 = (l * 16 + k) * 128 + k1;
                    if (k1 <= 0 + this.rand.nextInt(5))
                    {
                        par3ArrayOfByte[l1] = (byte)Block.bedrock.blockID;
                    }
                    else
                    {
                        byte b3 = par3ArrayOfByte[l1];
                        if (b3 == 0)
                        {
                            j1 = -1;
                        }
                        elseif (b3 == Block.stone.blockID)
                        {
                            if (j1 == -1)
                            {
                                if (i1 <= 0)
                                {
                                    b1 = 0;
                                    b2 = (byte)Block.stone.blockID;
                                }
                                elseif (k1 >= b0 – 4 && k1 <= b0 + 1)
                                {
                                    b1 = biomegenbase.topBlock;
                                    b2 = biomegenbase.fillerBlock;
                                }
                                if (k1 < b0 && b1 == 0)
                                {
                                    if (f < 0.15F)
                                    {
                                        b1 = (byte)Block.ice.blockID;
                                    }
                                    else
                                    {
                                        b1 = (byte)Block.waterStill.blockID;
                                    }
                                }
                                j1 = i1;
                                if (k1 >= b0 – 1)
                                {
                                    par3ArrayOfByte[l1] = b1;
                                }
                                else
                                {
                                    par3ArrayOfByte[l1] = b2;
                                }
                            }
                            elseif (j1 > 0)
                            {
                                –j1;
                                par3ArrayOfByte[l1] = b2;
                                if (j1 == 0 && b2 == Block.sand.blockID)
                                {
                                    j1 = this.rand.nextInt(4);
                                    b2 = (byte)Block.sandStone.blockID;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    /**
     * loads or generates the chunk at the chunk location specified
     */
    public Chunk loadChunk(int par1, int par2)
    {
        returnthis.provideChunk(par1, par2);
    }
    /**
     * Will return back a chunk, if it doesn’t exist and its not a MP client it will generates all the blocks for the
     * specified chunk from the map seed and chunk seed
     */
    public Chunk provideChunk(int par1, int par2)
    {
        this.rand.setSeed((long)par1 * 341873128712L + (long)par2 * 132897987541L);
        byte[] abyte = newbyte[32768];
        this.generateTerrain(par1, par2, abyte);
        this.biomesForGeneration = this.worldObj.getWorldChunkManager().loadBlockGeneratorData(this.biomesForGeneration, par1 * 16, par2 * 16, 16, 16);
        this.replaceBlocksForBiome(par1, par2, abyte, this.biomesForGeneration);
        this.caveGenerator.generate(this, this.worldObj, par1, par2, abyte);
        this.ravineGenerator.generate(this, this.worldObj, par1, par2, abyte);
        if (this.mapFeaturesEnabled)
        {
            this.mineshaftGenerator.generate(this, this.worldObj, par1, par2, abyte);
            this.villageGenerator.generate(this, this.worldObj, par1, par2, abyte);
            this.strongholdGenerator.generate(this, this.worldObj, par1, par2, abyte);
            this.scatteredFeatureGenerator.generate(this, this.worldObj, par1, par2, abyte);
        }
        Chunk chunk = new Chunk(this.worldObj, abyte, par1, par2);
        byte[] abyte1 = chunk.getBiomeArray();
        for (int k = 0; k < abyte1.length; ++k)
        {
            abyte1[k] = (byte)this.biomesForGeneration[k].biomeID;
        }
        chunk.generateSkylightMap();
        return chunk;
    }
    /**
     * generates a subset of the level’s terrain data. Takes 7 arguments: the [empty] noise array, the position, and the
     * size.
     */
    privatedouble[] initializeNoiseField(double[] par1ArrayOfDouble, int par2, int par3, int par4, int par5, int par6, int par7)
    {
        ChunkProviderEvent.InitNoiseField event = newChunkProviderEvent.InitNoiseField(this, par1ArrayOfDouble, par2, par3, par4, par5, par6, par7);
        MinecraftForge.EVENT_BUS.post(event);
        if (event.getResult() == Result.DENY) return event.noisefield;
        if (par1ArrayOfDouble == null)
        {
            par1ArrayOfDouble = newdouble[par5 * par6 * par7];
        }
        if (this.parabolicField == null)
        {
            this.parabolicField = newfloat[25];
            for (int k1 = -2; k1 <= 2; ++k1)
            {
                for (int l1 = -2; l1 <= 2; ++l1)
                {
                    float f = 10.0F / MathHelper.sqrt_float((float)(k1 * k1 + l1 * l1) + 0.2F);
                    this.parabolicField[k1 + 2 + (l1 + 2) * 5] = f;
                }
            }
        }
        double d0 = 684.412D;
        double d1 = 684.412D;
        this.noise5 = this.noiseGen5.generateNoiseOctaves(this.noise5, par2, par4, par5, par7, 1.121D, 1.121D, 0.5D);
        this.noise6 = this.noiseGen6.generateNoiseOctaves(this.noise6, par2, par4, par5, par7, 200.0D, 200.0D, 0.5D);
        this.noise3 = this.noiseGen3.generateNoiseOctaves(this.noise3, par2, par3, par4, par5, par6, par7, d0 / 80.0D, d1 / 160.0D, d0 / 80.0D);
        this.noise1 = this.noiseGen1.generateNoiseOctaves(this.noise1, par2, par3, par4, par5, par6, par7, d0, d1, d0);
        this.noise2 = this.noiseGen2.generateNoiseOctaves(this.noise2, par2, par3, par4, par5, par6, par7, d0, d1, d0);
        boolean flag = false;
        boolean flag1 = false;
        int i2 = 0;
        int j2 = 0;
        for (int k2 = 0; k2 < par5; ++k2)
        {
            for (int l2 = 0; l2 < par7; ++l2)
            {
                float f1 = 0.0F;
                float f2 = 0.0F;
                float f3 = 0.0F;
                byte b0 = 2;
                BiomeGenBase biomegenbase = this.biomesForGeneration[k2 + 2 + (l2 + 2) * (par5 + 5)];
                for (int i3 = -b0; i3 <= b0; ++i3)
                {
                    for (int j3 = -b0; j3 <= b0; ++j3)
                    {
                        BiomeGenBase biomegenbase1 = this.biomesForGeneration[k2 + i3 + 2 + (l2 + j3 + 2) * (par5 + 5)];
                        float f4 = this.parabolicField[i3 + 2 + (j3 + 2) * 5] / (biomegenbase1.minHeight + 2.0F);
                        if (biomegenbase1.minHeight > biomegenbase.minHeight)
                        {
                            f4 /= 2.0F;
                        }
                        f1 += biomegenbase1.maxHeight * f4;
                        f2 += biomegenbase1.minHeight * f4;
                        f3 += f4;
                    }
                }
                f1 /= f3;
                f2 /= f3;
                f1 = f1 * 0.9F + 0.1F;
                f2 = (f2 * 4.0F – 1.0F) / 8.0F;
                double d2 = this.noise6[j2] / 8000.0D;
                if (d2 < 0.0D)
                {
                    d2 = -d2 * 0.3D;
                }
                d2 = d2 * 3.0D – 2.0D;
                if (d2 < 0.0D)
                {
                    d2 /= 2.0D;
                    if (d2 < -1.0D)
                    {
                        d2 = -1.0D;
                    }
                    d2 /= 1.4D;
                    d2 /= 2.0D;
                }
                else
                {
                    if (d2 > 1.0D)
                    {
                        d2 = 1.0D;
                    }
                    d2 /= 8.0D;
                }
                ++j2;
                for (int k3 = 0; k3 < par6; ++k3)
                {
                    double d3 = (double)f2;
                    double d4 = (double)f1;
                    d3 += d2 * 0.2D;
                    d3 = d3 * (double)par6 / 16.0D;
                    double d5 = (double)par6 / 2.0D + d3 * 4.0D;
                    double d6 = 0.0D;
                    double d7 = ((double)k3 – d5) * 12.0D * 128.0D / 128.0D / d4;
                    if (d7 < 0.0D)
                    {
                        d7 *= 4.0D;
                    }
                    double d8 = this.noise1[i2] / 512.0D;
                    double d9 = this.noise2[i2] / 512.0D;
                    double d10 = (this.noise3[i2] / 10.0D + 1.0D) / 2.0D;
                    if (d10 < 0.0D)
                    {
                        d6 = d8;
                    }
                    elseif (d10 > 1.0D)
                    {
                        d6 = d9;
                    }
                    else
                    {
                        d6 = d8 + (d9 – d8) * d10;
                    }
                    d6 -= d7;
                    if (k3 > par6 – 4)
                    {
                        double d11 = (double)((float)(k3 – (par6 – 4)) / 3.0F);
                        d6 = d6 * (1.0D – d11) + -10.0D * d11;
                    }
                    par1ArrayOfDouble[i2] = d6;
                    ++i2;
                }
            }
        }
        return par1ArrayOfDouble;
    }
    /**
     * Checks to see if a chunk exists at x, y
     */
    publicboolean chunkExists(int par1, int par2)
    {
        returntrue;
    }
    /**
     * Populates chunk with ores etc etc
     */
    publicvoidpopulate(IChunkProvider par1IChunkProvider, int par2, int par3)
    {
        BlockSand.fallInstantly = true;
        int k = par2 * 16;
        int l = par3 * 16;
        BiomeGenBase biomegenbase = this.worldObj.getBiomeGenForCoords(k + 16, l + 16);
        this.rand.setSeed(this.worldObj.getSeed());
        long i1 = this.rand.nextLong() / 2L * 2L + 1L;
        long j1 = this.rand.nextLong() / 2L * 2L + 1L;
        this.rand.setSeed((long)par2 * i1 + (long)par3 * j1 ^ this.worldObj.getSeed());
        boolean flag = false;
        MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Pre(par1IChunkProvider, worldObj, rand, par2, par3, flag));
        if (this.mapFeaturesEnabled)
        {
            this.mineshaftGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
            flag = this.villageGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
            this.strongholdGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
            this.scatteredFeatureGenerator.generateStructuresInChunk(this.worldObj, this.rand, par2, par3);
        }
        int k1;
        int l1;
        int i2;
        if (biomegenbase != BiomeGenBase.desert && biomegenbase != BiomeGenBase.desertHills && !flag && this.rand.nextInt(4) == 0
            && TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, flag, LAKE))
        {
            k1 = k + this.rand.nextInt(16) + 8;
            l1 = this.rand.nextInt(128);
            i2 = l + this.rand.nextInt(16) + 8;
            (new WorldGenLakes(Block.waterStill.blockID)).generate(this.worldObj, this.rand, k1, l1, i2);
        }
        if (TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, flag, LAVA) &&
                !flag && this.rand.nextInt(8) == 0)
        {
            k1 = k + this.rand.nextInt(16) + 8;
            l1 = this.rand.nextInt(this.rand.nextInt(120) + 8);
            i2 = l + this.rand.nextInt(16) + 8;
            if (l1 < 63 || this.rand.nextInt(10) == 0)
            {
                (new WorldGenLakes(Block.lavaStill.blockID)).generate(this.worldObj, this.rand, k1, l1, i2);
            }
        }
        boolean doGen = TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, flag, DUNGEON);
        for (k1 = 0; doGen && k1 < 8; ++k1)
        {
            l1 = k + this.rand.nextInt(16) + 8;
            i2 = this.rand.nextInt(128);
            int j2 = l + this.rand.nextInt(16) + 8;
            (newWorldGenDungeons()).generate(this.worldObj, this.rand, l1, i2, j2);
        }
        biomegenbase.decorate(this.worldObj, this.rand, k, l);
        SpawnerAnimals.performWorldGenSpawning(this.worldObj, biomegenbase, k + 8, l + 8, 16, 16, this.rand);
        k += 8;
        l += 8;
        doGen = TerrainGen.populate(par1IChunkProvider, worldObj, rand, par2, par3, flag, ICE);
        for (k1 = 0; doGen && k1 < 16; ++k1)
        {
            for (l1 = 0; l1 < 16; ++l1)
            {
                i2 = this.worldObj.getPrecipitationHeight(k + k1, l + l1);
                if (this.worldObj.isBlockFreezable(k1 + k, i2 – 1, l1 + l))
                {
                    this.worldObj.setBlock(k1 + k, i2 – 1, l1 + l, Block.ice.blockID, 0, 2);
                }
                if (this.worldObj.canSnowAt(k1 + k, i2, l1 + l))
                {
                    this.worldObj.setBlock(k1 + k, i2, l1 + l, Block.snow.blockID, 0, 2);
                }
            }
        }
        MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Post(par1IChunkProvider, worldObj, rand, par2, par3, flag));
        BlockSand.fallInstantly = false;
    }
    /**
     * Two modes of operation: if passed true, save all Chunks in one go.  If passed false, save up to two chunks.
     * Return true if all chunks have been saved.
     */
    publicboolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
    {
        returntrue;
    }
    publicvoid func_104112_b() {}
    /**
     * Unloads chunks that are marked to be unloaded. This is not guaranteed to unload every such chunk.
     */
    publicboolean unloadQueuedChunks()
    {
        returnfalse;
    }
    /**
     * Returns if the IChunkProvider supports saving.
     */
    publicboolean canSave()
    {
        returntrue;
    }
    /**
     * Converts the instance data to a readable string.
     */
    public String makeString()
    {
        return“RandomLevelSource”;
    }
    /**
     * Returns a list of creatures of the specified type that can spawn at the given location.
     */
    public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
    {
        BiomeGenBase biomegenbase = this.worldObj.getBiomeGenForCoords(par2, par4);
        return biomegenbase == null ? null : (biomegenbase == BiomeGenBase.swampland && par1EnumCreatureType == EnumCreatureType.monster && this.scatteredFeatureGenerator.hasStructureAt(par2, par3, par4) ? this.scatteredFeatureGenerator.getScatteredFeatureSpawnList() : biomegenbase.getSpawnableList(par1EnumCreatureType));
    }
    /**
     * Returns the location of the closest structure of the specified type. If not found returns null.
     */
    public ChunkPosition findClosestStructure(World par1World, String par2Str, int par3, int par4, int par5)
    {
        return“Stronghold”.equals(par2Str) && this.strongholdGenerator != null ? this.strongholdGenerator.getNearestInstance(par1World, par3, par4, par5) : null;
    }
    publicintgetLoadedChunkCount()
    {
        return 0;
    }
    publicvoid recreateStructures(int par1, int par2)
    {
        if (this.mapFeaturesEnabled)
        {
            this.mineshaftGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
            this.villageGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
            this.strongholdGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
            this.scatteredFeatureGenerator.generate(this, this.worldObj, par1, par2, (byte[])null);
        }
    }
}

From now on I will never put the whole ChunkProvider file in these posts, because it is way too big. Instead I will show you the changed pieces of code.
I won’t be explaining all of this code, because that would not really help a lot of people and it would take weeks to do so. However, in the customization tutorials I will show you what you may want to change in this file. In short the ChunkProvider pretty much generates or calls to generate all of the blocks. In here you can find code for caves, ravines, stone, biome blocks, dungeons, lakes etc. etc. It also does several other things like make the Ender eye work and the spawning of mobs.
These are all the files you need to create a proper dimension. However, you have no way to get there yet. In the next tutorials I will show you how to create a portal block and portal structure to get into the new dimension. After that will be loads of customization.

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="">