| package net.glowstone.generator.ground; |
| |
| import java.util.Arrays; |
| import java.util.Random; |
| import net.glowstone.util.noise.SimplexOctaveGenerator; |
| import org.bukkit.Material; |
| import org.bukkit.World; |
| import org.bukkit.block.Biome; |
| import org.bukkit.generator.ChunkGenerator.ChunkData; |
| import org.bukkit.material.MaterialData; |
| |
| public class MesaGroundGenerator extends GroundGenerator { |
| private final MesaType type; |
| // TODO: rewrite to use terracotta materials |
| private final int[] colorLayer = new int[64]; |
| private Material topMaterial; |
| private Material groundMaterial; |
| private SimplexOctaveGenerator colorNoise; |
| private SimplexOctaveGenerator canyonHeightNoise; |
| private SimplexOctaveGenerator canyonScaleNoise; |
| private long seed; |
| |
| public MesaGroundGenerator() { |
| this(MesaType.NORMAL); |
| } |
| |
| /** |
| * Creates a ground generator for mesa biomes. |
| * |
| * @param type the type of mesa biome to generate |
| */ |
| public MesaGroundGenerator(MesaType type) { |
| this.type = type; |
| topMaterial = Material.RED_SAND; |
| groundMaterial = Material.ORANGE_TERRACOTTA; |
| } |
| |
| private void initialize(long seed) { |
| if (seed != this.seed || colorNoise == null || canyonScaleNoise == null |
| || canyonHeightNoise == null) { |
| Random random = new Random(seed); |
| colorNoise = new SimplexOctaveGenerator(random, 1); |
| colorNoise.setScale(1 / 512.0D); |
| initializeColorLayers(random); |
| |
| canyonHeightNoise = new SimplexOctaveGenerator(random, 4); |
| canyonHeightNoise.setScale(1 / 4.0D); |
| canyonScaleNoise = new SimplexOctaveGenerator(random, 1); |
| canyonScaleNoise.setScale(1 / 512.0D); |
| this.seed = seed; |
| } |
| } |
| |
| @Override |
| public void generateTerrainColumn(ChunkData chunkData, World world, Random random, int x, int z, |
| Biome biome, double surfaceNoise) { |
| |
| initialize(world.getSeed()); |
| |
| int seaLevel = world.getSeaLevel(); |
| |
| Material topMat = topMaterial; |
| Material groundMat = groundMaterial; |
| |
| int surfaceHeight = Math |
| .max((int) (surfaceNoise / 3.0D + 3.0D + random.nextDouble() * 0.25D), 1); |
| boolean colored = Math.cos(surfaceNoise / 3.0D * Math.PI) <= 0; |
| double bryceCanyonHeight = 0; |
| if (type == MesaType.BRYCE) { |
| int noiseX = (x & 0xFFFFFFF0) + (z & 0xF); |
| int noiseZ = (z & 0xFFFFFFF0) + (x & 0xF); |
| double noiseCanyonHeight = Math |
| .min(Math.abs(surfaceNoise), |
| canyonHeightNoise.noise(noiseX, noiseZ, 0.5D, 2.0D)); |
| if (noiseCanyonHeight > 0) { |
| double heightScale = Math.abs(canyonScaleNoise.noise(noiseX, noiseZ, 0.5D, 2.0D)); |
| bryceCanyonHeight = Math.pow(noiseCanyonHeight, 2) * 2.5D; |
| double maxHeight = Math.ceil(50 * heightScale) + 14; |
| if (bryceCanyonHeight > maxHeight) { |
| bryceCanyonHeight = maxHeight; |
| } |
| bryceCanyonHeight += seaLevel; |
| } |
| } |
| |
| int chunkX = x; |
| int chunkZ = z; |
| x &= 0xF; |
| z &= 0xF; |
| |
| int deep = -1; |
| boolean groundSet = false; |
| for (int y = 255; y >= 0; y--) { |
| if (y < (int) bryceCanyonHeight && chunkData.getType(x, y, z) == Material.AIR) { |
| chunkData.setBlock(x, y, z, Material.STONE); |
| } |
| if (y <= random.nextInt(5)) { |
| chunkData.setBlock(x, y, z, Material.BEDROCK); |
| } else { |
| Material mat = chunkData.getType(x, y, z); |
| if (mat == Material.AIR) { |
| deep = -1; |
| } else if (mat != Material.STONE) { |
| continue; |
| } |
| if (deep == -1) { |
| groundSet = false; |
| if (y >= seaLevel - 5 && y <= seaLevel) { |
| groundMat = groundMaterial; |
| } |
| |
| deep = surfaceHeight + Math.max(0, y - seaLevel - 1); |
| if (y >= seaLevel - 2) { |
| if (type == MesaType.FOREST && y > seaLevel + 22 + (surfaceHeight |
| << 1)) { |
| topMat = colored ? Material.GRASS_BLOCK : Material.COARSE_DIRT; |
| chunkData.setBlock(x, y, z, topMat); |
| } else if (y > seaLevel + 2 + surfaceHeight) { |
| int color = colorLayer[ |
| (y + (int) Math.round( |
| colorNoise.noise(chunkX, chunkZ, 0.5D, 2.0D) * 2.0D)) |
| % colorLayer.length]; |
| setColoredGroundLayer(chunkData, x, y, z, |
| y < seaLevel || y > 128 ? Material.ORANGE_TERRACOTTA : colored ? Material.WHITE_TERRACOTTA : Material.TERRACOTTA); |
| } else { |
| chunkData.setBlock(x, y, z, topMaterial); |
| groundSet = true; |
| } |
| } else { |
| chunkData.setBlock(x, y, z, groundMat); |
| } |
| } else if (deep > 0) { |
| deep--; |
| if (groundSet) { |
| chunkData.setBlock(x, y, z, groundMaterial); |
| } else { |
| int color = colorLayer[ |
| (y + (int) Math.round( |
| colorNoise.noise(chunkX, chunkZ, 0.5D, 2.0D) * 2.0D)) |
| % colorLayer.length]; |
| setColoredGroundLayer(chunkData, x, y, z, Material.WHITE_TERRACOTTA); |
| } |
| } |
| } |
| } |
| } |
| |
| private void setColoredGroundLayer(ChunkData chunkData, int x, int y, int z, Material type) { |
| chunkData.setBlock(x, y, z, type); |
| } |
| |
| private void setRandomLayerColor(Random random, int minLayerCount, int minLayerHeight, |
| int color) { |
| for (int i = 0; i < random.nextInt(4) + minLayerCount; i++) { |
| int j = random.nextInt(colorLayer.length); |
| int k = 0; |
| while (k < random.nextInt(3) + minLayerHeight && j < colorLayer.length) { |
| colorLayer[j++] = color; |
| k++; |
| } |
| } |
| } |
| |
| private void initializeColorLayers(Random random) { |
| Arrays.fill(colorLayer, -1); // hard clay, other values are stained clay |
| int i = 0; |
| while (i < colorLayer.length) { |
| i += random.nextInt(5) + 1; |
| if (i < colorLayer.length) { |
| colorLayer[i++] = 1; // orange |
| } |
| } |
| setRandomLayerColor(random, 2, 1, 4); // yellow |
| setRandomLayerColor(random, 2, 2, 12); // brown |
| setRandomLayerColor(random, 2, 1, 14); // red |
| int j = 0; |
| for (i = 0; i < random.nextInt(3) + 3; i++) { |
| j += random.nextInt(16) + 4; |
| if (j >= colorLayer.length) { |
| break; |
| } |
| if (random.nextInt(2) == 0 || j < colorLayer.length - 1 && random.nextInt(2) == 0) { |
| colorLayer[j - 1] = 8; // light gray |
| } else { |
| colorLayer[j] = 0; // white |
| } |
| } |
| } |
| |
| public enum MesaType { |
| NORMAL, |
| BRYCE, |
| FOREST |
| } |
| } |