Closed creativitRy closed 7 years ago
Thanks for the report! Could you elaborate a little on what you mean by "intersecting but not overlapping" and/or attach a .world file demonstrating the problem?
By "intersecting but not overlapping", I meant that the two layers touch each other but don't occupy the same coordinates. For example, I drew the void layer, and I drew the water layer with a filter except on void.
Here's a world file with the bug. It's not the one on the picture, but the same bug is visible. http://www.mediafire.com/file/s87dblmg2ewbqru/Bug.world
Here are the settings for the water ground cover layer.
I tested it some more, and it seems as though the bug only appears when the width is set to 2 or higher. Also, both stationary water and stationary lava cause the bug.
I didn't look through your code completely, but judging from VoidExporter.java class's processEdgeColumn method, I believe the bug is happening due to processEdgeColumn detecting water placed by itself. You might want to store all the coordinates where the water will be placed into a collection and process them later.
I believe this modification to VoidExporter.java fixes it. Feel free to use (or ignore) this code without mentioning me.
/*
* 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 java.util.ArrayDeque;
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);
}
//if value is true, it is lava
ArrayDeque<FluidEntry> fluids = new ArrayDeque<>();
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, fluids, minecraftWorld);
}
}
}
processFluids(fluids, minecraftWorld);
return null;
}
private void processEdgeColumn(final Dimension dimension, final int x, final int y, ArrayDeque<FluidEntry> fluids, 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;
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 - 1, y, z) == BLK_STATIONARY_WATER)
|| (minecraftWorld.getBlockTypeAt(x, y - 1, z) == BLK_STATIONARY_WATER)
|| (minecraftWorld.getBlockTypeAt(x + 1, y, z) == BLK_STATIONARY_WATER)
|| (minecraftWorld.getBlockTypeAt(x, y + 1, z) == BLK_STATIONARY_WATER)) {
fluids.add(new FluidEntry(x, y, z, false));
break;
} else if ((minecraftWorld.getBlockTypeAt(x - 1, y, z) == BLK_STATIONARY_LAVA)
|| (minecraftWorld.getBlockTypeAt(x, y - 1, z) == BLK_STATIONARY_LAVA)
|| (minecraftWorld.getBlockTypeAt(x + 1, y, z) == BLK_STATIONARY_LAVA)
|| (minecraftWorld.getBlockTypeAt(x, y + 1, z) == BLK_STATIONARY_LAVA)) {
fluids.add(new FluidEntry(x, y, z, true));
break;
}
}
}
}
private void processFluids(ArrayDeque<FluidEntry> fluids, final MinecraftWorld minecraftWorld) {
for (FluidEntry fluid : fluids) {
if (fluid.isLava()) {
minecraftWorld.setBlockTypeAt(fluid.x, fluid.y, fluid.z, BLK_STATIONARY_LAVA);
minecraftWorld.setDataAt(fluid.x, fluid.y, fluid.z, 2);
for (int z = fluid.z - 1; z >= 0; z--) {
minecraftWorld.setBlockTypeAt(fluid.x, fluid.y, z, BLK_STATIONARY_LAVA);
minecraftWorld.setDataAt(fluid.x, fluid.y, z, 10);
}
}
else {
minecraftWorld.setBlockTypeAt(fluid.x, fluid.y, fluid.z, BLK_STATIONARY_WATER);
minecraftWorld.setDataAt(fluid.x, fluid.y, fluid.z, 1);
for (int z = fluid.z - 1; z >= 0; z--) {
minecraftWorld.setBlockTypeAt(fluid.x, fluid.y, z, BLK_STATIONARY_WATER);
minecraftWorld.setDataAt(fluid.x, fluid.y, z, 9);
}
}
}
}
private final PerlinNoise noise = new PerlinNoise(0);
private static final long SEED_OFFSET = 142644289;
private static class FluidEntry {
public FluidEntry(int x, int y, int z, boolean isLava) {
this.x = x;
this.y = y;
this.z = z;
this.isLava = isLava;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public boolean isLava() {
return isLava;
}
private int x;
private int y;
private int z;
private boolean isLava;
}
}
Thanks for the detailed information. I'll look into it!
One pedantic little point: if there's no overlap it can't be intersecting. ;) Hence my confusion. I would call that e.g. "abutting".
If you use the void layer and a ground cover layer with only one block (9: stationary water), and the two layers intersect (but doesn't overlap), water gets randomly placed in the void along the edges. Bug replicable in WorldPainter version 2.3.0.