Package org.spout.vanilla.world.generator.normal

Source Code of org.spout.vanilla.world.generator.normal.NormalGenerator

/*
* This file is part of Vanilla.
*
* Copyright (c) 2011 Spout LLC <http://www.spout.org/>
* Vanilla is licensed under the Spout License Version 1.
*
* Vanilla is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* In addition, 180 days after any changes are published, you can use the
* software, incorporating those changes, under the terms of the MIT license,
* as described in the Spout License Version 1.
*
* Vanilla is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License,
* the MIT license and the Spout License Version 1 along with this program.
* If not, see <http://www.gnu.org/licenses/> for the GNU Lesser General Public
* License and see <http://spout.in/licensev1> for the full license, including
* the MIT license.
*/
package org.spout.vanilla.world.generator.normal;

import java.util.Random;

import net.royawesome.jlibnoise.NoiseQuality;
import net.royawesome.jlibnoise.module.modifier.Exponent;
import net.royawesome.jlibnoise.module.modifier.ScalePoint;
import net.royawesome.jlibnoise.module.source.Perlin;

import org.spout.api.generator.WorldGeneratorUtils;
import org.spout.api.generator.biome.Biome;
import org.spout.api.generator.biome.BiomeManager;
import org.spout.api.generator.biome.BiomePopulator;
import org.spout.api.generator.biome.BiomeSelector;
import org.spout.api.generator.biome.selector.BiomeSelectorLayer;
import org.spout.api.generator.biome.selector.LayeredBiomeSelector;
import org.spout.api.generator.biome.selector.PerlinRangeLayer;
import org.spout.api.generator.biome.selector.RidgedMultiRangeLayer;
import org.spout.api.geo.World;
import org.spout.api.geo.cuboid.Chunk;
import org.spout.api.geo.discrete.Point;
import org.spout.api.util.LogicUtil;
import org.spout.api.util.cuboid.CuboidBlockMaterialBuffer;
import org.spout.api.util.map.TIntPairObjectHashMap;

import org.spout.math.GenericMath;
import org.spout.math.vector.Vector3f;
import org.spout.vanilla.data.Climate;
import org.spout.vanilla.material.VanillaMaterials;
import org.spout.vanilla.material.block.Liquid;
import org.spout.vanilla.world.generator.biome.VanillaBiomeGenerator;
import org.spout.vanilla.world.generator.biome.VanillaBiomes;
import org.spout.vanilla.world.generator.normal.biome.NormalBiome;
import org.spout.vanilla.world.generator.normal.biome.selector.WhittakerLayer;
import org.spout.vanilla.world.generator.normal.object.OreObject.VanillaOreTypes;
import org.spout.vanilla.world.generator.normal.populator.BedrockBoundPopulator;
import org.spout.vanilla.world.generator.normal.populator.CavePopulator;
import org.spout.vanilla.world.generator.normal.populator.DungeonPopulator;
import org.spout.vanilla.world.generator.normal.populator.FallingLiquidPopulator;
import org.spout.vanilla.world.generator.normal.populator.GroundCoverPopulator;
import org.spout.vanilla.world.generator.normal.populator.MineshaftPopulator;
import org.spout.vanilla.world.generator.normal.populator.OrePopulator;
import org.spout.vanilla.world.generator.normal.populator.PondPopulator;
import org.spout.vanilla.world.generator.normal.populator.RavinePopulator;
import org.spout.vanilla.world.generator.normal.populator.RockyShieldPopulator;
import org.spout.vanilla.world.generator.normal.populator.SnowPopulator;
import org.spout.vanilla.world.generator.normal.populator.StrongholdPopulator;
import org.spout.vanilla.world.generator.normal.populator.TemplePopulator;

public class NormalGenerator extends VanillaBiomeGenerator {
  // world constants
  public static final int HEIGHT = 256;
  public static final int SEA_LEVEL = 62;
  private static final byte BEDROCK_DEPTH = 5;
  // noise for generation
  private static final Perlin PERLIN = new Perlin();
  private static final Exponent CONTRAST = new Exponent();
  private static final ScalePoint NOISE = new ScalePoint();
  // smoothing stuff
  private static final int SMOOTH_SIZE = 2;
  private static final double[][] GAUSSIAN_KERNEL;

  static {
    PERLIN.setFrequency(0.012);
    PERLIN.setLacunarity(2);
    PERLIN.setNoiseQuality(NoiseQuality.BEST);
    PERLIN.setPersistence(0.5);
    PERLIN.setOctaveCount(16);

    CONTRAST.SetSourceModule(0, PERLIN);
    CONTRAST.setExponent(2.5);

    NOISE.SetSourceModule(0, CONTRAST);
    NOISE.setxScale(1);
    NOISE.setyScale(1);
    NOISE.setzScale(1);

    final int kernelSize = SMOOTH_SIZE * 2 + 1;
    GAUSSIAN_KERNEL = new double[kernelSize][kernelSize];
    final double bellSize = 1d / SMOOTH_SIZE;
    final double bellHeight = 2 * SMOOTH_SIZE;
    for (int sx = -SMOOTH_SIZE; sx <= SMOOTH_SIZE; sx++) {
      for (int sz = -SMOOTH_SIZE; sz <= SMOOTH_SIZE; sz++) {
        final double bx = bellSize * sx;
        final double bz = bellSize * sz;
        GAUSSIAN_KERNEL[sx + SMOOTH_SIZE][sz + SMOOTH_SIZE] = bellHeight * Math.exp(-(bx * bx + bz * bz) / 2);
      }
    }
  }

  @Override
  public void registerBiomes() {
    // if you want to check out a particular biome, use this!
    //setSelector(new PerBlockBiomeSelector(VanillaBiomes.TUNDRA));
    setSelector(new LayeredBiomeSelector(buildSelectorStack(1), VanillaBiomes.OCEAN) {
      @Override
      public Biome pickBiome(int x, int y, int z, long seed) {
        int hash = x * 2345803 ^ y * 9236449 ^ (int) seed;
        hash *= hash + 223;
        int xNoise = hash >> 20 & 3;
        int zNoise = hash >> 22 & 3;
        if (xNoise == 3) {
          xNoise = 1;
        }
        if (zNoise == 3) {
          zNoise = 1;
        }
        return super.pickBiome(x + xNoise - 1, y, z + zNoise - 1, seed);
      }
    });
    final BedrockBoundPopulator bedrock = new BedrockBoundPopulator();
    bedrock.addBound(0, 1, BEDROCK_DEPTH);
    addGeneratorPopulators(
        bedrock, new GroundCoverPopulator(), new RockyShieldPopulator(),
        new CavePopulator(), new RavinePopulator());
    final OrePopulator ores = new OrePopulator();
    ores.addOreTypes(VanillaOreTypes.DIRT, VanillaOreTypes.GRAVEL, VanillaOreTypes.COAL, VanillaOreTypes.IRON,
        VanillaOreTypes.REDSTONE, VanillaOreTypes.GOLD, VanillaOreTypes.LAPIS_LAZULI, VanillaOreTypes.DIAMOND);
    addPopulators(
        new MineshaftPopulator(), new StrongholdPopulator(), new TemplePopulator(),
        new PondPopulator(), new DungeonPopulator(), ores,
        new BiomePopulator(),
        new FallingLiquidPopulator(), new SnowPopulator());
    register(VanillaBiomes.OCEAN);
    register(VanillaBiomes.FROZEN_OCEAN);
    register(VanillaBiomes.PLAINS);
    register(VanillaBiomes.DESERT);
    register(VanillaBiomes.DESERT_HILLS);
    register(VanillaBiomes.SMALL_MOUNTAINS);
    register(VanillaBiomes.MOUNTAINS);
    register(VanillaBiomes.BEACH);
    register(VanillaBiomes.SWAMP);
    register(VanillaBiomes.FOREST);
    register(VanillaBiomes.FOREST_HILLS);
    register(VanillaBiomes.FROZEN_RIVER);
    register(VanillaBiomes.RIVER);
    register(VanillaBiomes.JUNGLE);
    register(VanillaBiomes.JUNGLE_HILLS);
    register(VanillaBiomes.MUSHROOM);
    register(VanillaBiomes.MUSHROOM_SHORE);
    register(VanillaBiomes.TUNDRA);
    register(VanillaBiomes.TUNDRA_HILLS);
    register(VanillaBiomes.TAIGA);
    register(VanillaBiomes.TAIGA_HILLS);
  }

  @Override
  public String getName() {
    return "VanillaNormal";
  }

  @Override
  protected void generateTerrain(CuboidBlockMaterialBuffer blockData, int x, int y, int z, BiomeManager biomes, long seed) {
    PERLIN.setSeed((int) seed);
    final Vector3f size = blockData.getSize();
    final int sizeX = size.getFloorX();
    final int sizeY = size.getFloorY();
    final int sizeZ = size.getFloorZ();
    final double[][][] noise = WorldGeneratorUtils.fastNoise(NOISE, sizeX, sizeY, sizeZ, 4, x, y, z);
    final BiomeSelector selector = getSelector();
    final TIntPairObjectHashMap<NormalBiome> biomeCache = new TIntPairObjectHashMap<NormalBiome>();
    for (int xx = 0; xx < sizeX; xx++) {
      for (int zz = 0; zz < sizeZ; zz++) {
        double maxSum = 0;
        double minSum = 0;
        double weightSum = 0;
        for (int sx = -SMOOTH_SIZE; sx <= SMOOTH_SIZE; sx++) {
          for (int sz = -SMOOTH_SIZE; sz <= SMOOTH_SIZE; sz++) {
            final NormalBiome adjacent;
            if (xx + sx < 0 || zz + sz < 0
                || xx + sx >= sizeX || zz + sz >= sizeZ) {
              if (biomeCache.containsKey(x + xx + sx, z + zz + sz)) {
                adjacent = biomeCache.get(x + xx + sx, z + zz + sz);
              } else {
                adjacent = (NormalBiome) selector.pickBiome(x + xx + sx, y, z + zz + sz, seed);
                biomeCache.put(x + xx + sx, z + zz + sz, adjacent);
              }
            } else {
              adjacent = (NormalBiome) biomes.getBiome(xx + sx, y, zz + sz);
            }
            final double weight = GAUSSIAN_KERNEL[sx + SMOOTH_SIZE][sz + SMOOTH_SIZE];
            minSum += adjacent.getMinElevation() * weight;
            maxSum += adjacent.getMaxElevation() * weight;
            weightSum += weight;
          }
        }
        final double minElevation = minSum / weightSum;
        final double smoothHeight = (maxSum / weightSum - minElevation) / 2;
        for (int yy = 0; yy < sizeY; yy++) {
          final double noiseValue = noise[xx][yy][zz] - 1 / smoothHeight * (y + yy - smoothHeight - minElevation);
          if (noiseValue >= 0) {
            blockData.set(x + xx, y + yy, z + zz, VanillaMaterials.STONE);
          } else {
            if (y + yy <= SEA_LEVEL) {
              if (y + yy == SEA_LEVEL && ((NormalBiome) biomes.getBiome(xx, 0, zz)).getClimate() == Climate.COLD) {
                blockData.set(x + xx, y + yy, z + zz, VanillaMaterials.ICE);
              } else {
                blockData.set(x + xx, y + yy, z + zz, VanillaMaterials.STATIONARY_WATER);
              }
            } else {
              blockData.set(x + xx, y + yy, z + zz, VanillaMaterials.AIR);
            }
          }
        }
      }
    }
  }

  @Override
  public Point getSafeSpawn(World world) {
    short shift = 0;
    final BiomeSelector selector = getSelector();
    final long seed = world.getSeed();
    while (LogicUtil.equalsAny(selector.pickBiome(shift, 0, seed),
        VanillaBiomes.OCEAN, VanillaBiomes.BEACH, VanillaBiomes.RIVER,
        VanillaBiomes.SWAMP, VanillaBiomes.MUSHROOM_SHORE, VanillaBiomes.MUSHROOM)
        && shift < 1600) {
      shift += 16;
    }
    final Random random = GenericMath.getRandom();
    for (byte attempts = 0; attempts < 32; attempts++) {
      final int x = random.nextInt(256) - 127 + shift;
      final int z = random.nextInt(256) - 127;
      final int y = getHighestSolidBlock(world, x, z);
      if (y != -1 && !LogicUtil.equalsAny(world.getBiome(x, y, z),
          VanillaBiomes.MUSHROOM_SHORE, VanillaBiomes.MUSHROOM)) {
        return new Point(world, x, y + 0.5f, z);
      }
    }
    return new Point(world, shift, 80, 0);
  }

  private int getHighestSolidBlock(World world, int x, int z) {
    int y = HEIGHT - 1;
    while (world.getBlockMaterial(x, y, z).isInvisible()) {
      if (--y == 0 || world.getBlockMaterial(x, y, z) instanceof Liquid) {
        return -1;
      }
    }
    return ++y;
  }

  @Override
  public int[][] getSurfaceHeight(World world, int chunkX, int chunkY) {
    int[][] heights = new int[Chunk.BLOCKS.SIZE][Chunk.BLOCKS.SIZE];
    for (int x = 0; x < Chunk.BLOCKS.SIZE; x++) {
      for (int z = 0; z < Chunk.BLOCKS.SIZE; z++) {
        heights[x][z] = SEA_LEVEL;
      }
    }
    return heights;
  }

  private static BiomeSelectorLayer buildSelectorStack(double scale) {
    //
    // STANDARD FEATURES
    //
    // rivers
    final RidgedMultiRangeLayer rivers =
        new RidgedMultiRangeLayer(2).
            setOctaveCount(1).
            setFrequency(0.005 / scale);
    // hills
    final PerlinRangeLayer hills =
        new PerlinRangeLayer(1).
            setOctaveCount(1).
            setFrequency(0.004 / scale);
    // frozen oceans
    final PerlinRangeLayer frozenOceans =
        new PerlinRangeLayer(3).
            setOctaveCount(1).
            setFrequency(0.004 / scale);
    //
    // LAND LAYERS
    //
    // desert
    final BiomeSelectorLayer basicDesert =
        hills.clone().
            addElement(VanillaBiomes.DESERT, -1, 0.5f).
            addElement(VanillaBiomes.DESERT_HILLS, 0.5f, 1);
    // desert land
    final BiomeSelectorLayer desert =
        rivers.clone().
            addElement(basicDesert, -1, 0.14f).
            addElement(VanillaBiomes.RIVER, 0.14f, 1);
    // forest
    final BiomeSelectorLayer basicForest =
        hills.clone().
            addElement(VanillaBiomes.FOREST, -1, 0.5f).
            addElement(VanillaBiomes.FOREST_HILLS, 0.5f, 1);
    // forest land
    final BiomeSelectorLayer forest =
        rivers.clone().
            addElement(basicForest, -1, 0.14f).
            addElement(VanillaBiomes.RIVER, 0.14f, 1);
    // jungle
    final BiomeSelectorLayer basicJungle =
        hills.clone().
            addElement(VanillaBiomes.JUNGLE, -1, 0.5f).
            addElement(VanillaBiomes.JUNGLE_HILLS, 0.5f, 1);
    // jungle land
    final BiomeSelectorLayer jungle =
        rivers.clone().
            addElement(basicJungle, -1, 0.14f).
            addElement(VanillaBiomes.RIVER, 0.14f, 1);
    // plains
    final BiomeSelectorLayer plains =
        rivers.clone().
            addElement(VanillaBiomes.PLAINS, -1, 0.14f).
            addElement(VanillaBiomes.RIVER, 0.14f, 1);
    // swamp
    final BiomeSelectorLayer swamp =
        rivers.clone().
            addElement(VanillaBiomes.SWAMP, -1, 0.14f).
            addElement(VanillaBiomes.RIVER, 0.14f, 1);
    // taiga
    final BiomeSelectorLayer basicTaiga =
        hills.clone().
            addElement(VanillaBiomes.TAIGA, -1, 0.5f).
            addElement(VanillaBiomes.TAIGA_HILLS, 0.5f, 1);
    // taiga sub-land
    final BiomeSelectorLayer subTaiga =
        rivers.clone().
            addElement(basicTaiga, -1, 0.14f).
            addElement(VanillaBiomes.FROZEN_RIVER, 0.14f, 1);
    // taiga land
    final BiomeSelectorLayer taiga =
        frozenOceans.clone().
            addElement(subTaiga, -1, 0.4f).
            addElement(VanillaBiomes.FROZEN_OCEAN, 0.4f, 1);
    // tundra
    final BiomeSelectorLayer basicTundra =
        hills.clone().
            addElement(VanillaBiomes.TUNDRA, -1, 0.5f).
            addElement(VanillaBiomes.TUNDRA_HILLS, 0.5f, 1);
    // tundra sub-land
    final BiomeSelectorLayer subTundra =
        rivers.clone().
            addElement(basicTundra, -1, 0.14f).
            addElement(VanillaBiomes.FROZEN_RIVER, 0.14f, 1);
    // tundra land
    final BiomeSelectorLayer tundra =
        frozenOceans.clone().
            addElement(subTundra, -1, 0.4f).
            addElement(VanillaBiomes.FROZEN_OCEAN, 0.4f, 1);
    //
    //  PRIMARY LAYERS
    //
    // mushroom
    final BiomeSelectorLayer mushroom =
        new PerlinRangeLayer(11).
            setOctaveCount(1).
            setFrequency(0.004 / scale).
            addElement(VanillaBiomes.OCEAN, -1, 0.75f).
            addElement(VanillaBiomes.MUSHROOM_SHORE, 0.75f, 0.85f).
            addElement(VanillaBiomes.MUSHROOM, 0.85f, 1);
    // shore
    final BiomeSelectorLayer shore =
        rivers.clone().
            addElement(VanillaBiomes.BEACH, -1, 0.16f).
            addElement(VanillaBiomes.RIVER, 0.16f, 1);
    // land
    final BiomeSelectorLayer land =
        new WhittakerLayer(7).
            setHumidityOctaveCount(1).
            setHumidityFrequency(0.0005 / scale).
            setTemperatureOctaveCount(1).
            setTemperatureFrequency(0.0005 / scale).
            addElement(desert, 20, 50).
            addElement(plains, 10, 150).
            addElement(forest, 15, 235).
            addElement(jungle, 20, 350).
            addElement(swamp, 10, 300).
            addElement(taiga, -5, 215).
            addElement(tundra, -10, 185);
    // small mountains
    final BiomeSelectorLayer smallMountains =
        rivers.clone().
            addElement(VanillaBiomes.SMALL_MOUNTAINS, -1, 0.16f).
            addElement(VanillaBiomes.RIVER, 0.16f, 1);
    // mountains
    final BiomeSelectorLayer mountains =
        rivers.clone().
            addElement(VanillaBiomes.MOUNTAINS, -1, 0.16f).
            addElement(VanillaBiomes.RIVER, 0.16f, 1);
    //
    // STARTING LAYER
    //
    // start
    final BiomeSelectorLayer start =
        new PerlinRangeLayer(5).
            setOctaveCount(1).
            setFrequency(0.0028 / scale).
            addElement(mushroom, -1, -0.5f).
            addElement(VanillaBiomes.OCEAN, -0.5f, -0.05f).
            addElement(shore, -0.05f, 0).
            addElement(land, 0, 0.675f).
            addElement(smallMountains, 0.675f, 0.71f).
            addElement(mountains, 0.71f, 1);
    return start;
  }
}
TOP

Related Classes of org.spout.vanilla.world.generator.normal.NormalGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.