| 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; |
| } |
| } |
| } |
| } |
| } |