/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.layers.exporters;
import org.pepsoft.util.MathUtils;
import org.pepsoft.util.PerlinNoise;
import org.pepsoft.worldpainter.Dimension;
import org.pepsoft.worldpainter.exporting.AbstractLayerExporter;
import org.pepsoft.worldpainter.exporting.Fixup;
import org.pepsoft.worldpainter.exporting.MinecraftWorld;
import org.pepsoft.worldpainter.exporting.SecondPassLayerExporter;
import org.pepsoft.worldpainter.layers.Void;
import java.awt.*;
import java.util.List;
import static org.pepsoft.minecraft.Constants.BLK_STATIONARY_LAVA;
import static org.pepsoft.minecraft.Constants.BLK_STATIONARY_WATER;
import static org.pepsoft.minecraft.Material.AIR;
import static org.pepsoft.worldpainter.Constants.SMALL_BLOBS;
/**
* This exporter does the second half of the void processing. The first half
* has been performed in the first pass by hardcoded code which has left any
* columns marked as Void completely empty.
*
* <p>This plugin does some decoration around the void areas.
*
* @author pepijn
*/
public class VoidExporter extends AbstractLayerExporter<org.pepsoft.worldpainter.layers.Void> implements SecondPassLayerExporter {
public VoidExporter() {
super(Void.INSTANCE);
}
@Override
public List<Fixup> render(Dimension dimension, Rectangle area, Rectangle exportedArea, MinecraftWorld minecraftWorld) {
if (noise.getSeed() != (dimension.getSeed() + SEED_OFFSET)) {
noise.setSeed(dimension.getSeed() + SEED_OFFSET);
}
for (int x = area.x; x < area.x + area.width; x++) {
for (int y = area.y; y < area.y + area.height; y++) {
if (dimension.getBitLayerValueAt(Void.INSTANCE, x, y)
&& (dimension.getDistanceToEdge(Void.INSTANCE, x, y, 2) < 2)) {
// We're on the edge of the Void
processEdgeColumn(dimension, x, y, minecraftWorld);
}
}
}
return null;
}
private void processEdgeColumn(final Dimension dimension, final int x, final int y, final MinecraftWorld minecraftWorld) {
final int maxHeight = minecraftWorld.getMaxHeight();
// Taper the world edges slightly inward
final int r = 3;
for (int dx = -r; dx <= r; dx++) {
for (int dy = -r; dy <= r; dy++) {
if ((dx != 0) || (dy != 0)) {
final int x2 = x + dx, y2 = y + dy;
if (dimension.getBitLayerValueAt(Void.INSTANCE, x2, y2)) {
continue;
}
final float distance = MathUtils.getDistance(dx, dy);
final float height = dimension.getHeightAt(x2, y2);
final int depth = (int) (height / Math.pow(2, distance + noise.getPerlinNoise(x2 / SMALL_BLOBS, y2 / SMALL_BLOBS)) + 0.5f);
for (int z = 0; z < depth; z++) {
minecraftWorld.setMaterialAt(x2, y2, z, AIR);
}
}
}
}
// Check for water surrounding the column; pre-render the falling water
// column to avoid long pauses in Minecraft when the chunks are loaded
// (but not for ceiling dimensions)
if (dimension.getDim() >= 0) {
for (int z = maxHeight - 1; z >= 0; z--) {
if ((minecraftWorld.getBlockTypeAt(x, y, z) == BLK_STATIONARY_WATER)
|| (minecraftWorld.getBlockTypeAt(x, y, z) == BLK_STATIONARY_LAVA)) {
// A previous iteration already placed fluid here
break;
} else if (isWaterAndNotVoid(dimension, minecraftWorld, x - 1, y, z)
|| isWaterAndNotVoid(dimension, minecraftWorld, x, y - 1, z)
|| isWaterAndNotVoid(dimension, minecraftWorld, x + 1, y, z)
|| isWaterAndNotVoid(dimension, minecraftWorld, x, y + 1, z)) {
minecraftWorld.setBlockTypeAt(x, y, z, BLK_STATIONARY_WATER);
minecraftWorld.setDataAt(x, y, z, 1);
for (z--; z >= 0; z--) {
minecraftWorld.setBlockTypeAt(x, y, z, BLK_STATIONARY_WATER);
minecraftWorld.setDataAt(x, y, z, 9);
}
break;
} else if (isLavaAndNotVoid(dimension, minecraftWorld, x - 1, y, z)
|| isLavaAndNotVoid(dimension, minecraftWorld, x, y - 1, z)
|| isLavaAndNotVoid(dimension, minecraftWorld, x + 1, y, z)
|| isLavaAndNotVoid(dimension, minecraftWorld, x, y + 1, z)) {
minecraftWorld.setBlockTypeAt(x, y, z, BLK_STATIONARY_LAVA);
minecraftWorld.setDataAt(x, y, z, 2);
for (z--; z >= 0; z--) {
minecraftWorld.setBlockTypeAt(x, y, z, BLK_STATIONARY_LAVA);
minecraftWorld.setDataAt(x, y, z, 10);
}
break;
}
}
}
}
private boolean isWaterAndNotVoid(Dimension dimension, MinecraftWorld minecraftWorld, int x, int y, int z) {
return (! dimension.getBitLayerValueAt(Void.INSTANCE, x, y)) && (minecraftWorld.getBlockTypeAt(x, y, z) == BLK_STATIONARY_WATER);
}
private boolean isLavaAndNotVoid(Dimension dimension, MinecraftWorld minecraftWorld, int x, int y, int z) {
return (! dimension.getBitLayerValueAt(Void.INSTANCE, x, y)) && (minecraftWorld.getBlockTypeAt(x, y, z) == BLK_STATIONARY_LAVA);
}
private final PerlinNoise noise = new PerlinNoise(0);
private static final long SEED_OFFSET = 142644289;
}