package micdoodle8.mods.galacticraft.planets.asteroids.world.gen;
import micdoodle8.mods.galacticraft.api.vector.BlockVec3;
import micdoodle8.mods.galacticraft.core.GCBlocks;
import micdoodle8.mods.galacticraft.core.perlin.NoiseModule;
import micdoodle8.mods.galacticraft.core.perlin.generator.Billowed;
import micdoodle8.mods.galacticraft.core.perlin.generator.Gradient;
import micdoodle8.mods.galacticraft.core.util.ConfigManagerCore;
import micdoodle8.mods.galacticraft.planets.asteroids.ConfigManagerAsteroids;
import micdoodle8.mods.galacticraft.planets.asteroids.blocks.AsteroidBlocks;
import micdoodle8.mods.galacticraft.planets.asteroids.dimension.WorldProviderAsteroids;
import micdoodle8.mods.galacticraft.planets.asteroids.world.gen.base.MapGenAbandonedBase;
import net.minecraft.block.*;
import net.minecraft.block.BlockFlower.EnumFlowerType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.util.IProgressUpdate;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkPrimer;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderGenerate;
import net.minecraft.world.gen.feature.WorldGenFlowers;
import net.minecraft.world.gen.feature.WorldGenLakes;
import net.minecraft.world.gen.feature.WorldGenTallGrass;
import net.minecraft.world.gen.feature.WorldGenTrees;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
public class ChunkProviderAsteroids extends ChunkProviderGenerate
{
final Block ASTEROID_STONE = AsteroidBlocks.blockBasic;
final byte ASTEROID_STONE_META_0 = 0;
final byte ASTEROID_STONE_META_1 = 1;
final byte ASTEROID_STONE_META_2 = 2;
final Block DIRT = Blocks.dirt;
final byte DIRT_META = 0;
final Block GRASS = Blocks.grass;
final byte GRASS_META = 0;
final Block LIGHT = Blocks.glowstone;
final byte LIGHT_META = 0;
BlockTallGrass.EnumType GRASS_TYPE = BlockTallGrass.EnumType.GRASS;
final BlockFlower FLOWER = Blocks.red_flower;
final Block LAVA = Blocks.lava;
final byte LAVA_META = 0;
final Block WATER = Blocks.water;
final byte WATER_META = 0;
private final Random rand;
private final World worldObj;
private final NoiseModule asteroidDensity;
private final NoiseModule asteroidTurbulance;
private final NoiseModule asteroidSkewX;
private final NoiseModule asteroidSkewY;
private final NoiseModule asteroidSkewZ;
private final SpecialAsteroidBlockHandler coreHandler;
private final SpecialAsteroidBlockHandler shellHandler;
// DO NOT CHANGE
private static final int CHUNK_SIZE_X = 16;
private static final int CHUNK_SIZE_Y = 256;
private static final int CHUNK_SIZE_Z = 16;
private static final int MAX_ASTEROID_RADIUS = 25;
private static final int MIN_ASTEROID_RADIUS = 5;
private static final int MAX_ASTEROID_SKEW = 8;
private static final int MIN_ASTEROID_Y = 48;
private static final int MAX_ASTEROID_Y = ChunkProviderAsteroids.CHUNK_SIZE_Y - 48;
private static final int ASTEROID_CHANCE = 800; //About 1 / n chance per XZ pair
private static final int ASTEROID_CORE_CHANCE = 2; //1 / n chance per asteroid
private static final int ASTEROID_SHELL_CHANCE = 2; //1 / n chance per asteroid
private static final int MIN_BLOCKS_PER_CHUNK = 50;
private static final int MAX_BLOCKS_PER_CHUNK = 200;
private static final int ILMENITE_CHANCE = 400;
private static final int IRON_CHANCE = 300;
private static final int ALUMINUM_CHANCE = 250;
private static final int RANDOM_BLOCK_FADE_SIZE = 32;
private static final int FADE_BLOCK_CHANCE = 5; //1 / n chance of a block being in the fade zone
private static final int NOISE_OFFSET_SIZE = 256;
private static final float MIN_HOLLOW_SIZE = .6F;
private static final float MAX_HOLLOW_SIZE = .8F;
private static final int HOLLOW_CHANCE = 10; //1 / n chance per asteroid
private static final int MIN_RADIUS_FOR_HOLLOW = 15;
private static final float HOLLOW_LAVA_SIZE = .12F;
//Per chunk per asteroid
private static final int TREE_CHANCE = 2;
private static final int TALL_GRASS_CHANCE = 2;
private static final int FLOWER_CHANCE = 2;
private static final int WATER_CHANCE = 2;
private static final int LAVA_CHANCE = 2;
private static final int GLOWSTONE_CHANCE = 20;
private ArrayList<AsteroidData> largeAsteroids = new ArrayList<AsteroidData>();
private int largeCount = 0;
private static HashSet<BlockVec3> chunksDone = new HashSet<BlockVec3>();
private int largeAsteroidsLastChunkX;
private int largeAsteroidsLastChunkZ;
private final MapGenAbandonedBase dungeonGenerator = new MapGenAbandonedBase();
public ChunkProviderAsteroids(World par1World, long par2, boolean par4)
{
super(par1World, par2, par4, "");
this.worldObj = par1World;
this.rand = new Random(par2);
this.asteroidDensity = new Billowed(this.rand.nextLong(), 2, .25F);
this.asteroidDensity.setFrequency(.009F);
this.asteroidDensity.amplitude = .6F;
this.asteroidTurbulance = new Gradient(this.rand.nextLong(), 1, .2F);
this.asteroidTurbulance.setFrequency(.08F);
this.asteroidTurbulance.amplitude = .5F;
this.asteroidSkewX = new Gradient(this.rand.nextLong(), 1, 1);
this.asteroidSkewX.amplitude = ChunkProviderAsteroids.MAX_ASTEROID_SKEW;
this.asteroidSkewX.frequencyX = 0.005F;
this.asteroidSkewY = new Gradient(this.rand.nextLong(), 1, 1);
this.asteroidSkewY.amplitude = ChunkProviderAsteroids.MAX_ASTEROID_SKEW;
this.asteroidSkewY.frequencyY = 0.005F;
this.asteroidSkewZ = new Gradient(this.rand.nextLong(), 1, 1);
this.asteroidSkewZ.amplitude = ChunkProviderAsteroids.MAX_ASTEROID_SKEW;
this.asteroidSkewZ.frequencyZ = 0.005F;
this.coreHandler = new SpecialAsteroidBlockHandler();
this.coreHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, this.ASTEROID_STONE_META_2, 5, .3));
this.coreHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, this.ASTEROID_STONE_META_1, 7, .3));
this.coreHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, this.ASTEROID_STONE_META_0, 11, .25));
if (!ConfigManagerAsteroids.disableAluminumGen)
this.coreHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, (byte) 3, 5, .2));
if (!ConfigManagerAsteroids.disableIlmeniteGen)
this.coreHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, (byte) 4, 4, .15));
if (!ConfigManagerAsteroids.disableIronGen)
this.coreHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, (byte) 5, 3, .2));
if (ConfigManagerCore.enableSiliconOreGen)
this.coreHandler.addBlock(new SpecialAsteroidBlock(GCBlocks.basicBlock, (byte) 8, 2, .15)); //TODO: Asteroids version of silicon ore
//Solid Meteoric Iron - has no config to disable
this.coreHandler.addBlock(new SpecialAsteroidBlock(GCBlocks.basicBlock, (byte) 12, 2, .13));
//Diamond ore - has no config to disable
this.coreHandler.addBlock(new SpecialAsteroidBlock(Blocks.diamond_ore, (byte) 0, 1, .1)); //TODO: Asteroids version of diamond ore
this.shellHandler = new SpecialAsteroidBlockHandler();
this.shellHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, this.ASTEROID_STONE_META_0, 1, .15));
this.shellHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, this.ASTEROID_STONE_META_1, 3, .15));
this.shellHandler.addBlock(new SpecialAsteroidBlock(this.ASTEROID_STONE, this.ASTEROID_STONE_META_2, 1, .15));
this.shellHandler.addBlock(new SpecialAsteroidBlock(AsteroidBlocks.blockDenseIce, (byte) 0, 1, .15));
}
public void generateTerrain(int chunkX, int chunkZ, ChunkPrimer primer, boolean flagDataOnly)
{
this.largeAsteroids.clear();
this.largeCount = 0;
final Random random = new Random();
final int asteroidChance = ChunkProviderAsteroids.ASTEROID_CHANCE;
final int rangeY = ChunkProviderAsteroids.MAX_ASTEROID_Y - ChunkProviderAsteroids.MIN_ASTEROID_Y;
final int rangeSize = ChunkProviderAsteroids.MAX_ASTEROID_RADIUS - ChunkProviderAsteroids.MIN_ASTEROID_RADIUS;
//If there is an asteroid centre nearby, it might need to generate some asteroid parts in this chunk
for (int i = chunkX - 3; i < chunkX + 3; i++)
{
int minX = i * 16;
int maxX = minX + ChunkProviderAsteroids.CHUNK_SIZE_X;
for (int k = chunkZ - 3; k < chunkZ + 3; k++)
{
int minZ = k * 16;
int maxZ = minZ + ChunkProviderAsteroids.CHUNK_SIZE_Z;
//NOTE: IF UPDATING THIS CODE also update addLargeAsteroids() which is the same algorithm
//??? ^^ this now seems redundant
for (int x = minX; x < maxX; x += 2)
{
for (int z = minZ; z < maxZ; z += 2)
{
//The next line is called 3136 times per chunk generated. getNoise is a little slow.
if (this.randFromPointPos(x, z) < (this.asteroidDensity.getNoise(x, z) + .4) / asteroidChance)
{
random.setSeed(x + z * 3067);
int y = random.nextInt(rangeY) + ChunkProviderAsteroids.MIN_ASTEROID_Y;
int size = random.nextInt(rangeSize) + ChunkProviderAsteroids.MIN_ASTEROID_RADIUS;
//Generate the parts of the asteroid which are in this chunk
this.generateAsteroid(random, x, y, z, chunkX << 4, chunkZ << 4, size, primer, flagDataOnly);
this.largeCount++;
}
}
}
}
}
}
private void generateAsteroid(Random rand, int asteroidX, int asteroidY, int asteroidZ, int chunkX, int chunkZ, int size, ChunkPrimer primer, boolean flagDataOnly)
{
SpecialAsteroidBlock core = this.coreHandler.getBlock(rand, size);
SpecialAsteroidBlock shell = null;
if (rand.nextInt(ChunkProviderAsteroids.ASTEROID_SHELL_CHANCE) == 0)
{
shell = this.shellHandler.getBlock(rand, size);
}
boolean isHollow = false;
final float hollowSize = rand.nextFloat() * (ChunkProviderAsteroids.MAX_HOLLOW_SIZE - ChunkProviderAsteroids.MIN_HOLLOW_SIZE) + ChunkProviderAsteroids.MIN_HOLLOW_SIZE;
if (rand.nextInt(ChunkProviderAsteroids.HOLLOW_CHANCE) == 0 && size >= ChunkProviderAsteroids.MIN_RADIUS_FOR_HOLLOW)
{
isHollow = true;
shell = new SpecialAsteroidBlock(AsteroidBlocks.blockDenseIce, (byte) 0, 1, .15);
}
//Add to the list of asteroids for external use
((WorldProviderAsteroids) this.worldObj.provider).addAsteroid(asteroidX, asteroidY, asteroidZ, size, isHollow ? -1 : core.index);
final int xMin = this.clamp(Math.max(chunkX, asteroidX - size - ChunkProviderAsteroids.MAX_ASTEROID_SKEW - 2) - chunkX, 0, 16);
final int zMin = this.clamp(Math.max(chunkZ, asteroidZ - size - ChunkProviderAsteroids.MAX_ASTEROID_SKEW - 2) - chunkZ, 0, 16);
final int yMin = asteroidY - size - ChunkProviderAsteroids.MAX_ASTEROID_SKEW - 2;
final int yMax = asteroidY + size + ChunkProviderAsteroids.MAX_ASTEROID_SKEW + 2;
final int xMax = this.clamp(Math.min(chunkX + 16, asteroidX + size + ChunkProviderAsteroids.MAX_ASTEROID_SKEW + 2) - chunkX, 0, 16);
final int zMax = this.clamp(Math.min(chunkZ + 16, asteroidZ + size + ChunkProviderAsteroids.MAX_ASTEROID_SKEW + 2) - chunkZ, 0, 16);
final int xSize = xMax - xMin;
final int ySize = yMax - yMin;
final int zSize = zMax - zMin;
if (xSize <= 0 || ySize <= 0 || zSize <= 0)
{
return;
}
final float noiseOffsetX = this.randFromPoint(asteroidX, asteroidY, asteroidZ) * ChunkProviderAsteroids.NOISE_OFFSET_SIZE + chunkX;
final float noiseOffsetY = this.randFromPoint(asteroidX * 7, asteroidY * 11, asteroidZ * 13) * ChunkProviderAsteroids.NOISE_OFFSET_SIZE;
final float noiseOffsetZ = this.randFromPoint(asteroidX * 17, asteroidY * 23, asteroidZ * 29) * ChunkProviderAsteroids.NOISE_OFFSET_SIZE + chunkZ;
this.setOtherAxisFrequency(1F / (size * 2F / 2F));
float[] sizeXArray = new float[ySize * zSize];
float[] sizeZArray = new float[xSize * ySize];
float[] sizeYArray = new float[xSize * zSize];
for (int x = 0; x < xSize; x++)
{
int xx = x * zSize;
float xxx = x + noiseOffsetX;
for (int z = 0; z < zSize; z++)
{
sizeYArray[xx + z] = this.asteroidSkewY.getNoise(xxx, z + noiseOffsetZ);
}
}
AsteroidData asteroidData = new AsteroidData(isHollow, sizeYArray, xMin, zMin, xMax, zMax, zSize, size, asteroidX, asteroidY, asteroidZ);
this.largeAsteroids.add(asteroidData);
this.largeAsteroidsLastChunkX = chunkX;
this.largeAsteroidsLastChunkZ = chunkZ;
if (flagDataOnly)
{
return;
}
for (int y = 0; y < ySize; y++)
{
int yy = y * zSize;
float yyy = y + noiseOffsetY;
for (int z = 0; z < zSize; z++)
{
sizeXArray[yy + z] = this.asteroidSkewX.getNoise(yyy, z + noiseOffsetZ);
}
}
for (int x = 0; x < xSize; x++)
{
int xx = x * ySize;
float xxx = x + noiseOffsetX;
for (int y = 0; y < ySize; y++)
{
sizeZArray[xx + y] = this.asteroidSkewZ.getNoise(xxx, y + noiseOffsetY);
}
}
double shellThickness = 0;
int terrainY = 0;
int terrainYY = 0;
IBlockState asteroidShell = null;
if (shell != null)
{
asteroidShell = shell.block.getStateFromMeta(shell.meta);
shellThickness = 1.0 - shell.thickness;
}
IBlockState asteroidCore = core.block.getStateFromMeta(core.meta);
IBlockState asteroidRock0 = this.ASTEROID_STONE.getStateFromMeta(this.ASTEROID_STONE_META_0);
IBlockState asteroidRock1 = this.ASTEROID_STONE.getStateFromMeta(this.ASTEROID_STONE_META_1);
IBlockState airBlock = Blocks.air.getDefaultState();
IBlockState dirtBlock = this.DIRT.getStateFromMeta(this.DIRT_META);
IBlockState grassBlock = this.GRASS.getStateFromMeta(this.GRASS_META);
for (int x = xMax - 1; x >= xMin; x--)
{
int indexXY = (x - xMin) * ySize - yMin;
int indexXZ = (x - xMin) * zSize - zMin;
int distanceX = asteroidX - (x + chunkX);
int indexBaseX = x * ChunkProviderAsteroids.CHUNK_SIZE_Y << 4;
float xx = x + chunkX;
for (int z = zMin; z < zMax; z++)
{
if (isHollow)
{
float sizeModY = sizeYArray[indexXZ + z];
terrainY = this.getTerrainHeightFor(sizeModY, asteroidY, size);
terrainYY = this.getTerrainHeightFor(sizeModY, asteroidY - 1, size);
}
float sizeY = size + sizeYArray[indexXZ + z];
sizeY *= sizeY;
int distanceZ = asteroidZ - (z + chunkZ);
int indexBase = indexBaseX | z * ChunkProviderAsteroids.CHUNK_SIZE_Y;
float zz = z + chunkZ;
for (int y = yMin; y < yMax; y++)
{
float dSizeX = distanceX / (size + sizeXArray[(y - yMin) * zSize + z - zMin]);
float dSizeZ = distanceZ / (size + sizeZArray[indexXY + y]);
dSizeX *= dSizeX;
dSizeZ *= dSizeZ;
int distanceY = asteroidY - y;
distanceY *= distanceY;
float distance = dSizeX + distanceY / sizeY + dSizeZ;
float distanceAbove = distance;
distance += this.asteroidTurbulance.getNoise(xx, y, zz);
if (isHollow && distance <= hollowSize)
{
distanceAbove += this.asteroidTurbulance.getNoise(xx, y + 1, zz);
if (distanceAbove <= 1)
{
if ((y - 1) == terrainYY)
{
int index = indexBase | (y + 1);
primer.setBlockState(index, this.LIGHT.getStateFromMeta(this.LIGHT_META));
// blockArray[index] = this.LIGHT;
// metaArray[index] = this.LIGHT_META;
}
}
}
if (distance <= 1)
{
int index = indexBase | y;
if (isHollow && distance <= hollowSize)
{
if (y == terrainY)
{
primer.setBlockState(index, grassBlock);
// blockArray[index] = this.GRASS;
// metaArray[index] = this.GRASS_META;
}
else if (y < terrainY)
{
primer.setBlockState(index, dirtBlock);
// blockArray[index] = this.DIRT;
// metaArray[index] = this.DIRT_META;
}
else
{
primer.setBlockState(index, airBlock);
// blockArray[index] = Blocks.air;
// metaArray[index] = 0;
}
}
else if (distance <= core.thickness)
{
if (rand.nextBoolean())
{
primer.setBlockState(index, asteroidCore);
// blockArray[index] = core.block;
// metaArray[index] = core.meta;
}
else
{
primer.setBlockState(index, asteroidRock0);
// blockArray[index] = this.ASTEROID_STONE;
// metaArray[index] = this.ASTEROID_STONE_META_0;
}
}
else if (shell != null && distance >= shellThickness)
{
primer.setBlockState(index, asteroidShell);
// blockArray[index] = shell.block;
// metaArray[index] = shell.meta;
}
else
{
primer.setBlockState(index, asteroidRock1);
// blockArray[index] = this.ASTEROID_STONE;
// metaArray[index] = this.ASTEROID_STONE_META_1;
}
}
}
}
}
if (isHollow)
{
shellThickness = 0;
if (shell != null)
{
shellThickness = 1.0 - shell.thickness;
}
for (int x = xMin; x < xMax; x++)
{
int indexXY = (x - xMin) * ySize - yMin;
int indexXZ = (x - xMin) * zSize - zMin;
int distanceX = asteroidX - (x + chunkX);
distanceX *= distanceX;
int indexBaseX = x * ChunkProviderAsteroids.CHUNK_SIZE_Y << 4;
for (int z = zMin; z < zMax; z++)
{
float sizeModY = sizeYArray[indexXZ + z];
float sizeY = size + sizeYArray[indexXZ + z];
sizeY *= sizeY;
int distanceZ = asteroidZ - (z + chunkZ);
distanceZ *= distanceZ;
int indexBase = indexBaseX | z * ChunkProviderAsteroids.CHUNK_SIZE_Y;
for (int y = yMin; y < yMax; y++)
{
float sizeX = size + sizeXArray[(y - yMin) * zSize + z - zMin];
float sizeZ = size + sizeZArray[indexXY + y];
sizeX *= sizeX;
sizeZ *= sizeZ;
int distanceY = asteroidY - y;
distanceY *= distanceY;
float distance = distanceX / sizeX + distanceY / sizeY + distanceZ / sizeZ;
distance += this.asteroidTurbulance.getNoise(x + chunkX, y, z + chunkZ);
if (distance <= 1)
{
int index = indexBase | y;
int indexAbove = indexBase | (y + 1);
IBlockState state = primer.getBlockState(index);
IBlockState stateAbove = primer.getBlockState(indexAbove);
if (Blocks.air == stateAbove.getBlock() && (state.getBlock() == ASTEROID_STONE || state.getBlock() == GRASS))
{
if (this.rand.nextInt(GLOWSTONE_CHANCE) == 0)
{
primer.setBlockState(index, this.LIGHT.getStateFromMeta(this.LIGHT_META));
// blockArray[index] = this.LIGHT;
// metaArray[index] = this.LIGHT_META;
}
}
}
}
}
}
}
}
private final void setOtherAxisFrequency(float frequency)
{
this.asteroidSkewX.frequencyY = frequency;
this.asteroidSkewX.frequencyZ = frequency;
this.asteroidSkewY.frequencyX = frequency;
this.asteroidSkewY.frequencyZ = frequency;
this.asteroidSkewZ.frequencyX = frequency;
this.asteroidSkewZ.frequencyY = frequency;
}
private final int clamp(int x, int min, int max)
{
if (x < min)
{
x = min;
}
else if (x > max)
{
x = max;
}
return x;
}
private final double clamp(double x, double min, double max)
{
if (x < min)
{
x = min;
}
else if (x > max)
{
x = max;
}
return x;
}
private final int getTerrainHeightFor(float yMod, int asteroidY, int asteroidSize)
{
return (int) (asteroidY - asteroidSize / 4 + yMod * 1.5F);
}
private final int getTerrainHeightAt(int x, int z, float[] yModArray, int xMin, int zMin, int zSize, int asteroidY, int asteroidSize)
{
final int index = (x - xMin) * zSize - zMin;
if (index < yModArray.length && index >= 0)
{
final float yMod = yModArray[index];
return this.getTerrainHeightFor(yMod, asteroidY, asteroidSize);
}
return 1;
}
@Override
public Chunk provideChunk(int par1, int par2)
{
ChunkPrimer primer = new ChunkPrimer();
// long time1 = System.nanoTime();
this.rand.setSeed(par1 * 341873128712L + par2 * 132897987541L);
// final Block[] ids = new Block[65536];
// final byte[] meta = new byte[65536];
this.generateTerrain(par1, par2, primer, false);
//this.biomesForGeneration = this.worldObj.getWorldChunkManager().loadBlockGeneratorData(this.biomesForGeneration, par1 * 16, par2 * 16, 16, 16);
this.dungeonGenerator.generate(this, this.worldObj, par1, par2, primer);
// long time2 = System.nanoTime();
final Chunk var4 = new Chunk(this.worldObj, primer, par1, par2);
final byte[] var5 = var4.getBiomeArray();
for (int var6 = 0; var6 < var5.length; ++var6)
{
var5[var6] = (byte) BiomeGenBaseAsteroids.asteroid.biomeID;
}
// long time3 = System.nanoTime();
this.generateSkylightMap(var4, par1, par2);
// long time4 = System.nanoTime();
// if (ConfigManagerCore.enableDebug)
// {
// BlockVec3 vec = new BlockVec3(par1, par2, 0);
// if (chunksDone.contains(vec)) System.out.println("Done chunk already at "+par1+","+par2);
// else chunksDone.add(vec);
// System.out.println("Chunk gen: " + timeString(time1, time4) + " at "+par1+","+par2 + " - L"+this.largeCount+ " H"+this.largeAsteroids.size()+ " Terrain:"+timeString(time1, time2)+ " Biomes:"+timeString(time2,time3)+ " Light:"+timeString(time3, time4));
// }
return var4;
}
private int getIndex(int x, int y, int z)
{
return x * ChunkProviderAsteroids.CHUNK_SIZE_Y * 16 | z * ChunkProviderAsteroids.CHUNK_SIZE_Y | y;
}
private String timeString(long time1, long time2)
{
int ms100 = (int) ((time2 - time1) / 10000);
int msdecimal = ms100 % 100;
String msd = ((ms100 < 10) ? "0" : "") + ms100;
return "" + ms100 / 100 + "." + msd + "ms";
}
private float randFromPoint(int x, int y, int z)
{
int n = x + z * 57 + y * 571;
n ^= n << 13;
n = n * (n * n * 15731 + 789221) + 1376312589 & 0x7fffffff;
return 1.0F - n / 1073741824.0F;
}
private float randFromPoint(int x, int z)
{
int n = x + z * 57;
n ^= n << 13;
n = n * (n * n * 15731 + 789221) + 1376312589 & 0x7fffffff;
return 1.0F - n / 1073741824.0F;
}
private float randFromPointPos(int x, int z)
{
int n = x + z * 57;
n ^= n << 13;
n = n * (n * n * 15731 + 789221) + 1376312589 & 0x3fffffff;
return 1.0F - n / 1073741824.0F;
}
@Override
public boolean chunkExists(int par1, int par2)
{
return true;
}
@Override
public void populate(IChunkProvider par1IChunkProvider, int chunkX, int chunkZ)
{
int x = chunkX << 4;
int z = chunkZ << 4;
if (!ChunkProviderAsteroids.chunksDone.add(new BlockVec3(x, 0, z)))
{
return;
}
BlockFalling.fallInstantly = true;
this.worldObj.getBiomeGenForCoords(new BlockPos(x + 16, 0, z + 16));
BlockFalling.fallInstantly = false;
this.rand.setSeed(this.worldObj.getSeed());
long var7 = this.rand.nextLong() / 2L * 2L + 1L;
long var9 = this.rand.nextLong() / 2L * 2L + 1L;
this.rand.setSeed(chunkX * var7 + chunkZ * var9 ^ this.worldObj.getSeed());
//50:50 chance to include small blocks each chunk
if (this.rand.nextBoolean())
{
double density = this.asteroidDensity.getNoise(chunkX * 16, chunkZ * 16) * 0.54;
double numOfBlocks = this.clamp(this.randFromPoint(chunkX, chunkZ), .4, 1) * ChunkProviderAsteroids.MAX_BLOCKS_PER_CHUNK * density + ChunkProviderAsteroids.MIN_BLOCKS_PER_CHUNK;
int y0 = this.rand.nextInt(2);
Block block;
int meta;
int yRange = ChunkProviderAsteroids.MAX_ASTEROID_Y - ChunkProviderAsteroids.MIN_ASTEROID_Y;
for (int i = 0; i < numOfBlocks; i++)
{
int y = this.rand.nextInt(yRange) + ChunkProviderAsteroids.MIN_ASTEROID_Y;
//50:50 chance vertically as well
if (y0 == (y / 16) % 2)
{
int px = x + this.rand.nextInt(ChunkProviderAsteroids.CHUNK_SIZE_X);
int pz = z + this.rand.nextInt(ChunkProviderAsteroids.CHUNK_SIZE_Z);
block = this.ASTEROID_STONE;
meta = this.ASTEROID_STONE_META_1;
if (this.rand.nextInt(ILMENITE_CHANCE) == 0)
{
meta = 4;
if (ConfigManagerAsteroids.disableIlmeniteGen)
{
continue;
}
}
else if (this.rand.nextInt(IRON_CHANCE) == 0)
{
meta = 5;
if (ConfigManagerAsteroids.disableIronGen)
{
continue;
}
}
else if (this.rand.nextInt(ALUMINUM_CHANCE) == 0)
{
meta = 3;
if (ConfigManagerAsteroids.disableAluminumGen)
{
continue;
}
}
worldObj.setBlockState(new BlockPos(px, y, pz), block.getStateFromMeta(meta), 2);
int count = 9;
if (!(worldObj.getBlockState(new BlockPos(px - 1, y, pz)).getBlock() instanceof BlockAir))
{
count = 1;
}
else if (!(worldObj.getBlockState(new BlockPos(px - 2, y, pz)).getBlock() instanceof BlockAir))
{
count = 3;
}
else if (!(worldObj.getBlockState(new BlockPos(px - 3, y, pz)).getBlock() instanceof BlockAir))
{
count = 5;
}
else if (!(worldObj.getBlockState(new BlockPos(px - 4, y, pz)).getBlock() instanceof BlockAir))
{
count = 7;
}
//LIGHTEMP worldObj.setLightFor(EnumSkyBlock.BLOCK, new BlockPos(px - (count > 1 ? 1 : 0), y, pz), count);
}
}
}
if (this.largeAsteroidsLastChunkX != chunkX || this.largeAsteroidsLastChunkZ != chunkZ)
{
this.generateTerrain(chunkX, chunkZ, null, true);
}
this.rand.setSeed(chunkX * var7 + chunkZ * var9 ^ this.worldObj.getSeed());
//Look for hollow asteroids to populate
if (!this.largeAsteroids.isEmpty())
{
for (AsteroidData asteroidIndex : this.largeAsteroids)
{
if (!asteroidIndex.isHollow)
{
continue;
}
float[] sizeYArray = asteroidIndex.sizeYArray;
int xMin = asteroidIndex.xMinArray;
int zMin = asteroidIndex.zMinArray;
int zSize = asteroidIndex.zSizeArray;
int asteroidY = asteroidIndex.asteroidYArray;
int asteroidSize = asteroidIndex.asteroidSizeArray;
boolean treesdone = false;
if(ConfigManagerCore.challengeMode || ConfigManagerCore.challengeAsteroidPopulation || rand.nextInt(ChunkProviderAsteroids.TREE_CHANCE) == 0)
{
int treeType = rand.nextInt(3);
if (treeType == 1)
{
treeType = 0;
}
IBlockState log = Blocks.log.getDefaultState().withProperty(BlockOldLog.VARIANT, BlockPlanks.EnumType.OAK);
IBlockState leaves = Blocks.leaves.getDefaultState().withProperty(BlockOldLeaf.VARIANT, BlockPlanks.EnumType.OAK).withProperty(BlockLeaves.CHECK_DECAY, Boolean.valueOf(false));
WorldGenTrees wg = new WorldGenTrees(false, 2, log, leaves, false);
for (int tries = 0; tries < 5; tries++)
{
int i = rand.nextInt(16) + x + 8;
int k = rand.nextInt(16) + z + 8;
if (wg.generate(worldObj, rand, new BlockPos(i, this.getTerrainHeightAt(i - x, k - z, sizeYArray, xMin, zMin, zSize, asteroidY, asteroidSize), k)))
{
break;
}
}
treesdone = true;
}
if (!treesdone || rand.nextInt(ChunkProviderAsteroids.TALL_GRASS_CHANCE) == 0)
{
int i = rand.nextInt(16) + x + 8;
int k = rand.nextInt(16) + z + 8;
new WorldGenTallGrass(GRASS_TYPE).generate(worldObj, rand, new BlockPos(i, this.getTerrainHeightAt(i - x, k - z, sizeYArray, xMin, zMin, zSize, asteroidY, asteroidSize), k));
}
if (rand.nextInt(ChunkProviderAsteroids.FLOWER_CHANCE) == 0)
{
int i = rand.nextInt(16) + x + 8;
int k = rand.nextInt(16) + z + 8;
int[] types = new int[]{2, 4, 5, 7};
new WorldGenFlowers(this.FLOWER, EnumFlowerType.getType(BlockFlower.EnumFlowerColor.RED, types[rand.nextInt(types.length)])).generate(worldObj, rand, new BlockPos(i, this.getTerrainHeightAt(i - x, k - z, sizeYArray, xMin, zMin, zSize, asteroidY, asteroidSize), k));
}
if (rand.nextInt(ChunkProviderAsteroids.LAVA_CHANCE) == 0)
{
int i = rand.nextInt(16) + x + 8;
int k = rand.nextInt(16) + z + 8;
new WorldGenLakes(this.LAVA).generate(worldObj, rand, new BlockPos(i, this.getTerrainHeightAt(i - x, k - z, sizeYArray, xMin, zMin, zSize, asteroidY, asteroidSize), k));
}
if (rand.nextInt(ChunkProviderAsteroids.WATER_CHANCE) == 0)
{
int i = rand.nextInt(16) + x + 8;
int k = rand.nextInt(16) + z + 8;
new WorldGenLakes(this.WATER).generate(worldObj, rand, new BlockPos(i, this.getTerrainHeightAt(i - x, k - z, sizeYArray, xMin, zMin, zSize, asteroidY, asteroidSize), k));
}
}
}
//Update all block lighting
for (int xx = 0; xx < 16; xx++)
{
int xPos = x + xx;
for (int zz = 0; zz < 16; zz++)
{
int zPos = z + zz;
//Asteroid at min height 48, size 20, can't have lit blocks below 16
for (int y = 16; y < 240; y++)
{
//LIGHTTEMP worldObj.checkLightFor(EnumSkyBlock.BLOCK, new BlockPos(xPos, y, zPos));
}
}
}
this.dungeonGenerator.generateStructure(this.worldObj, this.rand, new ChunkCoordIntPair(chunkX, chunkZ));
}
@Override
public void recreateStructures(Chunk chunk, int x, int z)
{
this.dungeonGenerator.generate(this, this.worldObj, x, z, null);
}
public void generateSkylightMap(Chunk chunk, int cx, int cz)
{
World w = chunk.getWorld();
boolean flagXChunk = w.getChunkProvider().chunkExists(cx - 1, cz);
boolean flagZUChunk = w.getChunkProvider().chunkExists(cx, cz + 1);
boolean flagZDChunk = w.getChunkProvider().chunkExists(cx, cz - 1);
boolean flagXZUChunk = w.getChunkProvider().chunkExists(cx - 1, cz + 1);
boolean flagXZDChunk = w.getChunkProvider().chunkExists(cx - 1, cz - 1);
for (int j = 0; j < 16; j++)
{
if (chunk.getBlockStorageArray()[j] == null)
{
chunk.getBlockStorageArray()[j] = new ExtendedBlockStorage(j << 4, false);
}
}
int i = chunk.getTopFilledSegment();
chunk.heightMapMinimum = Integer.MAX_VALUE;
for (int j = 0; j < 16; ++j)
{
int k = 0;
while (k < 16)
{
chunk.precipitationHeightMap[j + (k << 4)] = -999;
int y = i + 15;
while (true)
{
if (y > 0)
{
if (chunk.getBlockLightOpacity(new BlockPos(j, y - 1, k)) == 0)
{
--y;
continue;
}
chunk.heightMap[k << 4 | j] = y;
if (y < chunk.heightMapMinimum)
{
chunk.heightMapMinimum = y;
}
}
++k;
break;
}
}
}
for (AsteroidData a : this.largeAsteroids)
{
int yMin = a.asteroidYArray - a.asteroidSizeArray;
int yMax = a.asteroidYArray + a.asteroidSizeArray;
int xMin = a.xMinArray;
if (yMin < 0)
{
yMin = 0;
}
if (yMax > 255)
{
yMax = 255;
}
if (xMin == 0)
{
xMin = 1;
}
for (int x = a.xMax - 1; x >= xMin; x--)
{
for (int z = a.zMinArray; z < a.zMax; z++)
{
for (int y = yMin; y < yMax; y++)
{
if (chunk.getBlock(x - 1, y, z) instanceof BlockAir && !(chunk.getBlock(x, y, z) instanceof BlockAir))
{
int count = 2;
if (x > 1)
{
if ((chunk.getBlock(x - 2, y, z) instanceof BlockAir))
{
count += 2;
}
}
if (x > 2)
{
if ((chunk.getBlock(x - 3, y, z) instanceof BlockAir))
{
count += 2;
}
if ((chunk.getBlock(x - 3, y + 1, z) instanceof BlockAir))
{
count++;
}
if ((chunk.getBlock(x - 3, y + 1, z) instanceof BlockAir))
{
count++;
}
if ((z > 0 /*|| ((xPos & 15) > 2 ? flagZDChunk : flagXZDChunk)*/) && (chunk.getBlock(x - 3, y, z - 1) instanceof BlockAir))
{
count++;
}
if ((z < 15/* || ((xPos & 15) > 2 ? flagZUChunk : flagXZUChunk)*/) && (chunk.getBlock(x - 3, y, z + 1) instanceof BlockAir))
{
count++;
}
}
if (/*flagXChunk || */x > 3)
{
if ((chunk.getBlock(x - 4, y, z) instanceof BlockAir))
{
count += 2;
}
if ((chunk.getBlock(x - 4, y + 1, z) instanceof BlockAir))
{
count++;
}
if ((chunk.getBlock(x - 4, y + 1, z) instanceof BlockAir))
{
count++;
}
if ((z > 0/* || ((xPos & 15) > 3 ? flagZDChunk : flagXZDChunk)*/) && !(chunk.getBlock(x - 4, y, z - 1) instanceof BlockAir))
{
count++;
}
if ((z < 15/* || ((xPos & 15) > 3 ? flagZUChunk : flagXZUChunk)*/) && !(chunk.getBlock(x - 4, y, z + 1) instanceof BlockAir))
{
count++;
}
}
if (count > 12)
{
count = 12;
}
if (count > 12) count = 12;
chunk.setBlockState(new BlockPos(x - 1, y, z), GCBlocks.brightAir.getStateFromMeta(13 - count));
ExtendedBlockStorage extendedblockstorage = chunk.getBlockStorageArray()[y >> 4];
if (extendedblockstorage != null)
{
extendedblockstorage.setExtBlocklightValue(x - 1, y & 15, z, count + 2);
}
}
}
}
}
}
chunk.isModified = true;
}
public void resetBase()
{
this.dungeonGenerator.reset();
}
@Override
public boolean saveChunks(boolean par1, IProgressUpdate par2IProgressUpdate)
{
return true;
}
@Override
public boolean canSave()
{
return true;
}
@Override
public String makeString()
{
return "RandomLevelSource";
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public List<BiomeGenBase.SpawnListEntry> getPossibleCreatures(EnumCreatureType creatureType, BlockPos pos)
{
if (creatureType == EnumCreatureType.MONSTER)
{
return BiomeGenBaseAsteroids.asteroid.getSpawnableList(creatureType);
}
else
{
return null;
}
}
/**
* Whether a large asteroid is located the provided coordinates
*
* @param x0 X-Coordinate to check, in Block Coords
* @param z0 Z-Coordinate to check, in Block Coords
* @return True if large asteroid is located here, False if not
*/
public BlockVec3 isLargeAsteroidAt(int x0, int z0)
{
int xToCheck;
int zToCheck;
for (int i0 = 0; i0 <= 32; i0++)
{
for (int i1 = -i0; i1 <= i0; i1++)
{
xToCheck = (x0 >> 4) + i0;
zToCheck = (z0 >> 4) + i1;
if (isLargeAsteroidAt0(xToCheck * 16, zToCheck * 16))
{
return new BlockVec3(xToCheck * 16, 0, zToCheck * 16);
}
xToCheck = (x0 >> 4) + i0;
zToCheck = (z0 >> 4) - i1;
if (isLargeAsteroidAt0(xToCheck * 16, zToCheck * 16))
{
return new BlockVec3(xToCheck * 16, 0, zToCheck * 16);
}
xToCheck = (x0 >> 4) - i0;
zToCheck = (z0 >> 4) + i1;
if (isLargeAsteroidAt0(xToCheck * 16, zToCheck * 16))
{
return new BlockVec3(xToCheck * 16, 0, zToCheck * 16);
}
xToCheck = (x0 >> 4) - i0;
zToCheck = (z0 >> 4) - i1;
if (isLargeAsteroidAt0(xToCheck * 16, zToCheck * 16))
{
return new BlockVec3(xToCheck * 16, 0, zToCheck * 16);
}
}
}
return null;
}
private boolean isLargeAsteroidAt0(int x0, int z0)
{
for (int x = x0; x < x0 + ChunkProviderAsteroids.CHUNK_SIZE_X; x += 2)
{
for (int z = z0; z < z0 + ChunkProviderAsteroids.CHUNK_SIZE_Z; z += 2)
{
if ((Math.abs(this.randFromPoint(x, z)) < (this.asteroidDensity.getNoise(x, z) + .4) / ChunkProviderAsteroids.ASTEROID_CHANCE))
{
return true;
}
}
}
return false;
}
public static void reset()
{
chunksDone.clear();
}
private class AsteroidData
{
public boolean isHollow;
public float[] sizeYArray;
public int xMinArray;
public int zMinArray;
public int xMax;
public int zMax;
public int zSizeArray;
public int asteroidSizeArray;
public int asteroidXArray;
public int asteroidYArray;
public int asteroidZArray;
public AsteroidData(boolean hollow, float[] sizeYArray2, int xMin, int zMin, int xmax, int zmax, int zSize, int size, int asteroidX, int asteroidY, int asteroidZ)
{
this.isHollow = hollow;
this.sizeYArray = sizeYArray2.clone();
this.xMinArray = xMin;
this.zMinArray = zMin;
this.xMax = xmax;
this.zMax = zmax;
this.zSizeArray = zSize;
this.asteroidSizeArray = size;
this.asteroidXArray = asteroidX;
this.asteroidYArray = asteroidY;
this.asteroidZArray = asteroidZ;
}
}
}