blob: f0f0c4045f35d5cbac2a0b2962c65d5f200fb710 [file] [log] [blame] [raw]
package net.glowstone.generator;
import java.util.Map;
import java.util.Random;
import net.glowstone.GlowServer;
import net.glowstone.generator.populators.TheEndPopulator;
import net.glowstone.util.config.WorldConfig;
import net.glowstone.util.noise.PerlinOctaveGenerator;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.util.noise.OctaveGenerator;
public class TheEndGenerator extends GlowChunkGenerator {
private static double coordinateScale;
private static double heightScale;
private static double detailNoiseScaleX; // mainNoiseScaleX
private static double detailNoiseScaleY; // mainNoiseScaleY
private static double detailNoiseScaleZ; // mainNoiseScaleZ
private final double[][][] density = new double[3][3][33];
/**
* Creates a chunk generator for the End.
*/
public TheEndGenerator() {
super(new TheEndPopulator());
WorldConfig config = GlowServer.getWorldConfig();
coordinateScale = config.getDouble(WorldConfig.Key.END_COORDINATE_SCALE);
heightScale = config.getDouble(WorldConfig.Key.END_HEIGHT_SCALE);
detailNoiseScaleX = config.getDouble(WorldConfig.Key.END_DETAIL_NOISE_SCALE_X);
detailNoiseScaleY = config.getDouble(WorldConfig.Key.END_DETAIL_NOISE_SCALE_Y);
detailNoiseScaleZ = config.getDouble(WorldConfig.Key.END_DETAIL_NOISE_SCALE_Z);
}
@Override
public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ,
BiomeGrid biomes) {
return generateRawTerrain(world, chunkX, chunkZ);
}
@Override
public boolean canSpawn(World world, int x, int z) {
Block block = world.getHighestBlockAt(x, z).getRelative(BlockFace.DOWN);
return block.getType() == Material.ENDER_STONE;
}
@Override
protected void createWorldOctaves(World world, Map<String, OctaveGenerator> octaves) {
Random seed = new Random(world.getSeed());
OctaveGenerator gen = new PerlinOctaveGenerator(seed, 16, 3, 33, 3);
gen.setXScale(coordinateScale);
gen.setYScale(heightScale);
gen.setZScale(coordinateScale);
octaves.put("roughness", gen);
gen = new PerlinOctaveGenerator(seed, 16, 3, 33, 3);
gen.setXScale(coordinateScale);
gen.setYScale(heightScale);
gen.setZScale(coordinateScale);
octaves.put("roughness2", gen);
gen = new PerlinOctaveGenerator(seed, 8, 3, 33, 3);
gen.setXScale(coordinateScale / detailNoiseScaleX);
gen.setYScale(heightScale / detailNoiseScaleY);
gen.setZScale(coordinateScale / detailNoiseScaleZ);
octaves.put("detail", gen);
}
private ChunkData generateRawTerrain(World world, int chunkX, int chunkZ) {
generateTerrainDensity(world, chunkX << 1, chunkZ << 1);
ChunkData chunkData = createChunkData(world);
for (int i = 0; i < 3 - 1; i++) {
for (int j = 0; j < 3 - 1; j++) {
for (int k = 0; k < 33 - 1; k++) {
double d1 = density[i][j][k];
double d2 = density[i + 1][j][k];
double d3 = density[i][j + 1][k];
double d4 = density[i + 1][j + 1][k];
double d5 = (density[i][j][k + 1] - d1) / 4;
double d6 = (density[i + 1][j][k + 1] - d2) / 4;
double d7 = (density[i][j + 1][k + 1] - d3) / 4;
double d8 = (density[i + 1][j + 1][k + 1] - d4) / 4;
for (int l = 0; l < 4; l++) {
double d9 = d1;
double d10 = d3;
for (int m = 0; m < 8; m++) {
double dens = d9;
for (int n = 0; n < 8; n++) {
// any density higher than 0 is ground, any density lower or
// equal to 0 is air.
if (dens > 0) {
chunkData.setBlock(m + (i << 3), l + (k << 2), n + (j << 3),
Material.ENDER_STONE);
}
// interpolation along z
dens += (d10 - d9) / 8;
}
// interpolation along x
d9 += (d2 - d1) / 8;
// interpolate along z
d10 += (d4 - d3) / 8;
}
// interpolation along y
d1 += d5;
d3 += d7;
d2 += d6;
d4 += d8;
}
}
}
}
return chunkData;
}
private void generateTerrainDensity(World world, int x, int z) {
Map<String, OctaveGenerator> octaves = getWorldOctaves(world);
double[] roughnessNoise = ((PerlinOctaveGenerator) octaves.get("roughness"))
.getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D);
double[] roughnessNoise2 = ((PerlinOctaveGenerator) octaves.get("roughness2"))
.getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D);
double[] detailNoise = ((PerlinOctaveGenerator) octaves.get("detail"))
.getFractalBrownianMotion(x, 0, z, 0.5D, 2.0D);
int index = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
double noiseHeight =
100.0D - Math.sqrt((x + i) * (x + i) + (z + j) * (z + j)) * 8.0D;
noiseHeight = Math.max(-100.0D, Math.min(80.0D, noiseHeight));
for (int k = 0; k < 33; k++) {
double noiseR = roughnessNoise[index] / 512.0D;
double noiseR2 = roughnessNoise2[index] / 512.0D;
double noiseD = (detailNoise[index] / 10.0D + 1.0D) / 2.0D;
// linear interpolation
double dens = noiseD < 0 ? noiseR
: noiseD > 1 ? noiseR2 : noiseR + (noiseR2 - noiseR) * noiseD;
dens = dens - 8.0D + noiseHeight;
index++;
if (k < 8) {
double lowering = (8 - k) / 7;
dens = dens * (1.0D - lowering) + lowering * -30.0D;
} else if (k > 33 / 2 - 2) {
double lowering = (k - (33 / 2 - 2)) / 64.0D;
lowering = Math.max(0.0D, Math.min(1.0D, lowering));
dens = dens * (1.0D - lowering) + lowering * -3000.0D;
}
density[i][j][k] = dens;
}
}
}
}
}