package net.glowstone.generator;
import net.glowstone.generator.populators.*;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.util.noise.OctaveGenerator;
import org.bukkit.util.noise.SimplexOctaveGenerator;
import java.util.Map;
import java.util.Random;
/**
* Basic generator with lots of hills.
*/
public class SurfaceGenerator extends GlowChunkGenerator {
public SurfaceGenerator() {
super(
// In-ground
new LakePopulator(),
// On-ground
// Desert is before tree and mushroom but snow is after so trees have snow on top
new DesertPopulator(),
new TreePopulator(),
new MushroomPopulator(),
new SnowPopulator(),
new FlowerPopulator(),
new BiomePopulator(),
// Below-ground
new DungeonPopulator(),
//new CavePopulator(),
new OrePopulator()
);
}
@Override
public byte[] generate(World world, Random random, int chunkX, int chunkZ) {
Map<String, OctaveGenerator> octaves = getWorldOctaves(world);
OctaveGenerator noiseHeight = octaves.get("height");
OctaveGenerator noiseJitter = octaves.get("jitter");
OctaveGenerator noiseType = octaves.get("type");
chunkX <<= 4;
chunkZ <<= 4;
boolean nether = world.getEnvironment() == Environment.NETHER;
Material matMain = nether ? Material.NETHERRACK : Material.DIRT;
Material matShore = nether ? Material.SOUL_SAND : Material.SAND;
Material matShore2 = Material.GRAVEL;
Material matTop = nether ? Material.NETHERRACK : Material.GRASS;
Material matUnder = nether ? Material.NETHERRACK : Material.STONE;
Material matLiquid = nether ? Material.STATIONARY_LAVA : Material.STATIONARY_WATER;
byte[] buf = start(Material.AIR);
int baseHeight = WORLD_DEPTH / 2;
double terrainHeight = 50;
boolean noDirt = true;
int waterLevel = WORLD_DEPTH / 2;
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int deep = 0;
for (int y = (int) Math.min(baseHeight
+ noiseHeight.noise(x + chunkX, z + chunkZ, 0.7, 0.6, true)
* terrainHeight
+ noiseJitter.noise(x + chunkX, z + chunkZ, 0.5, 0.5)
* 1.5, WORLD_DEPTH - 1); y > 0; y--) {
double terrainType = noiseType.noise(x + chunkX, y, z + chunkZ, 0.5, 0.5);
Material ground = matTop;
if (Math.abs(terrainType) < random.nextDouble() / 3 && !noDirt) {
ground = matMain;
} else if (deep != 0 || y < waterLevel) {
ground = matMain;
}
if (Math.abs(y - waterLevel) < 5 - random.nextInt(2) && deep < 7) {
if (terrainType < random.nextDouble() / 2) {
if (terrainType < random.nextDouble() / 4) {
ground = matShore;
} else {
ground = matShore2;
}
}
}
if (deep > random.nextInt(3) + 6) {
ground = matUnder;
}
set(buf, x, y, z, ground);
deep++;
}
set(buf, x, 0, z, Material.BEDROCK);
}
}
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < waterLevel; y++) {
if (get(buf, x, y, z) == Material.AIR) {
set(buf, x, y, z, matLiquid);
}
}
}
}
return buf;
}
@Override
protected void createWorldOctaves(World world, Map<String, OctaveGenerator> octaves) {
Random seed = new Random(world.getSeed());
/* With default settings, this is 5 octaves. With tscale=256,terrainheight=50,
* this comes out to 14 octaves, which makes more complex terrain at the cost
* of more complex generation. Without this, the terrain looks bad, especially
* on higher tscale/terrainheight pairs. */
double value = Math.round(Math.sqrt(50 * 256.0 / (128 - 50)) * 1.1 - 0.2);
OctaveGenerator gen = new SimplexOctaveGenerator(seed, Math.max((int) value, 5));
gen.setScale(1 / 256.0);
octaves.put("height", gen);
gen = new SimplexOctaveGenerator(seed, gen.getOctaves().length / 2);
gen.setScale(Math.min(256.0 / 1024, 1 / 32.0));
octaves.put("jitter", gen);
gen = new SimplexOctaveGenerator(seed, 2);
gen.setScale(1 / WORLD_DEPTH);
octaves.put("type", gen);
}
@Override
public Location getFixedSpawnLocation(World world, Random random) {
return new Location(world, 0, 2 + world.getHighestBlockYAt(0, 0), 0);
}
}