BiomesOPlenty/src/main/java/biomesoplenty/common/world/ChunkProviderGenerateBOP.java

642 lines
29 KiB
Java

/*******************************************************************************
* Copyright 2014-2016, the Biomes O' Plenty Team
*
* This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License.
*
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/.
******************************************************************************/
package biomesoplenty.common.world;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.CAVE;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.MINESHAFT;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.OCEAN_MONUMENT;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.RAVINE;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.SCATTERED_FEATURE;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.STRONGHOLD;
import static net.minecraftforge.event.terraingen.InitMapGenEvent.EventType.VILLAGE;
import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.ANIMALS;
import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.DUNGEON;
import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.ICE;
import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.LAKE;
import static net.minecraftforge.event.terraingen.PopulateChunkEvent.Populate.EventType.LAVA;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import biomesoplenty.common.biome.overworld.BOPBiome;
import biomesoplenty.common.util.biome.BiomeUtils;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.init.Biomes;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldEntitySpawner;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkPrimer;
import net.minecraft.world.chunk.IChunkGenerator;
import net.minecraft.world.gen.MapGenBase;
import net.minecraft.world.gen.MapGenCaves;
import net.minecraft.world.gen.MapGenRavine;
import net.minecraft.world.gen.NoiseGeneratorOctaves;
import net.minecraft.world.gen.NoiseGeneratorPerlin;
import net.minecraft.world.gen.feature.WorldGenDungeons;
import net.minecraft.world.gen.feature.WorldGenLakes;
import net.minecraft.world.gen.structure.MapGenMineshaft;
import net.minecraft.world.gen.structure.MapGenScatteredFeature;
import net.minecraft.world.gen.structure.MapGenStronghold;
import net.minecraft.world.gen.structure.MapGenVillage;
import net.minecraft.world.gen.structure.StructureOceanMonument;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.terraingen.PopulateChunkEvent;
import net.minecraftforge.event.terraingen.TerrainGen;
public class ChunkProviderGenerateBOP implements IChunkGenerator
{
private Random rand;
private NoiseGeneratorOctaves xyzNoiseGenA;
private NoiseGeneratorOctaves xyzNoiseGenB;
private NoiseGeneratorOctaves xyzBalanceNoiseGen;
private NoiseGeneratorPerlin stoneNoiseGen;
public NoiseGeneratorBOPByte byteNoiseGen;
private World worldObj;
private final boolean mapFeaturesEnabled;
private BOPWorldSettings settings;
private IBlockState seaBlockState;
private IBlockState stoneBlockState;
private MapGenBase caveGenerator;
private MapGenStronghold strongholdGenerator;
private MapGenVillage villageGenerator;
private MapGenMineshaft mineshaftGenerator;
private MapGenScatteredFeature scatteredFeatureGenerator;
private MapGenBase ravineGenerator;
private StructureOceanMonument oceanMonumentGenerator;
private double[] xyzBalanceNoiseArray;
private double[] xyzNoiseArrayA;
private double[] xyzNoiseArrayB;
private double[] stoneNoiseArray;
private final double[] noiseArray;
private Map<Biome, TerrainSettings> biomeTerrainSettings;
public ChunkProviderGenerateBOP(World worldIn, long seed, boolean mapFeaturesEnabled, String chunkProviderSettingsString)
{
System.out.println("ChunkProviderGenerateBOP json: "+chunkProviderSettingsString);
this.worldObj = worldIn;
this.mapFeaturesEnabled = mapFeaturesEnabled;
this.rand = new Random(seed);
this.settings = new BOPWorldSettings(chunkProviderSettingsString);
System.out.println("ChunkProviderGenerateBOP settings: "+this.settings.toJson());
// set up structure generators (overridable by forge)
this.caveGenerator = TerrainGen.getModdedMapGen(new MapGenCaves(), CAVE);
this.strongholdGenerator = (MapGenStronghold)TerrainGen.getModdedMapGen(new MapGenStronghold(), STRONGHOLD);
this.villageGenerator = (MapGenVillage)TerrainGen.getModdedMapGen(new MapGenVillage(), VILLAGE);
this.mineshaftGenerator = (MapGenMineshaft)TerrainGen.getModdedMapGen(new MapGenMineshaft(), MINESHAFT);
this.scatteredFeatureGenerator = (MapGenScatteredFeature)TerrainGen.getModdedMapGen(new MapGenScatteredFeature(), SCATTERED_FEATURE);
this.ravineGenerator = TerrainGen.getModdedMapGen(new MapGenRavine(), RAVINE);
this.oceanMonumentGenerator = (StructureOceanMonument)TerrainGen.getModdedMapGen(new StructureOceanMonument(), OCEAN_MONUMENT);
// set up the noise generators
this.xyzNoiseGenA = new NoiseGeneratorOctaves(this.rand, 16);
this.xyzNoiseGenB = new NoiseGeneratorOctaves(this.rand, 16);
this.xyzBalanceNoiseGen = new NoiseGeneratorOctaves(this.rand, 8);
this.stoneNoiseGen = new NoiseGeneratorPerlin(this.rand, 4);
this.byteNoiseGen = new NoiseGeneratorBOPByte(this.rand, 6, 5, 5); // 6 octaves, 5x5 xz grid
this.stoneNoiseArray = new double[256];
this.noiseArray = new double[825];
// blockstates for stone and sea blocks
this.stoneBlockState = Blocks.STONE.getDefaultState();
this.seaBlockState = Blocks.WATER.getDefaultState();
// store a TerrainSettings object for each biome
this.biomeTerrainSettings = new HashMap<Biome, TerrainSettings>();
for (Biome biome : BiomeUtils.getRegisteredBiomes())
{
if (biome == null) {continue;}
this.biomeTerrainSettings.put(biome, (biome instanceof BOPBiome) ? ((BOPBiome)biome).terrainSettings : TerrainSettings.forVanillaBiome(biome));
}
}
@Override
public Chunk provideChunk(int chunkX, int chunkZ)
{
// initialize the random generator using the chunk coordinates
this.rand.setSeed((long)chunkX * 341873128712L + (long)chunkZ * 132897987541L);
// create the primer
ChunkPrimer chunkprimer = new ChunkPrimer();
// start off by adding the basic terrain shape with air stone and water blocks
this.setChunkAirStoneWater(chunkX, chunkZ, chunkprimer);
// hand over to the biomes for them to set bedrock grass and dirt
Biome[] biomes = this.worldObj.getBiomeProvider().getBiomes(null, chunkX * 16, chunkZ * 16, 16, 16);
this.replaceBlocksForBiome(chunkX, chunkZ, chunkprimer, biomes);
// add structures
if (this.settings.useCaves)
{
this.caveGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
if (this.settings.useRavines)
{
this.ravineGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
if (this.settings.useMineShafts && this.mapFeaturesEnabled)
{
this.mineshaftGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
if (this.settings.useVillages && this.mapFeaturesEnabled)
{
this.villageGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
if (this.settings.useStrongholds && this.mapFeaturesEnabled)
{
this.strongholdGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
if (this.settings.useTemples && this.mapFeaturesEnabled)
{
this.scatteredFeatureGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
if (this.settings.useMonuments && this.mapFeaturesEnabled)
{
this.oceanMonumentGenerator.generate(this.worldObj, chunkX, chunkZ, chunkprimer);
}
// create and return the chunk
Chunk chunk = new Chunk(this.worldObj, chunkprimer, chunkX, chunkZ);
byte[] chunkBiomes = chunk.getBiomeArray();
for (int k = 0; k < chunkBiomes.length; ++k)
{
chunkBiomes[k] = (byte)Biome.getIdForBiome(biomes[k]);
}
chunk.generateSkylightMap();
return chunk;
}
public void setChunkAirStoneWater(int chunkX, int chunkZ, ChunkPrimer primer)
{
// get noise values for the whole chunk
this.populateNoiseArray(chunkX, chunkZ);
double oneEighth = 0.125D;
double oneQuarter = 0.25D;
// entire chunk is 16x256x16
// process chunk in subchunks, each one 4x8x4 blocks in size
// 4 subchunks in x direction, each 4 blocks long
// 32 subchunks in y direction, each 8 blocks long
// 4 subchunks in z direction, each 4 blocks long
// for a total of 512 subchunks
// divide chunk into 4 subchunks in x direction, index as ix
for (int ix = 0; ix < 4; ++ix)
{
int k_x0 = ix * 5;
int k_x1 = (ix + 1) * 5;
// divide chunk into 4 subchunks in z direction, index as iz
for (int iz = 0; iz < 4; ++iz)
{
int k_x0z0 = (k_x0 + iz) * 33;
int k_x0z1 = (k_x0 + iz + 1) * 33;
int k_x1z0 = (k_x1 + iz) * 33;
int k_x1z1 = (k_x1 + iz + 1) * 33;
// divide chunk into 32 subchunks in y direction, index as iy
for (int iy = 0; iy < 32; ++iy)
{
// get the noise values from the noise array
// these are the values at the corners of the subchunk
double n_x0y0z0 = this.noiseArray[k_x0z0 + iy];
double n_x0y0z1 = this.noiseArray[k_x0z1 + iy];
double n_x1y0z0 = this.noiseArray[k_x1z0 + iy];
double n_x1y0z1 = this.noiseArray[k_x1z1 + iy];
double n_x0y1z0 = this.noiseArray[k_x0z0 + iy + 1];
double n_x0y1z1 = this.noiseArray[k_x0z1 + iy + 1];
double n_x1y1z0 = this.noiseArray[k_x1z0 + iy + 1];
double n_x1y1z1 = this.noiseArray[k_x1z1 + iy + 1];
// linearly interpolate between the noise points to get a noise value for each block in the subchunk
double noiseStepY00 = (n_x0y1z0 - n_x0y0z0) * oneEighth;
double noiseStepY01 = (n_x0y1z1 - n_x0y0z1) * oneEighth;
double noiseStepY10 = (n_x1y1z0 - n_x1y0z0) * oneEighth;
double noiseStepY11 = (n_x1y1z1 - n_x1y0z1) * oneEighth;
double noiseStartX0 = n_x0y0z0;
double noiseStartX1 = n_x0y0z1;
double noiseEndX0 = n_x1y0z0;
double noiseEndX1 = n_x1y0z1;
// subchunk is 8 blocks high in y direction, index as jy
for (int jy = 0; jy < 8; ++jy)
{
double noiseStartZ = noiseStartX0;
double noiseEndZ = noiseStartX1;
double noiseStepX0 = (noiseEndX0 - noiseStartX0) * oneQuarter;
double noiseStepX1 = (noiseEndX1 - noiseStartX1) * oneQuarter;
// subchunk is 4 blocks long in x direction, index as jx
for (int jx = 0; jx < 4; ++jx)
{
double noiseStepZ = (noiseEndZ - noiseStartZ) * oneQuarter;
double noiseVal = noiseStartZ;
// subchunk is 4 blocks long in x direction, index as jz
for (int jz = 0; jz < 4; ++jz)
{
// If the noise value is above zero, this block starts as stone
// Otherwise it's 'empty' - air above sealevel and water below it
if (noiseVal > 0.0D)
{
primer.setBlockState(ix * 4 + jx, iy * 8 + jy, iz * 4 + jz, this.stoneBlockState);
}
else if (iy * 8 + jy < this.settings.seaLevel)
{
primer.setBlockState(ix * 4 + jx, iy * 8 + jy, iz * 4 + jz, this.seaBlockState);
}
noiseVal += noiseStepZ;
}
noiseStartZ += noiseStepX0;
noiseEndZ += noiseStepX1;
}
noiseStartX0 += noiseStepY00;
noiseStartX1 += noiseStepY01;
noiseEndX0 += noiseStepY10;
noiseEndX1 += noiseStepY11;
}
}
}
}
}
// Biomes add their top blocks and filler blocks to the primer here
public void replaceBlocksForBiome(int chunkX, int chunkZ, ChunkPrimer primer, Biome[] biomes)
{
if (!net.minecraftforge.event.ForgeEventFactory.onReplaceBiomeBlocks(this, chunkX, chunkZ, primer, this.worldObj)) return;
double d0 = 0.03125D;
this.stoneNoiseArray = this.stoneNoiseGen.getRegion(this.stoneNoiseArray, (double)(chunkX * 16), (double)(chunkZ * 16), 16, 16, d0 * 2.0D, d0 * 2.0D, 1.0D);
for (int localX = 0; localX < 16; ++localX)
{
for (int localZ = 0; localZ < 16; ++localZ)
{
Biome biome = biomes[localZ + localX * 16];
biome.genTerrainBlocks(this.worldObj, this.rand, primer, chunkX * 16 + localX, chunkZ * 16 + localZ, this.stoneNoiseArray[localZ + localX * 16]);
}
}
}
// a 5x5 bell-shaped curve which can be multiplied over to quickly get a weighted average with a radial falloff - the constant was chosen so that it sums to 1
private static float[] radialFalloff5x5 = new float[25];
// similar to the above but falls off faster, so giving stronger weight to the center item
private static float[] radialStrongFalloff5x5 = new float[25];
static {
for (int j = -2; j <= 2; ++j)
{
for (int k = -2; k <= 2; ++k)
{
radialFalloff5x5[j + 2 + (k + 2) * 5] = 0.06476162171F / MathHelper.sqrt_float((float)(j * j + k * k) + 0.2F);
radialStrongFalloff5x5[j + 2 + (k + 2) * 5] = 0.076160519601F / ((float)(j * j + k * k) + 0.2F);
}
}
}
private TerrainSettings getWeightedTerrainSettings(int localX, int localZ, Biome[] biomes)
{
// Rivers shouldn't be influenced by the neighbors
Biome centerBiome = biomes[localX + 2 + (localZ + 2) * 10];
if (centerBiome == Biomes.RIVER || centerBiome == Biomes.FROZEN_RIVER || ((centerBiome instanceof BOPBiome) && ((BOPBiome)centerBiome).noNeighborTerrainInfuence))
{
return this.biomeTerrainSettings.get(centerBiome);
}
// Otherwise, get weighted average of properties from this and surrounding biomes
TerrainSettings settings = new TerrainSettings();
for (int i = -2; i <= 2; ++i)
{
for (int j = -2; j <= 2; ++j)
{
float weight = radialFalloff5x5[i + 2 + (j + 2) * 5];
TerrainSettings biomeSettings = this.biomeTerrainSettings.get(biomes[localX + i + 2 + (localZ + j + 2) * 10]);
if (biomeSettings != null)
{
settings.avgHeight += weight * biomeSettings.avgHeight;
settings.variationAbove += weight * biomeSettings.variationAbove;
settings.variationBelow += weight * biomeSettings.variationBelow;
settings.minHeight += weight * biomeSettings.minHeight;
settings.maxHeight += weight * biomeSettings.maxHeight;
settings.sidewaysNoiseAmount += weight * biomeSettings.sidewaysNoiseAmount;
for (int k = 0; k < settings.octaveWeights.length; k++)
{
settings.octaveWeights[k] += weight * biomeSettings.octaveWeights[k];
}
}
}
}
return settings;
}
private void populateNoiseArray(int chunkX, int chunkZ)
{
Biome[] biomes = this.worldObj.getBiomeProvider().getBiomesForGeneration(null, chunkX * 4 - 2, chunkZ * 4 - 2, 10, 10);
// values from vanilla
float coordinateScale = this.settings.coordinateScale;
float heightScale = this.settings.heightScale;
double upperLimitScale = this.settings.upperLimitScale;
double lowerLimitScale = this.settings.lowerLimitScale;
float mainNoiseScaleX = this.settings.mainNoiseScaleX;
float mainNoiseScaleY = this.settings.mainNoiseScaleY;
float mainNoiseScaleZ = this.settings.mainNoiseScaleZ;
int subchunkX = chunkX * 4;
int subchunkY = 0;
int subchunkZ = chunkZ * 4;
// generate the xz noise for the chunk
this.byteNoiseGen.generateNoise(subchunkX, subchunkZ);
// generate the xyz noise for the chunk
this.xyzBalanceNoiseArray = this.xyzBalanceNoiseGen.generateNoiseOctaves(this.xyzBalanceNoiseArray, subchunkX, subchunkY, subchunkZ, 5, 33, 5, (double)(coordinateScale / mainNoiseScaleX), (double)(heightScale / mainNoiseScaleY), (double)(coordinateScale / mainNoiseScaleZ));
this.xyzNoiseArrayA = this.xyzNoiseGenA.generateNoiseOctaves(this.xyzNoiseArrayA, subchunkX, subchunkY, subchunkZ, 5, 33, 5, (double)coordinateScale, (double)heightScale, (double)coordinateScale);
this.xyzNoiseArrayB = this.xyzNoiseGenB.generateNoiseOctaves(this.xyzNoiseArrayB, subchunkX, subchunkY, subchunkZ, 5, 33, 5, (double)coordinateScale, (double)heightScale, (double)coordinateScale);
// loop over the subchunks and calculate the overall noise value
int xyzCounter = 0;
int xzCounter = 0;
for (int ix = 0; ix < 5; ++ix)
{
for (int iz = 0; iz < 5; ++iz)
{
// get the terrain settings to use for this subchunk as a weighted average of the settings from the nearby biomes
TerrainSettings settings = this.getWeightedTerrainSettings(ix, iz, biomes);
// get the xz noise value
double xzNoiseVal = this.byteNoiseGen.getWeightedDouble(xzCounter, settings.octaveWeights);
// get the amplitudes
double xzAmplitude = this.settings.amplitude * (xzNoiseVal < 0 ? settings.variationBelow : settings.variationAbove) * (1 - settings.sidewaysNoiseAmount);
double xyzAmplitude = this.settings.amplitude * (xzNoiseVal < 0 ? settings.variationBelow : settings.variationAbove) * (settings.sidewaysNoiseAmount);
// the 'base level' is the average height, plus the height from the xz noise
double baseLevel = settings.avgHeight + (xzNoiseVal * xzAmplitude);
for (int iy = 0; iy < 33; ++iy)
{
int y = iy * 8;
if (y < settings.minHeight)
{
this.noiseArray[xyzCounter] = settings.minHeight - y;
}
else if (y > settings.maxHeight)
{
this.noiseArray[xyzCounter] = settings.maxHeight - y;
}
else
{
// calculate the xzy noise value
double xyzNoiseA = this.xyzNoiseArrayA[xyzCounter] / lowerLimitScale;
double xyzNoiseB = this.xyzNoiseArrayB[xyzCounter] / upperLimitScale;
double balance = (this.xyzBalanceNoiseArray[xyzCounter] / 10.0D + 1.0D) / 2.0D;
double xyzNoiseValue = MathHelper.denormalizeClamp(xyzNoiseA, xyzNoiseB, balance) / 50.0D;
// calculate the depth
double depth = baseLevel - y + (xyzAmplitude * xyzNoiseValue);
// make the noiseVal decrease sharply when we're close to the top of the chunk
// guarantees value of -10 at iy=32, so that there is always some air at the top
if (iy > 29)
{
double closeToTopOfChunkFactor = (double)((float)(iy - 29) / 3.0F); // 1/3, 2/3 or 1
depth = depth * (1.0D - closeToTopOfChunkFactor) + -10.0D * closeToTopOfChunkFactor;
}
this.noiseArray[xyzCounter] = depth;
}
++xyzCounter;
}
xzCounter++;
}
}
}
@Override
public void populate(int chunkX, int chunkZ)
{
BlockFalling.fallInstantly = true;
int x = chunkX * 16;
int z = chunkZ * 16;
BlockPos blockpos = new BlockPos(x, 0, z);
Biome Biome = this.worldObj.getBiome(blockpos.add(16, 0, 16));
this.rand.setSeed(this.worldObj.getSeed());
long l0 = this.rand.nextLong() / 2L * 2L + 1L;
long l1 = this.rand.nextLong() / 2L * 2L + 1L;
this.rand.setSeed((long)chunkX * l0 + (long)chunkZ * l1 ^ this.worldObj.getSeed());
boolean hasVillageGenerated = false;
ChunkPos chunkcoordintpair = new ChunkPos(chunkX, chunkZ);
MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Pre(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated));
// populate the structures
if (this.settings.useMineShafts && this.mapFeaturesEnabled)
{
this.mineshaftGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
}
if (this.settings.useVillages && this.mapFeaturesEnabled)
{
hasVillageGenerated = this.villageGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
}
if (this.settings.useStrongholds && this.mapFeaturesEnabled)
{
this.strongholdGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
}
if (this.settings.useTemples && this.mapFeaturesEnabled)
{
this.scatteredFeatureGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
}
if (this.settings.useMonuments && this.mapFeaturesEnabled)
{
this.oceanMonumentGenerator.generateStructure(this.worldObj, this.rand, chunkcoordintpair);
}
BlockPos decorateStart = blockpos.add(8, 0, 8);
BlockPos target;
// add water lakes
if (Biome.getRainfall() > 0.01F && Biome != Biomes.DESERT && Biome != Biomes.DESERT_HILLS && this.settings.useWaterLakes && !hasVillageGenerated && this.rand.nextInt(this.settings.waterLakeChance) == 0 && TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated, LAKE))
{
target = decorateStart.add(this.rand.nextInt(16), this.rand.nextInt(256), this.rand.nextInt(16));
(new WorldGenLakes(Blocks.WATER)).generate(this.worldObj, this.rand, target);
}
// add lava lakes
if (TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated, LAVA) && !hasVillageGenerated && this.rand.nextInt(this.settings.lavaLakeChance / 10) == 0 && this.settings.useLavaLakes)
{
target = decorateStart.add(this.rand.nextInt(16), this.rand.nextInt(248) + 8, this.rand.nextInt(16));
if (target.getY() < 63 || this.rand.nextInt(this.settings.lavaLakeChance / 8) == 0)
{
(new WorldGenLakes(Blocks.LAVA)).generate(this.worldObj, this.rand, target);
}
}
// add dungeons
if (this.settings.useDungeons && TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated, DUNGEON))
{
for (int i = 0; i < this.settings.dungeonChance; ++i)
{
target = decorateStart.add(this.rand.nextInt(16), this.rand.nextInt(256), this.rand.nextInt(16));
(new WorldGenDungeons()).generate(this.worldObj, this.rand, target);
}
}
// hand over to the biome to decorate itself
Biome.decorate(this.worldObj, this.rand, new BlockPos(x, 0, z));
// add animals
if (TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated, ANIMALS))
{
WorldEntitySpawner.performWorldGenSpawning(this.worldObj, Biome, x + 8, z + 8, 16, 16, this.rand);
}
// add ice and snow
if (TerrainGen.populate(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated, ICE))
{
for (int i = 0; i < 16; ++i)
{
for (int j = 0; j < 16; ++j)
{
target = this.worldObj.getPrecipitationHeight(decorateStart.add(i, 0, j));
Biome biome = this.worldObj.getBiome(target);
// if it's cold enough for ice, and there's exposed water, then freeze it
if (this.worldObj.canBlockFreezeWater(target.down()))
{
this.worldObj.setBlockState(target.down(), Blocks.ICE.getDefaultState(), 2);
}
// if it's cold enough for snow, add a layer of snow
if (biome.getRainfall() > 0.01F && this.worldObj.canSnowAt(target, true))
{
this.worldObj.setBlockState(target, Blocks.SNOW_LAYER.getDefaultState(), 2);
}
}
}
}
MinecraftForge.EVENT_BUS.post(new PopulateChunkEvent.Post(this, worldObj, rand, chunkX, chunkZ, hasVillageGenerated));
BlockFalling.fallInstantly = false;
}
@Override
public boolean generateStructures(Chunk chunkIn, int x, int z)
{
boolean flag = false;
if (this.settings.useMonuments && this.mapFeaturesEnabled && chunkIn.getInhabitedTime() < 3600L)
{
flag |= this.oceanMonumentGenerator.generateStructure(this.worldObj, this.rand, new ChunkPos(x, z));
}
return flag;
}
@Override
public List<Biome.SpawnListEntry> getPossibleCreatures(EnumCreatureType creatureType, BlockPos pos)
{
Biome Biome = this.worldObj.getBiome(pos);
if (this.mapFeaturesEnabled)
{
if (creatureType == EnumCreatureType.MONSTER && this.scatteredFeatureGenerator.isSwampHut(pos))
{
return this.scatteredFeatureGenerator.getScatteredFeatureSpawnList();
}
if (creatureType == EnumCreatureType.MONSTER && this.settings.useMonuments && this.oceanMonumentGenerator.isPositionInStructure(this.worldObj, pos))
{
return this.oceanMonumentGenerator.getScatteredFeatureSpawnList();
}
}
return Biome.getSpawnableList(creatureType);
}
@Override
public BlockPos getStrongholdGen(World worldIn, String structureName, BlockPos position)
{
return "Stronghold".equals(structureName) && this.strongholdGenerator != null ? this.strongholdGenerator.getClosestStrongholdPos(worldIn, position) : null;
}
@Override
public void recreateStructures(Chunk p_180514_1_, int p_180514_2_, int p_180514_3_)
{
if (this.settings.useMineShafts && this.mapFeaturesEnabled)
{
this.mineshaftGenerator.generate(this.worldObj, p_180514_2_, p_180514_3_, (ChunkPrimer)null);
}
if (this.settings.useVillages && this.mapFeaturesEnabled)
{
this.villageGenerator.generate(this.worldObj, p_180514_2_, p_180514_3_, (ChunkPrimer)null);
}
if (this.settings.useStrongholds && this.mapFeaturesEnabled)
{
this.strongholdGenerator.generate(this.worldObj, p_180514_2_, p_180514_3_, (ChunkPrimer)null);
}
if (this.settings.useTemples && this.mapFeaturesEnabled)
{
this.scatteredFeatureGenerator.generate(this.worldObj, p_180514_2_, p_180514_3_, (ChunkPrimer)null);
}
if (this.settings.useMonuments && this.mapFeaturesEnabled)
{
this.oceanMonumentGenerator.generate(this.worldObj, p_180514_2_, p_180514_3_, (ChunkPrimer)null);
}
}
}