In the chunk provider for the specific dimension there will be a method called "replaceBlocksForBiome". I believe the End and the Overworld use the same chunk provider, just so you know.
In the chunk provider for the specific dimension there will be a method called "replaceBlocksForBiome". I believe the End and the Overworld use the same chunk provider, just so you know.
The multi-biome dimension tutorial will be on page 15.
They use the same chunk provider you say? Interesting! That gave me an idea.. I know all about the replceBlocksForBiome method, problem is, I can't get it to work in the Nether :/
Also, I'm actually messaging jimmy on this very issue. (replacing biome blocks in the Nether that is) I've sent him the source code for a mod that has this feature to see if he could figure out what makes it tick. I've spent countless hours trying to figure this out, believe me. But, his dimension tutorial is great, I've tried it recently I just need to get this working before I can start implementing that
(BTW, I just checked and I was wrong. They don't use the same chunk provider, they use the same chunk manager)
Have you registered your own world provider to the Nether dimension? If you haven't you can do it like this:
In your init method in your main mod class add this line:
DimensionManager.unregisterProviderType(-1);
This will unlink the WorldProviderHell from the Nether dimension, whose dimension ID is -1 (overworld is 0 and the End is 1). Once this is done you will have to link your own world provider like so:
You will have to create your own world provider and chunk provider classes, but they can be duplicates of WorldProviderHell and ChunkProviderHell respectively. You would only have to change the world provider's chunk provider variable and then the desired replacement blocks in your chunk provider, but after that you should be all set.
(BTW, I just checked and I was wrong. They don't use the same chunk provider, they use the same chunk manager)
Have you registered your own world provider to the Nether dimension? If you haven't you can do it like this:
In your init method in your main mod class add this line:
DimensionManager.unregisterProviderType(-1);
This will unlink the WorldProviderHell from the Nether dimension, whose dimension ID is -1 (overworld is 0 and the End is 1). Once this is done you will have to link your own world provider like so:
You will have to create your own world provider and chunk provider classes, but they can be duplicates of WorldProviderHell and ChunkProviderHell respectively. You would only have to change the world provider's chunk provider variable and then the desired replacement blocks in your chunk provider, but after that you should be all set.
Let me get this straight,
Would this make it so I would be able to use my own chunk provider AND world provider, still have the dimension ID as -1, and still have the nether portal send me to the new nether? Kind of like overriding the whole dimension with my new classes? Or would it just be the world provider? Also, how does this enable the biome-specific replacement of top and filler blocks?
i don't recommend changing vanilla code :s other mods may not be capible anymore with your mod (wich makes it impossible to put your mod into a modpack... )
Yes yes I know, I'm just doing this for learning purposes so I can implement it WITHOUT changing base classes later
i don't recommend changing vanilla code :s other mods may not be capible anymore with your mod (wich makes it impossible to put your mod into a modpack... )
My method does not change vanilla code, although I admit completely replacing the world provider is a bit extreme. However, I do know of one mod that for certain does this too (which would make your mod incompatible with unless you develop some other kind of work around): Biomes O' Plenty.
Would this make it so I would be able to use my own chunk provider AND world provider, still have the dimension ID as -1, and still have the nether portal send me to the new nether? Kind of like overriding the whole dimension with my new classes?
Yes
Also, how does this enable the biome-specific replacement of top and filler blocks?
It doesn't inherently. If you were just to make a duplicate of the default hell chunk provider to use as your own, you would not have the code necessary to take into account top and filler blocks, as the Nether only has one biome, and doesn't have a 'top' to speak of. Now you could modify your chunk provider to adopt some of the surface's chunk provider's code that allows the use of top and filler block which is available in the 'replaceBlocksForBiome' method.
It doesn't inherently. If you were just to make a duplicate of the default hell chunk provider to use as your own, you would not have the code necessary to take into account top and filler blocks, as the Nether only has one biome, and doesn't have a 'top' to speak of. Now you could modify your chunk provider to adopt some of the surface's chunk provider's code that allows the use of top and filler block which is available in the 'replaceBlocksForBiome' method.
I've tried this in several different ways, no luck anywhere unfortunately :c
It doesn't inherently. If you were just to make a duplicate of the default hell chunk provider to use as your own, you would not have the code necessary to take into account top and filler blocks, as the Nether only has one biome, and doesn't have a 'top' to speak of. Now you could modify your chunk provider to adopt some of the surface's chunk provider's code that allows the use of top and filler block which is available in the 'replaceBlocksForBiome' method.
Alright, so I deobfuscated and decompiled a mod that does nether-style world gen and uses top and filler blocks, and used the chunk provider from there. It was a success, however, it also replaces lava with top and filler blocks at the bottom of the world. I think I can fix that, but, I still would like to use my own class instead of copying someone else's. I can paste the chunk provider here if you'd like to look at it. I still can't figure out what makes it work. I did find one odd thing, there's two replace biome block methods in this chunk provider.
Ok, some of the stuff that you guys have been bouncing back and forth is confusing me with all these chunk manager / provider things, so I'm just going to throw at you a world gen code of mine which replaces netherrack
DISCLAIMER: I made this mod for Minecraft 1.4.6. I hope too much hasn't changed, but sorry if it has
Go ahead and find the WorldGenMineable file (package net.minecraft.world.gen.feature). Very close to the bottom of the page, you'll find this
In other words, Minecraft is checking if the place where an ore is going to be is GenMineableReplaceable. We know that Stone is where ore spawns, so GenMineableReplaceable is completely synonymous with "is Stone"
So to Hell with that code (literally) because we replace it with:
block != null && block == Block.netherrack)
and now when you're creating your ore generation file, you ask for the WorldGenNether instead of the WorldGenMineable code (I haven't worked with worldgen in a while so I don't remember exactly how it goes, but if you've already got an overworld ore working then this will be easy)
You can have my entire WorldGenNether file if you want it, but you'll have to change the package declaration etc.
Author's Note: Some of what I said may have sounded condescending. Sorry bout that. I just dont like it when people try to help me but they think I already know everything and they dont help at all, so I tried to be very complete in my explanation.
EDIT: I didn't want to leave you hanging and I felt bad for being lazy and closing it there, so I've gone and found my nether ore code. I've cut out most of the crap you don't need:
package com.voussoir.carbon;
import java.util.Random;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import net.minecraft.world.*;
import cpw.mods.fml.common.IWorldGenerator;
public class CarbonWorldGenerator 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);
}
}
public void generateSurface(World world, Random random, int blockX, int blockZ)
{
//Overworld ore generation stuff, you probably already have something here
}
public void generateNether(World world, Random random, int blockX, int blockZ)
{
for(int q = 1;q<3;q++)
{
{
int xcoord = blockX + random.nextInt(16);
int ycoord = random.nextInt(90);
int zcoord = blockZ + random.nextInt(16);
(new WorldGenNether(mod_Carbon.crystalOreHell.blockID, random.nextInt(4))).generate(world, random, xcoord, ycoord, zcoord);
}
}
}
Don't forget to register your generator in your mod_ file
@allshallobey - yeah go ahead and post the code, I would like to take a look at it and see if I can explain a bit to you.
@Voussoir - Its great that you found a way to do what you wanted in a way that you understand, but there was a simpler way.
I want to point you to the 'generateNetherTerrain' method in the ChunkProviderHell class. In that method there is this portion of code:
for (int k2 = 0; k2 < 4; ++k2)
{
int l2 = 0;
//this generates the large lakes of lava near the bottom of the Nether
//simply replace the block ID to change it to whatever you want
if (k1 * 8 + l1 < b1)
{
l2 = Block.lavaStill.blockID;
}
//this will generate all of the netherrack
//simply replace this block ID to the one you want to change all of the netherrack to another block
if (d15 > 0.0D)
{
l2 = Block.netherrack.blockID;
}
par3ArrayOfByte[j2] = (byte)l2;
j2 += short1;
d15 += d16;
}
I've commented the code which you need to notice. All you had to do, Voussior, was change the netherrack block ID to whichever one you want. Of course, understand that you would need to do what I suggested in a previous post to make your own world provider and chunk provider as changes to base vanilla code will cause mod incompatibility.
@allshallobey - yeah go ahead and post the code, I would like to take a look at it and see if I can explain a bit to you.
@Voussoir - Its great that you found a way to do what you wanted in a way that you understand, but there was a simpler way.
I want to point you to the 'generateNetherTerrain' method in the ChunkProviderHell class. In that method there is this portion of code:
for (int k2 = 0; k2 < 4; ++k2)
{
int l2 = 0;
//this generates the large lakes of lava near the bottom of the Nether
//simply replace the block ID to change it to whatever you want
if (k1 * 8 + l1 < b1)
{
l2 = Block.lavaStill.blockID;
}
//this will generate all of the netherrack
//simply replace this block ID to the one you want to change all of the netherrack to another block
if (d15 > 0.0D)
{
l2 = Block.netherrack.blockID;
}
par3ArrayOfByte[j2] = (byte)l2;
j2 += short1;
d15 += d16;
}
I've commented the code which you need to notice. All you had to do, Voussior, was change the netherrack block ID to whichever one you want. Of course, understand that you would need to do what I suggested in a previous post to make your own world provider and chunk provider as changes to base vanilla code will cause mod incompatibility.
Okay, I'm going to be a bit clearer on what I need here. I don't need explanations on how to change netherrack to something else. Here's a picture, column of blocks on the left is what it generates like now, on the right is how I want it to generate. As you can see, I want top blocks in the nether.
Ok, some of the stuff that you guys have been bouncing back and forth is confusing me with all these chunk manager / provider things, so I'm just going to throw at you a world gen code of mine which replaces netherrack
DISCLAIMER: I made this mod for Minecraft 1.4.6. I hope too much hasn't changed, but sorry if it has
Go ahead and find the WorldGenMineable file (package net.minecraft.world.gen.feature). Very close to the bottom of the page, you'll find this
In other words, Minecraft is checking if the place where an ore is going to be is GenMineableReplaceable. We know that Stone is where ore spawns, so GenMineableReplaceable is completely synonymous with "is Stone"
So to Hell with that code (literally) because we replace it with:
block != null && block == Block.netherrack)
and now when you're creating your ore generation file, you ask for the WorldGenNether instead of the WorldGenMineable code (I haven't worked with worldgen in a while so I don't remember exactly how it goes, but if you've already got an overworld ore working then this will be easy)
You can have my entire WorldGenNether file if you want it, but you'll have to change the package declaration etc.
Author's Note: Some of what I said may have sounded condescending. Sorry bout that. I just dont like it when people try to help me but they think I already know everything and they dont help at all, so I tried to be very complete in my explanation.
EDIT: I didn't want to leave you hanging and I felt bad for being lazy and closing it there, so I've gone and found my nether ore code. I've cut out most of the crap you don't need:
package com.voussoir.carbon;
import java.util.Random;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import net.minecraft.world.*;
import cpw.mods.fml.common.IWorldGenerator;
public class CarbonWorldGenerator 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);
}
}
public void generateSurface(World world, Random random, int blockX, int blockZ)
{
//Overworld ore generation stuff, you probably already have something here
}
public void generateNether(World world, Random random, int blockX, int blockZ)
{
for(int q = 1;q<3;q++)
{
{
int xcoord = blockX + random.nextInt(16);
int ycoord = random.nextInt(90);
int zcoord = blockZ + random.nextInt(16);
(new WorldGenNether(mod_Carbon.crystalOreHell.blockID, random.nextInt(4))).generate(world, random, xcoord, ycoord, zcoord);
}
}
}
Don't forget to register your generator in your mod_ file
-Voussoir
Thanks, but unfortunately I don't need to just replace netherrack. :c See last two posts by me ^
What you could do is make a world generator that checks for top-exposed blocks in the nether by checking if the block above the coords you are looking at is an air block.
With x, y, and z being the current block coords you are comparing, you check the block above it to see if it is air.
If that returns true and the block is netherrack then replace the block:
if (world.isAirBlock(x, y + 1, z) && world.getBlockID(x, y, z) == Block.netherrack.blockID) {
world.setBlock(x, y, z, topBlockID);
}
A problem I can see immediately is that depending on the order world gens occur, this will also replace the floor blocks in caves if the caves are generated first.
What you could do is make a world generator that checks for top-exposed blocks in the nether by checking if the block above the coords you are looking at is an air block.
With x, y, and z being the current block coords you are comparing, you check the block above it to see if it is air.
If that returns true and the block is netherrack then replace the block:
if (world.isAirBlock(x, y + 1, z) && world.getBlockID(x, y, z) == Block.netherrack.blockID) {
world.setBlock(x, y, z, topBlockID);
}
A problem I can see immediately is that depending on the order world gens occur, this will also replace the floor blocks in caves if the caves are generated first.
ok so i have been messing around with a chunk provider i add to replace the ChunkProviderHell (nether) and i have got it to replace the top blocks with the ones i specfiy in my biome used for the nether, i will show both codes, and a pic to show what i did, if i have time tonight i will try do the multi biome version but maybe this will help, the big changes were made in the replaceNBlocksForBiomes method so use that as a reference, hope it helps you out
package com.Dimension.world;
import java.util.List;
import java.util.Random;
import com.Dimension.biomes.BiomeGenBaseTutorial;
import com.Dimension.biomes.MainBiomes;
import com.Dimension.world.gen.TopBlockReplacerGenerator;
import net.minecraft.block.Block;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.util.IProgressUpdate;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.biome.WorldChunkManager;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.MapGenBase;
import net.minecraft.world.gen.MapGenCavesHell;
import net.minecraft.world.gen.NoiseGeneratorOctaves;
import net.minecraft.world.gen.feature.WorldGenHellLava;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.Event.Result;
import net.minecraftforge.event.EventBus;
import net.minecraftforge.event.terraingen.ChunkProviderEvent;
import net.minecraftforge.event.terraingen.ChunkProviderEvent.ReplaceBiomeBlocks;
public class ChunkProviderNether1 implements IChunkProvider
{
private Random hellRNG;
private NoiseGeneratorOctaves netherNoiseGen1;
private NoiseGeneratorOctaves netherNoiseGen2;
private NoiseGeneratorOctaves netherNoiseGen3;
private NoiseGeneratorOctaves slowsandGravelNoiseGen;
private NoiseGeneratorOctaves stoneExculsivityNoiseGen;
public NoiseGeneratorOctaves netherNoiseGen6;
public NoiseGeneratorOctaves netherNoiseGen7;
private World worldObj;
private double[] field_4163_o;
private double[] slowsandNoise;
private double[] gravelNoise;
private double[] stoneExclusivityNoise;
private MapGenBase netherCaveGenerator;
double[] noiseData1;
double[] noiseData2;
double[] noiseData3;
double[] noiseData4;
double[] noiseData5;
private double[] noiseArray;
private double[] stoneNoise = new double[256];
private NoiseGeneratorOctaves noiseGen1;
private NoiseGeneratorOctaves noiseGen2;
private NoiseGeneratorOctaves noiseGen3;
private NoiseGeneratorOctaves noiseGen4;
public NoiseGeneratorOctaves noiseGen5;
public NoiseGeneratorOctaves noiseGen6;
public Random rand;
public ChunkProviderNether1(World par1World, long par2)
{
this.slowsandNoise = new double[256];
this.gravelNoise = new double[256];
this.stoneExclusivityNoise = new double[256];
this.netherCaveGenerator = new MapGenCavesHell();
this.worldObj = par1World;
this.hellRNG = new Random(par2);
this.rand = new Random(par2);
this.netherNoiseGen1 = new NoiseGeneratorOctaves(this.hellRNG, 16);
this.netherNoiseGen2 = new NoiseGeneratorOctaves(this.hellRNG, 16);
this.netherNoiseGen3 = new NoiseGeneratorOctaves(this.hellRNG, 8);
this.noiseGen1 = new NoiseGeneratorOctaves(this.rand, 16);
this.noiseGen2 = new NoiseGeneratorOctaves(this.rand, 16);
this.noiseGen3 = new NoiseGeneratorOctaves(this.rand, 8);
this.noiseGen4 = new NoiseGeneratorOctaves(this.rand, 4);
this.noiseGen5 = new NoiseGeneratorOctaves(this.rand, 10);
this.noiseGen6 = new NoiseGeneratorOctaves(this.rand, 16);
this.slowsandGravelNoiseGen = new NoiseGeneratorOctaves(this.hellRNG, 4);
this.stoneExculsivityNoiseGen = new NoiseGeneratorOctaves(this.hellRNG, 4);
this.netherNoiseGen6 = new NoiseGeneratorOctaves(this.hellRNG, 10);
this.netherNoiseGen7 = new NoiseGeneratorOctaves(this.hellRNG, 16);
}
public void generateNetherTerrain(int par1, int par2, byte[] par3ArrayOfByte)
{
byte byte0 = 4;
byte byte1 = 32;
int i = byte0 + 1;
byte byte2 = 17;
int j = byte0 + 1;
this.field_4163_o = func_4057_a(this.field_4163_o, par1 * byte0, 0, par2 * byte0, i, byte2, j);
for (int k = 0; k < byte0; k++)
{
for (int l = 0; l < byte0; l++)
{
for (int i1 = 0; i1 < 16; i1++)
{
double d = 0.125D;
double d1 = this.field_4163_o[(((k + 0) * j + (l + 0)) * byte2 + (i1 + 0))];
double d2 = this.field_4163_o[(((k + 0) * j + (l + 1)) * byte2 + (i1 + 0))];
double d3 = this.field_4163_o[(((k + 1) * j + (l + 0)) * byte2 + (i1 + 0))];
double d4 = this.field_4163_o[(((k + 1) * j + (l + 1)) * byte2 + (i1 + 0))];
double d5 = (this.field_4163_o[(((k + 0) * j + (l + 0)) * byte2 + (i1 + 1))] - d1) * d;
double d6 = (this.field_4163_o[(((k + 0) * j + (l + 1)) * byte2 + (i1 + 1))] - d2) * d;
double d7 = (this.field_4163_o[(((k + 1) * j + (l + 0)) * byte2 + (i1 + 1))] - d3) * d;
double d8 = (this.field_4163_o[(((k + 1) * j + (l + 1)) * byte2 + (i1 + 1))] - d4) * d;
for (int j1 = 0; j1 < 8; j1++)
{
double d9 = 0.25D;
double d10 = d1;
double d11 = d2;
double d12 = (d3 - d1) * d9;
double d13 = (d4 - d2) * d9;
for (int k1 = 0; k1 < 4; k1++)
{
int l1 = k1 + k * 4 << 11 | 0 + l * 4 << 7 | i1 * 8 + j1;
char c = 128;
double d14 = 0.25D;
double d15 = d10;
double d16 = (d11 - d10) * d14;
for (int i2 = 0; i2 < 4; i2++)
{
int j2 = 0;
if (i1 * 8 + j1 < byte1)
{
j2 = Block.stone.blockID;
}
if (d15 > 0.0D)
{
j2 = Block.stone.blockID;
}
par3ArrayOfByte[l1] = ((byte)j2);
l1 += c;
d15 += d16;
}
d10 += d12;
d11 += d13;
}
d1 += d5;
d2 += d6;
d3 += d7;
d4 += d8;
}
}
}
}
}
public void func_4058_b(int par1, int par2, byte[] par3ArrayOfByte, BiomeGenBase[] par4ArrayOfBiomeGenBase)
{
byte byte0 = 64;
double d = 0.03125D;
this.slowsandNoise = this.slowsandGravelNoiseGen.generateNoiseOctaves(this.slowsandNoise, par1 * 16, par2 * 16, 0, 16, 16, 1, d, d, 1.0D);
this.gravelNoise = this.slowsandGravelNoiseGen.generateNoiseOctaves(this.gravelNoise, par1 * 16, 109, par2 * 16, 16, 1, 16, d, 1.0D, d);
this.stoneExclusivityNoise = this.stoneExculsivityNoiseGen.generateNoiseOctaves(this.stoneExclusivityNoise, par1 * 16, par2 * 16, 0, 16, 16, 1, d * 2.0D, d * 2.0D, d * 2.0D);
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
BiomeGenBase biomegenbase = par4ArrayOfBiomeGenBase[i + j * 16];
boolean flag = this.slowsandNoise[(i + j * 16)] + 10.0D > 0.0D;
boolean flag1 = this.gravelNoise[(i + j * 16)] + 10.0D > 0.0D;
int k = (int)(this.stoneExclusivityNoise[(i + j * 16)] / 3.0D + 3.0D + this.hellRNG.nextDouble() * 0.25D);
int l = -1;
byte byte1 = (byte)Block.stone.blockID;
byte byte2 = (byte)Block.stone.blockID;
for (int i1 = 127; i1 >= 0; i1--)
{
int j1 = (j * 16 + i) * 128 + i1;
if (i1 >= 127 - this.hellRNG.nextInt(5))
{
par3ArrayOfByte[j1] = ((byte)Block.bedrock.blockID);
}
else if (i1 <= 0 + this.hellRNG.nextInt(5))
{
par3ArrayOfByte[j1] = ((byte)Block.bedrock.blockID);
}
else if(i1 >= 1 && i1 <= 35 )
{
par3ArrayOfByte[j1] = ((byte)Block.lavaMoving.blockID);
}
else
{
byte byte3 = par3ArrayOfByte[j1];
if (byte3 == 0)
{
l = -1;
if ((par3ArrayOfByte[j1] == 0) && (par3ArrayOfByte[(j1 - 1)] == Block.stone.blockID))
{
par3ArrayOfByte[(j1 - 1)] = ((byte)Block.stone.blockID);
}
}
else
{
if (l == -1)
{
if (k <= 2)
{
byte1 = (byte)Block.stone.blockID;
byte2 = (byte)Block.stone.blockID;
}
else if ((i1 >= byte0 - 4) && (i1 <= byte0 + 1))
{
byte1 = (byte)Block.stone.blockID;
byte2 = biomegenbase.fillerBlock;//(byte)Block.stone.blockID;
}
if ((i1 < byte0) && (byte1 == 0))
{
byte1 = (byte)Block.stone.blockID;
}
l = k;
if (i1 >= byte0 - 1)
{
par3ArrayOfByte[j1] = byte1;
}
else
{
par3ArrayOfByte[j1] = byte2;
}
}
if (l > 0)
{
l--;
par3ArrayOfByte[j1] = byte2;
}
if ((par3ArrayOfByte[(j1 + 1)] == 0) && (par3ArrayOfByte[j1] == Block.dirt.blockID))
{
par3ArrayOfByte[j1] = ((byte)Block.stone.blockID);
}
}
}
}
}
}
}
public Chunk loadChunk(int par1, int par2) {
return provideChunk(par1, par2);
}
public Chunk provideChunk(int par1, int par2)
{
this.hellRNG.setSeed(par1 * 341873128712L + par2 * 132897987541L);
this.rand.setSeed(par1 * 341873128712L + par2 * 132897987541L);
byte[] abyte0 = new byte[32768];
BiomeGenBase[] abiomegenbase = this.worldObj.getWorldChunkManager().loadBlockGeneratorData(null, par1 * 16, par2 * 16, 16, 16);
generateNetherTerrain(par1, par2, abyte0);
func_4058_b(par1, par2, abyte0, abiomegenbase);
replaceBlocksForBiome(par1, par2, abyte0, abiomegenbase);
this.netherCaveGenerator.generate(this, this.worldObj, par1, par2, abyte0);
Chunk chunk = new Chunk(this.worldObj, abyte0, par1, par2);
byte[] abyte1 = chunk.getBiomeArray();
for (int i = 0; i < abyte1.length; i++)
{
abyte1[i] = ((byte)abiomegenbase[i].biomeID);
}
chunk.resetRelightChecks();
return chunk;
}
private double[] func_4057_a(double[] par1ArrayOfDouble, int par2, int par3, int par4, int par5, int par6, int par7)
{
if (par1ArrayOfDouble == null)
{
par1ArrayOfDouble = new double[par5 * par6 * par7];
}
double d = 684.41200000000003D;
double d1 = 2053.2359999999999D;
this.noiseData4 = this.netherNoiseGen6.generateNoiseOctaves(this.noiseData4, par2, par3, par4, par5, 1, par7, 1.0D, 0.0D, 1.0D);
this.noiseData5 = this.netherNoiseGen7.generateNoiseOctaves(this.noiseData5, par2, par3, par4, par5, 1, par7, 100.0D, 0.0D, 100.0D);
this.noiseData1 = this.netherNoiseGen3.generateNoiseOctaves(this.noiseData1, par2, par3, par4, par5, par6, par7, d / 80.0D, d1 / 60.0D, d / 80.0D);
this.noiseData2 = this.netherNoiseGen1.generateNoiseOctaves(this.noiseData2, par2, par3, par4, par5, par6, par7, d, d1, d);
this.noiseData3 = this.netherNoiseGen2.generateNoiseOctaves(this.noiseData3, par2, par3, par4, par5, par6, par7, d, d1, d);
int i = 0;
int j = 0;
double[] ad = new double[par6];
for (int k = 0; k < par6; k++)
{
ad[k] = (Math.cos(k * 3.141592653589793D * 6.0D / par6) * 2.0D);
double d2 = k;
if (k > par6 / 2)
{
d2 = par6 - 1 - k;
}
if (d2 < 4.0D)
{
d2 = 4.0D - d2;
ad[k] -= d2 * d2 * d2 * 10.0D;
}
}
for (int l = 0; l < par5; l++)
{
for (int i1 = 0; i1 < par7; i1++)
{
double d3 = (this.noiseData4[j] + 256.0D) / 512.0D;
if (d3 > 1.0D)
{
d3 = 1.0D;
}
double d4 = 0.0D;
double d5 = this.noiseData5[j] / 8000.0D;
if (d5 < 0.0D)
{
d5 = -d5;
}
d5 = d5 * 3.0D - 3.0D;
if (d5 < 0.0D)
{
d5 /= 2.0D;
if (d5 < -1.0D)
{
d5 = -1.0D;
}
d5 /= 1.4D;
d5 /= 2.0D;
d3 = 0.0D;
}
else
{
if (d5 > 1.0D)
{
d5 = 1.0D;
}
d5 /= 6.0D;
}
d3 += 0.5D;
d5 = d5 * par6 / 16.0D;
j++;
for (int j1 = 0; j1 < par6; j1++)
{
double d6 = 0.0D;
double d7 = ad[j1];
double d8 = this.noiseData2[i] / 512.0D;
double d9 = this.noiseData3[i] / 512.0D;
double d10 = (this.noiseData1[i] / 10.0D + 1.0D) / 2.0D;
if (d10 < 0.0D)
{
d6 = d8;
}
else if (d10 > 1.0D)
{
d6 = d9;
}
else
{
d6 = d8 + (d9 - d8) * d10;
}
d6 -= d7;
if (j1 > par6 - 4)
{
double d11 = (j1 - (par6 - 4)) / 3.0F;
d6 = d6 * (1.0D - d11) + -10.0D * d11;
}
if (j1 < d4)
{
double d12 = (d4 - j1) / 4.0D;
if (d12 < 0.0D)
{
d12 = 0.0D;
}
if (d12 > 1.0D)
{
d12 = 1.0D;
}
d6 = d6 * (1.0D - d12) + -10.0D * d12;
}
par1ArrayOfDouble[i] = d6;
i++;
}
}
}
return par1ArrayOfDouble;
}
public boolean chunkExists(int par1, int par2)
{
return true;
}
public void populate(IChunkProvider par1IChunkProvider, int par2, int par3)
{
net.minecraft.block.BlockSand.fallInstantly = true;
//this.genSpiderTunnels.generateStructuresInChunk(this.worldObj, this.hellRNG, par2, par3);
int i = par2 * 16;
int j = par3 * 16;
for (int k = 0; k < 20; k++)
{
int i1 = i + this.hellRNG.nextInt(16) + 8;
int k2 = this.hellRNG.nextInt(120) + 4;
int i4 = j + this.hellRNG.nextInt(16) + 8;
new WorldGenTutorialHellLava(Block.waterMoving.blockID, true).generate(this.worldObj, this.hellRNG, i1, k2, i4);
}
int l = this.hellRNG.nextInt(this.hellRNG.nextInt(10) + 1);
BiomeGenBase b = this.worldObj.getBiomeGenForCoords(i, j);
if ((b instanceof BiomeGenBaseTutorial))
{
((BiomeGenBaseTutorial)B).generateTerrain(this.worldObj, this.hellRNG, par1IChunkProvider, i, j);
}
net.minecraft.block.BlockSand.fallInstantly = false;
}
public boolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
{
return true;
}
public boolean unload100OldestChunks()
{
return false;
}
public boolean unloadQueuedChunks()
{
return true;
}
public String d()
{
return "HellRandomLevelSource";
}
public List getPossibleCreatures(EnumCreatureType par1EnumCreatureType, int par2, int par3, int par4)
{
BiomeGenBase var5 = this.worldObj.getBiomeGenForCoords(par2, par4);
return var5 == null ? null : var5.getSpawnableList(par1EnumCreatureType);
}
public ChunkPosition findClosestStructure(World par1World, String par2Str, int par3, int i, int j)
{
return null;
}
public int e()
{
return 0;
}
public void replaceBlocksForBiome(int par1, int par2, byte[] par3ArrayOfByte, BiomeGenBase[] par4ArrayOfBiomeGenBase)
{
ChunkProviderEvent.ReplaceBiomeBlocks event = new ChunkProviderEvent.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 z = 0; z < 16; ++z)
{
for (int x = 0; x < 16; ++x)
{
BiomeGenBase biomegenbase = par4ArrayOfBiomeGenBase[x + z * 16];
int stoneDepth = (int)(this.stoneNoise[z + x * 16] / 3.0D + 3.0D + this.rand.nextDouble() * 0.25D);
int sandstoneDepth = -1;
byte top = biomegenbase.topBlock;
byte filler = biomegenbase.fillerBlock;
for (int y = 127; y >= 0; --y)
{
int index = (x * 16 + z) * 128 + y;
byte blockID = par3ArrayOfByte[index];
if (blockID == 0)
{
sandstoneDepth = -1;
}
else if (blockID == Block.stone.blockID)
{
if (sandstoneDepth == -1)
{
if (stoneDepth <= 0)
{
top = 0;
filler = (byte)Block.stone.blockID;
}
sandstoneDepth = stoneDepth;
if (y >= 0)
{
par3ArrayOfByte[index] = biomegenbase.topBlock;
} else {
par3ArrayOfByte[index] = biomegenbase.fillerBlock;
}
} else if (sandstoneDepth > 0)
{
--sandstoneDepth;
par3ArrayOfByte[index] = filler;
if (sandstoneDepth == 0 && filler == Block.sand.blockID)
{
sandstoneDepth = this.rand.nextInt(4);
filler = (byte)Block.sandStone.blockID;
}
}
}
}
}
}
}
@Override
public boolean canSave() {
// TODO Auto-generated method stub
return false;
}
@Override
public String makeString() {
// TODO Auto-generated method stub
return null;
}
@Override
public int getLoadedChunkCount() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void recreateStructures(int i, int j) {
// TODO Auto-generated method stub
}
@Override
public void func_104112_b() {
// TODO Auto-generated method stub
}
}
See if you can take the regular ChunkProviderHell and manipulate it to change top blocks, that's what I've been trying to do for weeks. Great find on that one! You should add this to your tutorial page
As for making multiple biomes for the nether check out this great tutorial by Jimmy04creeper: http://www.minecraftforum.net/topic/1797143-152-forge-dimension-tutorial-multi-biome-dimension-tutorial-ore-generation-basic-house-gen-in-dimension-tree-generation/
The multi-biome dimension tutorial will be on page 15.
They use the same chunk provider you say? Interesting! That gave me an idea.. I know all about the replceBlocksForBiome method, problem is, I can't get it to work in the Nether :/
Also, I'm actually messaging jimmy on this very issue. (replacing biome blocks in the Nether that is) I've sent him the source code for a mod that has this feature to see if he could figure out what makes it tick. I've spent countless hours trying to figure this out, believe me. But, his dimension tutorial is great, I've tried it recently I just need to get this working before I can start implementing that
Have you registered your own world provider to the Nether dimension? If you haven't you can do it like this:
In your init method in your main mod class add this line:
This will unlink the WorldProviderHell from the Nether dimension, whose dimension ID is -1 (overworld is 0 and the End is 1). Once this is done you will have to link your own world provider like so:
You will have to create your own world provider and chunk provider classes, but they can be duplicates of WorldProviderHell and ChunkProviderHell respectively. You would only have to change the world provider's chunk provider variable and then the desired replacement blocks in your chunk provider, but after that you should be all set.
Let me get this straight,
Would this make it so I would be able to use my own chunk provider AND world provider, still have the dimension ID as -1, and still have the nether portal send me to the new nether? Kind of like overriding the whole dimension with my new classes? Or would it just be the world provider? Also, how does this enable the biome-specific replacement of top and filler blocks?
Yes yes I know, I'm just doing this for learning purposes so I can implement it WITHOUT changing base classes later
My method does not change vanilla code, although I admit completely replacing the world provider is a bit extreme. However, I do know of one mod that for certain does this too (which would make your mod incompatible with unless you develop some other kind of work around): Biomes O' Plenty.
Yes
It doesn't inherently. If you were just to make a duplicate of the default hell chunk provider to use as your own, you would not have the code necessary to take into account top and filler blocks, as the Nether only has one biome, and doesn't have a 'top' to speak of. Now you could modify your chunk provider to adopt some of the surface's chunk provider's code that allows the use of top and filler block which is available in the 'replaceBlocksForBiome' method.
I've tried this in several different ways, no luck anywhere unfortunately :c
It's cool man
Alright, so I deobfuscated and decompiled a mod that does nether-style world gen and uses top and filler blocks, and used the chunk provider from there. It was a success, however, it also replaces lava with top and filler blocks at the bottom of the world. I think I can fix that, but, I still would like to use my own class instead of copying someone else's. I can paste the chunk provider here if you'd like to look at it. I still can't figure out what makes it work. I did find one odd thing, there's two replace biome block methods in this chunk provider.
Ok, some of the stuff that you guys have been bouncing back and forth is confusing me with all these chunk manager / provider things, so I'm just going to throw at you a world gen code of mine which replaces netherrack
DISCLAIMER: I made this mod for Minecraft 1.4.6. I hope too much hasn't changed, but sorry if it has
Go ahead and find the WorldGenMineable file (package net.minecraft.world.gen.feature). Very close to the bottom of the page, you'll find this
More importantly:
block != null && block.isGenMineableReplaceable(par1World, k2, l2, i3, field_94523_c)
In other words, Minecraft is checking if the place where an ore is going to be is GenMineableReplaceable. We know that Stone is where ore spawns, so GenMineableReplaceable is completely synonymous with "is Stone"
So to Hell with that code (literally) because we replace it with:
block != null && block == Block.netherrack)
and now when you're creating your ore generation file, you ask for the WorldGenNether instead of the WorldGenMineable code (I haven't worked with worldgen in a while so I don't remember exactly how it goes, but if you've already got an overworld ore working then this will be easy)
You can have my entire WorldGenNether file if you want it, but you'll have to change the package declaration etc.
Author's Note: Some of what I said may have sounded condescending. Sorry bout that. I just dont like it when people try to help me but they think I already know everything and they dont help at all, so I tried to be very complete in my explanation.
EDIT: I didn't want to leave you hanging and I felt bad for being lazy and closing it there, so I've gone and found my nether ore code. I've cut out most of the crap you don't need:
Don't forget to register your generator in your mod_ file
-Voussoir
@Voussoir - Its great that you found a way to do what you wanted in a way that you understand, but there was a simpler way.
I want to point you to the 'generateNetherTerrain' method in the ChunkProviderHell class. In that method there is this portion of code:
I've commented the code which you need to notice. All you had to do, Voussior, was change the netherrack block ID to whichever one you want. Of course, understand that you would need to do what I suggested in a previous post to make your own world provider and chunk provider as changes to base vanilla code will cause mod incompatibility.
Okay, I'm going to be a bit clearer on what I need here. I don't need explanations on how to change netherrack to something else. Here's a picture, column of blocks on the left is what it generates like now, on the right is how I want it to generate. As you can see, I want top blocks in the nether.
And here's the chunk provider, because for some reason it wouldn't let me put it in a code or spoiler box:
https://www.dropbox.com/s/86sv0w0t8qd6chh/ChunkProviderUndergroundJungle.java
It's from a mod called the Erebus. It's also UTF-8 text encoding, so if you use it, make sure you change that in file>properties on eclipse.
Thanks, but unfortunately I don't need to just replace netherrack. :c See last two posts by me ^
With x, y, and z being the current block coords you are comparing, you check the block above it to see if it is air.
If that returns true and the block is netherrack then replace the block:
A problem I can see immediately is that depending on the order world gens occur, this will also replace the floor blocks in caves if the caves are generated first.
Where would I put this? In the chunk provider?
See if you can take the regular ChunkProviderHell and manipulate it to change top blocks, that's what I've been trying to do for weeks. Great find on that one! You should add this to your tutorial page