package net.glowstone.generator.populators;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.generator.BlockPopulator;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* BlockPopulator for snake-based caves.
*/
public class CavePopulator extends BlockPopulator {
private static class FinishSnakeTask implements Runnable {
private final Location[] snake;
public FinishSnakeTask(Set<Location> snake) {
this.snake = snake.toArray(new Location[snake.size()]);
}
@Override
public void run() {
for (Location loc : snake) {
Block block = loc.getBlock();
if (!block.isEmpty() && !block.isLiquid() && block.getType() != Material.BEDROCK) {
block.setType(Material.AIR);
}
}
for (Location loc : snake) {
loc.getWorld().unloadChunkRequest(loc.getBlockX() / 16, loc.getBlockZ() / 16);
}
}
}
@Override
public void populate(final World world, final Random random, Chunk source) {
if (random.nextInt(100) < 10) {
final int x = 4 + random.nextInt(8) + source.getX() * 16;
final int z = 4 + random.nextInt(8) + source.getZ() * 16;
int maxY = world.getHighestBlockYAt(x, z);
if (maxY < 16) {
maxY = 32;
}
final int y = random.nextInt(maxY);
new Thread(new Runnable() {
@Override
public void run() {
Set<Location> snake = startSnake(world, random, x, y, z);
// Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(GenPlugin.instance, new FinishSnake(world, snake));
if (random.nextInt(16) > 5) {
if (y > 36) {
snake = startSnake(world, random, x, y / 2, z);
// Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(GenPlugin.instance, new FinishSnake(world, snake));
} else if (y < 24) {
snake = startSnake(world, random, x, y * 2, z);
// Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(GenPlugin.instance, new FinishSnake(world, snake));
}
}
}
}).start();
}
}
private static Set<Location> startSnake(World world, Random random, int blockX, int blockY, int blockZ) {
Set<Location> snakeBlocks = new HashSet<>();
int airHits = 0;
while (true) {
if (airHits > 2000) {
break;
}
if (random.nextInt(20) == 0) {
blockY++;
} else if (world.getBlockTypeIdAt(blockX, blockY + 2, blockZ) == 0) {
blockY += 2;
} else if (world.getBlockTypeIdAt(blockX + 2, blockY, blockZ) == 0) {
blockX++;
} else if (world.getBlockTypeIdAt(blockX - 2, blockY, blockZ) == 0) {
blockX--;
} else if (world.getBlockTypeIdAt(blockX, blockY, blockZ + 2) == 0) {
blockZ++;
} else if (world.getBlockTypeIdAt(blockX, blockY, blockZ - 2) == 0) {
blockZ--;
} else if (world.getBlockTypeIdAt(blockX + 1, blockY, blockZ) == 0) {
blockX++;
} else if (world.getBlockTypeIdAt(blockX - 1, blockY, blockZ) == 0) {
blockX--;
} else if (world.getBlockTypeIdAt(blockX, blockY, blockZ + 1) == 0) {
blockZ++;
} else if (world.getBlockTypeIdAt(blockX, blockY, blockZ - 1) == 0) {
blockZ--;
} else if (random.nextBoolean()) {
if (random.nextBoolean()) {
blockX++;
} else {
blockZ++;
}
} else {
if (random.nextBoolean()) {
blockX--;
} else {
blockZ--;
}
}
if (world.getBlockTypeIdAt(blockX, blockY, blockZ) != 0) {
int radius = 1 + random.nextInt(3);
int radius2 = radius * radius + 1;
for (int x = -radius; x <= radius; x++) {
for (int y = -radius; y <= radius; y++) {
for (int z = -radius; z <= radius; z++) {
if (x * x + y * y + z * z <= radius2 && y >= 0 && y < 128) {
if (world.getBlockTypeIdAt(blockX + x, blockY + y, blockZ + z) == 0) {
airHits++;
} else {
snakeBlocks.add(new Location(world, blockX + x, blockY + y, blockZ + z));
}
}
}
}
}
} else {
airHits++;
}
}
return snakeBlocks;
}
}