|
|
@@ -0,0 +1,294 @@ |
|
|
/* |
|
|
* This file is part of Vanilla. |
|
|
* |
|
|
* Copyright (c) 2011-2012, SpoutDev <http://www.spout.org/> |
|
|
* Vanilla is licensed under the SpoutDev 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 SpoutDev 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 SpoutDev 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://www.spout.org/SpoutDevLicenseV1.txt> for the full license, |
|
|
* including the MIT license. |
|
|
*/ |
|
|
package org.spout.vanilla.world.generator.normal.object; |
|
|
|
|
|
import java.util.Random; |
|
|
|
|
|
import org.spout.api.generator.WorldGeneratorObject; |
|
|
import org.spout.api.generator.biome.Biome; |
|
|
import org.spout.api.geo.World; |
|
|
import org.spout.api.geo.cuboid.Block; |
|
|
import org.spout.api.material.BlockMaterial; |
|
|
|
|
|
import org.spout.vanilla.material.VanillaMaterials; |
|
|
import org.spout.vanilla.material.block.Liquid; |
|
|
import org.spout.vanilla.world.generator.VanillaBiomes; |
|
|
|
|
|
public class PondObject extends WorldGeneratorObject { |
|
|
|
|
|
// rng |
|
|
private final Random random; |
|
|
// pond instance for generating the height maps |
|
|
private final PondHole pond; |
|
|
// height maps for generation |
|
|
private byte[] holeHeightMap; |
|
|
private byte[] topHeightMap; |
|
|
// the liquid, can be any block really |
|
|
private BlockMaterial liquid; |
|
|
// extras |
|
|
private boolean stoneWalls; |
|
|
private boolean stonyTop; |
|
|
private boolean biomeAdaptedSurface; |
|
|
|
|
|
public PondObject(Random random, PondType type) { |
|
|
this.random = random; |
|
|
pond = new PondHole(); |
|
|
liquid = type.liquid; |
|
|
stoneWalls = type.stoneWalls; |
|
|
stonyTop = type.stonyTop; |
|
|
biomeAdaptedSurface = type.biomeSurface; |
|
|
generateHeightMaps(); |
|
|
} |
|
|
|
|
|
@Override |
|
|
public boolean canPlaceObject(World world, int x, int y, int z) { |
|
|
x -= 8; |
|
|
z -= 8; |
|
|
for (byte px = 0; px < 16; px++) { |
|
|
for (byte pz = 0; pz < 16; pz++) { |
|
|
for (byte py = 1; py < 5; py++) { |
|
|
if (isWallBlock(px, py, pz, holeHeightMap)) { |
|
|
final BlockMaterial material = world.getBlockMaterial(x + px, y - py, z + pz); |
|
|
if (!material.isSolid() && material != liquid) { |
|
|
return false; |
|
|
} |
|
|
} |
|
|
if (isWallBlock(px, py, pz, topHeightMap)) { |
|
|
if (world.getBlockMaterial(x + px, y + py, z + pz) instanceof Liquid) { |
|
|
return false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return true; |
|
|
} |
|
|
|
|
|
@Override |
|
|
public void placeObject(World world, int x, int y, int z) { |
|
|
x -= 8; |
|
|
z -= 8; |
|
|
for (byte px = 0; px < 16; px++) { |
|
|
for (byte pz = 0; pz < 16; pz++) { |
|
|
for (byte py = (byte) -holeHeightMap[16 * px + pz]; py < 0; py++) { |
|
|
world.setBlockMaterial(px + x, py + y, pz + z, liquid, (short) 0, world); |
|
|
} |
|
|
if (stoneWalls) { |
|
|
for (byte py = 1; py < 5; py++) { |
|
|
if (isWallBlock(px, py, pz, holeHeightMap)) { |
|
|
world.setBlockMaterial(x + px, y - py, z + pz, VanillaMaterials.STONE, (short) 0, world); |
|
|
} |
|
|
} |
|
|
} |
|
|
for (byte py = 0; py < topHeightMap[16 * px + pz]; py++) { |
|
|
world.setBlockMaterial(px + x, py + y, pz + z, VanillaMaterials.AIR, (short) 0, world); |
|
|
} |
|
|
if (stonyTop) { |
|
|
for (byte py = 1; py < 5; py++) { |
|
|
if (isWallBlock(px, py, pz, topHeightMap)) { |
|
|
final Block block = world.getBlock(px + x, py + y - 1, pz + z); |
|
|
if (random.nextBoolean() && block.getMaterial().isOpaque()) { |
|
|
block.setMaterial(VanillaMaterials.STONE); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
if (biomeAdaptedSurface) { |
|
|
finalizeSurface(world, x, y, z); |
|
|
} |
|
|
} |
|
|
|
|
|
private void finalizeSurface(World world, int x, int y, int z) { |
|
|
for (byte px = 0; px < 16; px++) { |
|
|
for (byte pz = 0; pz < 16; pz++) { |
|
|
for (byte py = -1; py < 4; py++) { |
|
|
if (world.getBlockSkyLight(x + px, y + py + 1, z + pz) > 0) { |
|
|
final Block block = world.getBlock(x + px, y + py, z + pz); |
|
|
final BlockMaterial material = block.getMaterial(); |
|
|
if (material == VanillaMaterials.DIRT) { |
|
|
if (block.getBiomeType() == VanillaBiomes.MUSHROOM) { |
|
|
block.setMaterial(VanillaMaterials.MYCELIUM); |
|
|
} else { |
|
|
block.setMaterial(VanillaMaterials.GRASS); |
|
|
} |
|
|
} else if (material == VanillaMaterials.STATIONARY_WATER |
|
|
&& block.translate(0, 1, 0).getMaterial() == VanillaMaterials.AIR) { |
|
|
final Biome biome = block.getBiomeType(); |
|
|
if (biome == VanillaBiomes.TAIGA || biome == VanillaBiomes.TUNDRA) { |
|
|
block.setMaterial(VanillaMaterials.ICE); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
public final void generateHeightMaps() { |
|
|
holeHeightMap = new byte[256]; |
|
|
topHeightMap = new byte[256]; |
|
|
for (byte px = 0; px < 16; px++) { |
|
|
for (byte pz = 0; pz < 16; pz++) { |
|
|
holeHeightMap[16 * px + pz] = pond.getDepth(px, pz); |
|
|
topHeightMap[16 * px + pz] = pond.getDepth(px, pz); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
private boolean isWallBlock(int x, int y, int z, byte[] blocks) { |
|
|
if (y <= blocks[16 * x + z]) { // Is a fluid block on x, y, z ? |
|
|
return false; |
|
|
} |
|
|
if (x < 15 && y <= blocks[16 * (x + 1) + z]) { //is a fluid block on x + 1, y, z |
|
|
return true; |
|
|
} else if (x > 0 && y <= blocks[16 * (x - 1) + z]) { //is a fluid block on x - 1, y, z |
|
|
return true; |
|
|
} else if (z < 15 && y <= blocks[16 * x + z + 1]) { //is a fluid block on x, y, z + 1 |
|
|
return true; |
|
|
} else if (z > 0 && y <= blocks[16 * x + z - 1]) { //is a fluid block on x, y, z - 1 |
|
|
return true; |
|
|
} else if (y > 1 && y <= blocks[16 * x + z] + 1) { //is a fluid block on x, y - 1, z |
|
|
return true; |
|
|
} else { |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* Represents a hole in the shape of a pond |
|
|
*/ |
|
|
private class PondHole { |
|
|
|
|
|
private final SphericalNoise[] noise; |
|
|
|
|
|
private PondHole() { |
|
|
noise = new SphericalNoise[random.nextInt(4) + 4]; |
|
|
for (byte i = 0; i < noise.length; i++) { |
|
|
noise[i] = new SphericalNoise(); |
|
|
} |
|
|
} |
|
|
|
|
|
private byte getDepth(int x, int z) { |
|
|
byte depth = Byte.MIN_VALUE; |
|
|
for (final SphericalNoise n : noise) { |
|
|
byte d = n.getValue(x, z); |
|
|
depth = d > depth ? d : depth; |
|
|
} |
|
|
return depth; |
|
|
} |
|
|
|
|
|
/* |
|
|
* Noise used to generate the pond hole |
|
|
*/ |
|
|
private class SphericalNoise { |
|
|
|
|
|
private final float radius; |
|
|
private final int xOffset; |
|
|
private final int yOffset; |
|
|
private final int zOffset; |
|
|
private final float xMultiplier; |
|
|
private final float yMultiplier; |
|
|
private final float zMultiplier; |
|
|
|
|
|
private SphericalNoise() { |
|
|
int yOff = random.nextInt(2); |
|
|
if (random.nextBoolean()) { |
|
|
yOff = -yOff; |
|
|
} |
|
|
yOffset = yOff; |
|
|
xOffset = random.nextInt(7) + 4; |
|
|
zOffset = random.nextInt(7) + 4; |
|
|
radius = random.nextInt(2) + 2; |
|
|
xMultiplier = random.nextFloat() * 0.2f + 0.95f; |
|
|
yMultiplier = random.nextFloat() + 0.9f; |
|
|
zMultiplier = random.nextFloat() * 0.2f + 0.95f; |
|
|
} |
|
|
|
|
|
private byte getValue(int x, int z) { |
|
|
final float xOffNoise = random.nextFloat() * 0.2f; |
|
|
final float zOffNoise = random.nextFloat() * 0.2f; |
|
|
final float radiusNoise = random.nextFloat() * 0.8f; |
|
|
final float multiXNoise = 1f - random.nextFloat() * 0.1f; |
|
|
final float multiZNoise = 1f - random.nextFloat() * 0.1f; |
|
|
final float value = (float) Math.sqrt(Math.pow(radius + radiusNoise, 2) - Math.pow((xMultiplier * multiXNoise) * x - xOffset - xOffNoise, 2) - Math.pow((zMultiplier * multiZNoise) * z - zOffset - zOffNoise, 2)); |
|
|
return (byte) ((value + yOffset) / yMultiplier); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
public void setLiquid(BlockMaterial liquid) { |
|
|
this.liquid = liquid; |
|
|
} |
|
|
|
|
|
public void biomeAdaptedSurface(boolean biomeAdaptedSurface) { |
|
|
this.biomeAdaptedSurface = biomeAdaptedSurface; |
|
|
} |
|
|
|
|
|
public void stoneWalls(boolean stoneWalls) { |
|
|
this.stoneWalls = stoneWalls; |
|
|
} |
|
|
|
|
|
public void stonyTop(boolean stonyTop) { |
|
|
this.stonyTop = stonyTop; |
|
|
} |
|
|
|
|
|
public static enum PondType { |
|
|
|
|
|
WATER(VanillaMaterials.STATIONARY_WATER, false, false, true), |
|
|
LAVA(VanillaMaterials.STATIONARY_LAVA, true, true, true); |
|
|
// |
|
|
private final BlockMaterial liquid; |
|
|
private final boolean stoneWalls; |
|
|
private final boolean stonyTop; |
|
|
private final boolean biomeSurface; |
|
|
|
|
|
private PondType(BlockMaterial liquid, boolean stoneWalls, boolean stonyTop, boolean biomeSurface) { |
|
|
this.liquid = liquid; |
|
|
this.stoneWalls = stoneWalls; |
|
|
this.stonyTop = stonyTop; |
|
|
this.biomeSurface = biomeSurface; |
|
|
} |
|
|
|
|
|
public boolean biomeAdaptedSurface() { |
|
|
return biomeSurface; |
|
|
} |
|
|
|
|
|
public BlockMaterial getLiquid() { |
|
|
return liquid; |
|
|
} |
|
|
|
|
|
public boolean stoneWalls() { |
|
|
return stoneWalls; |
|
|
} |
|
|
|
|
|
public boolean stonyTop() { |
|
|
return stonyTop; |
|
|
} |
|
|
} |
|
|
} |