Snow heightmap!
This commit is contained in:
parent
1b71bcd4a1
commit
eedc3f4069
@ -99,6 +99,7 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.history.change.EntityCreate;
|
||||
import com.sk89q.worldedit.history.change.EntityRemove;
|
||||
import com.sk89q.worldedit.math.convolution.HeightMap;
|
||||
import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
@ -432,6 +433,7 @@ public class Fawe {
|
||||
ExtentEntityCopy.inject(); // Async entity create fix
|
||||
// Transforms
|
||||
FlattenedClipboardTransform.inject(); // public access
|
||||
HeightMap.inject(); // Optimizations + Features
|
||||
// Entity create/remove
|
||||
EntityCreate.inject(); // Optimizations
|
||||
EntityRemove.inject(); // Optimizations
|
||||
|
@ -13,8 +13,8 @@ import java.io.InputStream;
|
||||
|
||||
public class FlattenBrush extends HeightBrush {
|
||||
|
||||
public FlattenBrush(InputStream stream, int rotation, double yscale, Clipboard clipboard, ScalableHeightMap.Shape shape) {
|
||||
super(stream, rotation, yscale, clipboard, shape);
|
||||
public FlattenBrush(InputStream stream, int rotation, double yscale, boolean layers, Clipboard clipboard, ScalableHeightMap.Shape shape) {
|
||||
super(stream, rotation, yscale, layers, clipboard, shape);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -26,6 +26,6 @@ public class FlattenBrush extends HeightBrush {
|
||||
}
|
||||
HeightMap map = getHeightMap();
|
||||
map.setSize(size);
|
||||
map.perform(editSession, mask, position, size, rotation, yscale, true, true);
|
||||
map.perform(editSession, mask, position, size, rotation, yscale, true, true, layers);
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,16 @@ public class HeightBrush implements Brush {
|
||||
private boolean randomRotate;
|
||||
public final int rotation;
|
||||
public final double yscale;
|
||||
public final boolean layers;
|
||||
|
||||
public HeightBrush(InputStream stream, int rotation, double yscale, Clipboard clipboard) {
|
||||
this(stream, rotation, yscale, clipboard, ScalableHeightMap.Shape.CONE);
|
||||
public HeightBrush(InputStream stream, int rotation, double yscale, boolean layers, Clipboard clipboard) {
|
||||
this(stream, rotation, yscale, layers, clipboard, ScalableHeightMap.Shape.CONE);
|
||||
}
|
||||
|
||||
public HeightBrush(InputStream stream, int rotation, double yscale, Clipboard clipboard, ScalableHeightMap.Shape shape) {
|
||||
public HeightBrush(InputStream stream, int rotation, double yscale, boolean layers, Clipboard clipboard, ScalableHeightMap.Shape shape) {
|
||||
this.rotation = (rotation / 90) % 4;
|
||||
this.yscale = yscale;
|
||||
this.layers = layers;
|
||||
if (stream != null) {
|
||||
try {
|
||||
heightMap = ScalableHeightMap.fromPNG(stream);
|
||||
@ -68,6 +70,6 @@ public class HeightBrush implements Brush {
|
||||
}
|
||||
HeightMap map = getHeightMap();
|
||||
map.setSize(size);
|
||||
map.perform(editSession, mask, position, size, rotation, yscale, true, false);
|
||||
map.perform(editSession, mask, position, size, rotation, yscale, true, false, layers);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ public class StencilBrush extends HeightBrush {
|
||||
private final boolean onlyWhite;
|
||||
|
||||
public StencilBrush(InputStream stream, int rotation, double yscale, boolean onlyWhite, Clipboard clipboard) {
|
||||
super(stream, rotation, yscale, clipboard);
|
||||
super(stream, rotation, yscale, false, clipboard);
|
||||
this.onlyWhite = onlyWhite;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.WorldVector;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.internal.LocalWorldAdapter;
|
||||
@ -19,12 +20,12 @@ public interface HeightMap {
|
||||
public void setSize(int size);
|
||||
|
||||
|
||||
default void perform(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
||||
int[] data = generateHeightData(session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
||||
applyHeightMapData(data, session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
||||
default void perform(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards, boolean layers) throws MaxChangedBlocksException {
|
||||
int[][] data = generateHeightData(session, mask, pos, size, rotationMode, yscale, smooth, towards, layers);
|
||||
applyHeightMapData(data, session, mask, pos, size, rotationMode, yscale, smooth, towards, layers);
|
||||
}
|
||||
|
||||
default void applyHeightMapData(int[] data, EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
||||
default void applyHeightMapData(int[][] data, EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards, boolean layers) throws MaxChangedBlocksException {
|
||||
Vector top = session.getMaximumPoint();
|
||||
int maxY = top.getBlockY();
|
||||
int diameter = 2 * size + 1;
|
||||
@ -32,19 +33,29 @@ public interface HeightMap {
|
||||
WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, maxY, size));
|
||||
Vector max = pos.add(size, maxY, size);
|
||||
Region region = new CuboidRegion(session.getWorld(), min, max);
|
||||
com.sk89q.worldedit.math.convolution.HeightMap heightMap = new com.sk89q.worldedit.math.convolution.HeightMap(session, region, false);
|
||||
com.sk89q.worldedit.math.convolution.HeightMap heightMap = new com.sk89q.worldedit.math.convolution.HeightMap(session, region, data[0]);
|
||||
if (smooth) {
|
||||
try {
|
||||
HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1));
|
||||
data = filter.filter(data, diameter, diameter);
|
||||
data[1] = filter.filter(data[1], diameter, diameter);
|
||||
} catch (Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
}
|
||||
heightMap.apply(data);
|
||||
try {
|
||||
if (layers) {
|
||||
heightMap.applyLayers(data[1]);
|
||||
} else {
|
||||
heightMap.apply(data[1]);
|
||||
}
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
throw e;
|
||||
} catch (WorldEditException e2) {
|
||||
throw new RuntimeException(e2);
|
||||
}
|
||||
}
|
||||
|
||||
default int[] generateHeightData(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) {
|
||||
default int[][] generateHeightData(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards, final boolean layers) {
|
||||
Vector top = session.getMaximumPoint();
|
||||
int maxY = top.getBlockY();
|
||||
int diameter = 2 * size + 1;
|
||||
@ -53,7 +64,12 @@ public interface HeightMap {
|
||||
int centerY = pos.getBlockY();
|
||||
int endY = pos.getBlockY() + size;
|
||||
int startY = pos.getBlockY() - size;
|
||||
int[] newData = new int[diameter * diameter];
|
||||
int[] oldData = new int[diameter * diameter];
|
||||
int[] newData = new int[oldData.length];
|
||||
if (layers) { // Pixel accuracy
|
||||
centerY <<= 3;
|
||||
maxY <<= 3;
|
||||
}
|
||||
Vector mutablePos = new Vector(0, 0, 0);
|
||||
if (towards) {
|
||||
double sizePow = Math.pow(size, yscale);
|
||||
@ -79,7 +95,13 @@ public interface HeightMap {
|
||||
raise = getHeight(-z, -x);
|
||||
break;
|
||||
}
|
||||
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, 255);
|
||||
int height;
|
||||
if (layers) {
|
||||
height = session.getNearestSurfaceLayer(xx, zz, pos.getBlockY(), 0, maxY);
|
||||
} else {
|
||||
height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY);
|
||||
}
|
||||
oldData[index] = height;
|
||||
if (height == 0) {
|
||||
newData[index] = centerY;
|
||||
continue;
|
||||
@ -115,18 +137,24 @@ public interface HeightMap {
|
||||
raise = getHeight(-z, -x);
|
||||
break;
|
||||
}
|
||||
int height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY);
|
||||
int height;
|
||||
if (layers) {
|
||||
height = session.getNearestSurfaceLayer(xx, zz, pos.getBlockY(), 0, maxY);
|
||||
} else {
|
||||
height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, 255);
|
||||
}
|
||||
oldData[index] = height;
|
||||
if (height == 0) {
|
||||
newData[index] = centerY;
|
||||
continue;
|
||||
}
|
||||
raise = (yscale * raise);
|
||||
int random = PseudoRandom.random.random(maxY + 1) < (int) ((raise - (int) raise) * (maxY + 1)) ? 1 : 0;
|
||||
int random = PseudoRandom.random.random(256) < (int) ((raise - (int) raise) * (256)) ? 1 : 0;
|
||||
int newHeight = height + (int) raise + random;
|
||||
newData[index] = newHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newData;
|
||||
return new int[][] {oldData, newData};
|
||||
}
|
||||
}
|
||||
|
@ -981,6 +981,52 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
return this.getHighestTerrainBlock(x, z, minY, maxY, false);
|
||||
}
|
||||
|
||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
int clearance = Math.min(clearanceAbove, clearanceBelow);
|
||||
|
||||
BaseBlock block = getBlock(x, y, z);
|
||||
boolean state = FaweCache.isLiquidOrGas(block.getId());
|
||||
int data1 = block.getData();
|
||||
int data2 = block.getData();
|
||||
int offset = state ? 0 : 1;
|
||||
for (int d = 0; d <= clearance; d++) {
|
||||
int y1 = y + d;
|
||||
block = getLazyBlock(x, y1, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((y1 - offset) << 3) - (7 - (state ? block.getData() : data1));
|
||||
}
|
||||
data1 = block.getData();
|
||||
int y2 = y - d;
|
||||
block = getLazyBlock(x, y2, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((y2 + offset) << 3) - (7 - (state ? block.getData() : data2));
|
||||
}
|
||||
data2 = block.getData();
|
||||
}
|
||||
if (clearanceAbove != clearanceBelow) {
|
||||
if (clearanceAbove < clearanceBelow) {
|
||||
for (int layer = y - clearance - 1; layer >= minY; layer--) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((layer + offset) << 3) - (7 - (state ? block.getData() : data1));
|
||||
}
|
||||
data1 = block.getData();
|
||||
}
|
||||
} else {
|
||||
for (int layer = y + clearance + 1; layer <= maxY; layer++) {
|
||||
block = getLazyBlock(x, layer, z);
|
||||
if (FaweCache.isLiquidOrGas(block.getId()) != state) {
|
||||
return ((layer - offset) << 3) - (7 - (state ? block.getData() : data2));
|
||||
}
|
||||
data2 = block.getData();
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxY << 4;
|
||||
}
|
||||
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
|
@ -714,13 +714,15 @@ public class BrushCommands {
|
||||
flags = "h",
|
||||
desc = "Height brush",
|
||||
help =
|
||||
"This brush raises and lowers land.\n",
|
||||
"This brush raises and lowers land.\n" +
|
||||
"The -r flag enables random off-axis rotation\n" +
|
||||
"The -l flag will work on snow layers",
|
||||
min = 1,
|
||||
max = 4
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.height")
|
||||
public void heightBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||
terrainBrush(player, session, radius, filename, rotation, yscale, false, randomRotate, ScalableHeightMap.Shape.CONE);
|
||||
public void heightBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate, @Switch('l') boolean layers) throws WorldEditException {
|
||||
terrainBrush(player, session, radius, filename, rotation, yscale, false, randomRotate, layers, ScalableHeightMap.Shape.CONE);
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -729,28 +731,32 @@ public class BrushCommands {
|
||||
flags = "h",
|
||||
desc = "Cliff brush",
|
||||
help =
|
||||
"This brush flattens terrain and creates cliffs.\n",
|
||||
"This brush flattens terrain and creates cliffs.\n" +
|
||||
"The -r flag enables random off-axis rotation\n" +
|
||||
"The -l flag will work on snow layers",
|
||||
min = 1,
|
||||
max = 4
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.height")
|
||||
public void cliffBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, randomRotate, ScalableHeightMap.Shape.CYLINDER);
|
||||
public void cliffBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate, @Switch('l') boolean layers) throws WorldEditException {
|
||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, randomRotate, layers, ScalableHeightMap.Shape.CYLINDER);
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "flatten", "flatmap", "flat" },
|
||||
usage = "[radius] [file|#clipboard|null] [rotation] [yscale]",
|
||||
flags = "h",
|
||||
desc = "Flatten brush",
|
||||
desc = "Flatten brush makes terrain flatter\n" +
|
||||
"The -r flag enables random off-axis rotation\n" +
|
||||
"The -l flag will work on snow layers",
|
||||
help =
|
||||
"This brush raises and lowers land towards the clicked point\n",
|
||||
min = 1,
|
||||
max = 4
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.height")
|
||||
public void flattenBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate) throws WorldEditException {
|
||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, randomRotate, ScalableHeightMap.Shape.CONE);
|
||||
public void flattenBrush(Player player, LocalSession session, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('r') boolean randomRotate, @Switch('l') boolean layers) throws WorldEditException {
|
||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, randomRotate, layers, ScalableHeightMap.Shape.CONE);
|
||||
}
|
||||
|
||||
private InputStream getHeightmapStream(String filename) {
|
||||
@ -784,7 +790,7 @@ public class BrushCommands {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void terrainBrush(Player player, LocalSession session, double radius, String filename, int rotation, double yscale, boolean flat, boolean randomRotate, ScalableHeightMap.Shape shape) throws WorldEditException {
|
||||
private void terrainBrush(Player player, LocalSession session, double radius, String filename, int rotation, double yscale, boolean flat, boolean randomRotate, boolean layers, ScalableHeightMap.Shape shape) throws WorldEditException {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
InputStream stream = getHeightmapStream(filename);
|
||||
BrushTool tool = session.getBrushTool(player);
|
||||
@ -792,15 +798,15 @@ public class BrushCommands {
|
||||
HeightBrush brush;
|
||||
if (flat) {
|
||||
try {
|
||||
brush = new FlattenBrush(stream, rotation, yscale, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null, shape);
|
||||
brush = new FlattenBrush(stream, rotation, yscale, layers, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null, shape);
|
||||
} catch (EmptyClipboardException ignore) {
|
||||
brush = new FlattenBrush(stream, rotation, yscale, null, shape);
|
||||
brush = new FlattenBrush(stream, rotation, yscale, layers, null, shape);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
brush = new HeightBrush(stream, rotation, yscale, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null);
|
||||
brush = new HeightBrush(stream, rotation, yscale, layers, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null);
|
||||
} catch (EmptyClipboardException ignore) {
|
||||
brush = new HeightBrush(stream, rotation, yscale, null);
|
||||
brush = new HeightBrush(stream, rotation, yscale, layers, null);
|
||||
}
|
||||
}
|
||||
tool.setBrush(brush, "worldedit.brush.height", player);
|
||||
|
@ -0,0 +1,242 @@
|
||||
package com.sk89q.worldedit.math.convolution;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Allows applications of Kernels onto the region's height map.
|
||||
*
|
||||
* <p>Currently only used for smoothing (with a GaussianKernel)</p>.
|
||||
*/
|
||||
public class HeightMap {
|
||||
|
||||
private int[] data;
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
private Region region;
|
||||
private EditSession session;
|
||||
|
||||
/**
|
||||
* Constructs the HeightMap
|
||||
*
|
||||
* @param session an edit session
|
||||
* @param region the region
|
||||
*/
|
||||
public HeightMap(EditSession session, Region region) {
|
||||
this(session, region, false);
|
||||
}
|
||||
|
||||
public HeightMap(EditSession session, Region region, boolean naturalOnly) {
|
||||
checkNotNull(session);
|
||||
checkNotNull(region);
|
||||
|
||||
this.session = session;
|
||||
this.region = region;
|
||||
|
||||
this.width = region.getWidth();
|
||||
this.height = region.getLength();
|
||||
|
||||
int minX = region.getMinimumPoint().getBlockX();
|
||||
int minY = region.getMinimumPoint().getBlockY();
|
||||
int minZ = region.getMinimumPoint().getBlockZ();
|
||||
int maxY = region.getMaximumPoint().getBlockY();
|
||||
|
||||
// Store current heightmap data
|
||||
data = new int[width * height];
|
||||
for (int z = 0; z < height; ++z) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
data[z * width + x] = session.getHighestTerrainBlock(x + minX, z + minZ, minY, maxY, naturalOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HeightMap(EditSession session, Region region, int[] data) {
|
||||
this.session = session;
|
||||
this.region = region;
|
||||
|
||||
this.width = region.getWidth();
|
||||
this.height = region.getLength();
|
||||
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter 'iterations' amount times.
|
||||
*
|
||||
* @param filter the filter
|
||||
* @param iterations the number of iterations
|
||||
* @return number of blocks affected
|
||||
* @throws MaxChangedBlocksException
|
||||
*/
|
||||
|
||||
public int applyFilter(HeightMapFilter filter, int iterations) throws WorldEditException {
|
||||
checkNotNull(filter);
|
||||
|
||||
int[] newData = new int[data.length];
|
||||
System.arraycopy(data, 0, newData, 0, data.length);
|
||||
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
newData = filter.filter(newData, width, height);
|
||||
}
|
||||
|
||||
return apply(newData);
|
||||
}
|
||||
|
||||
public int applyLayers(int[] data) throws WorldEditException {
|
||||
checkNotNull(data);
|
||||
|
||||
Vector minY = region.getMinimumPoint();
|
||||
int originX = minY.getBlockX();
|
||||
int originY = minY.getBlockY();
|
||||
int originZ = minY.getBlockZ();
|
||||
|
||||
int maxY = region.getMaximumPoint().getBlockY();
|
||||
BaseBlock fillerAir = EditSession.nullBlock;
|
||||
|
||||
int blocksChanged = 0;
|
||||
|
||||
// Apply heightmap
|
||||
int maxY4 = maxY << 4;
|
||||
int index = 0;
|
||||
for (int z = 0; z < height; ++z) {
|
||||
int zr = z + originZ;
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int curHeight = this.data[index];
|
||||
int newHeight = Math.min(maxY4, data[index++]);
|
||||
int curBlock = (curHeight) >> 3;
|
||||
int newBlock = (newHeight + 7) >> 3;
|
||||
int xr = x + originX;
|
||||
|
||||
// We are keeping the topmost blocks so take that in account for the scale
|
||||
double scale = (double) (curHeight - originY) / (double) (newHeight - originY);
|
||||
|
||||
// Depending on growing or shrinking we need to start at the bottom or top
|
||||
if (newHeight > curHeight) {
|
||||
// Set the top block of the column to be the same type (this might go wrong with rounding)
|
||||
BaseBlock existing = session.getBlock(xr, curBlock, zr);
|
||||
|
||||
// Skip water/lava
|
||||
if (!FaweCache.isLiquidOrGas(existing.getId())) {
|
||||
// Grow -- start from 1 below top replacing airblocks
|
||||
for (int y = newBlock - 1 - originY; y >= curBlock; --y) {
|
||||
int copyFrom = (int) (y * scale);
|
||||
session.setBlock(xr, originY + y, zr, session.getBlock(xr, originY + copyFrom, zr));
|
||||
++blocksChanged;
|
||||
}
|
||||
int setData = newHeight & 7;
|
||||
if (setData != 0) {
|
||||
existing = FaweCache.getBlock(existing.getId(), setData - 1);
|
||||
session.setBlock(xr, newBlock, zr, existing);
|
||||
++blocksChanged;
|
||||
} else {
|
||||
existing = FaweCache.getBlock(existing.getId(), 7);
|
||||
session.setBlock(xr, newBlock, zr, existing);
|
||||
++blocksChanged;
|
||||
}
|
||||
}
|
||||
} else if (curHeight > newHeight) {
|
||||
// Fill rest with air
|
||||
for (int y = newBlock + 1; y <= ((curHeight + 7) >> 3); ++y) {
|
||||
session.setBlock(xr, y, zr, fillerAir);
|
||||
++blocksChanged;
|
||||
}
|
||||
// Set the top block of the column to be the same type
|
||||
// (this could otherwise go wrong with rounding)
|
||||
int setData = newHeight & 7;
|
||||
BaseBlock existing = session.getBlock(xr, curBlock, zr);
|
||||
if (setData != 0) {
|
||||
existing = FaweCache.getBlock(existing.getId(), setData - 1);
|
||||
session.setBlock(xr, newBlock, zr, existing);
|
||||
} else {
|
||||
existing = FaweCache.getBlock(existing.getId(), 7);
|
||||
session.setBlock(xr, newBlock, zr, existing);
|
||||
}
|
||||
++blocksChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocksChanged;
|
||||
}
|
||||
|
||||
public int apply(int[] data) throws WorldEditException {
|
||||
checkNotNull(data);
|
||||
|
||||
Vector minY = region.getMinimumPoint();
|
||||
int originX = minY.getBlockX();
|
||||
int originY = minY.getBlockY();
|
||||
int originZ = minY.getBlockZ();
|
||||
|
||||
int maxY = region.getMaximumPoint().getBlockY();
|
||||
BaseBlock fillerAir = EditSession.nullBlock;
|
||||
|
||||
int blocksChanged = 0;
|
||||
|
||||
// Apply heightmap
|
||||
int index = 0;
|
||||
for (int z = 0; z < height; ++z) {
|
||||
int zr = z + originZ;
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int curHeight = this.data[index];
|
||||
int newHeight = Math.min(maxY, data[index++]);
|
||||
int xr = x + originX;
|
||||
|
||||
// We are keeping the topmost blocks so take that in account for the scale
|
||||
double scale = (double) (curHeight - originY) / (double) (newHeight - originY);
|
||||
|
||||
// Depending on growing or shrinking we need to start at the bottom or top
|
||||
if (newHeight > curHeight) {
|
||||
// Set the top block of the column to be the same type (this might go wrong with rounding)
|
||||
BaseBlock existing = session.getBlock(xr, curHeight, zr);
|
||||
|
||||
// Skip water/lava
|
||||
if (!FaweCache.isLiquidOrGas(existing.getId())) {
|
||||
session.setBlock(xr, newHeight, zr, existing);
|
||||
++blocksChanged;
|
||||
|
||||
// Grow -- start from 1 below top replacing airblocks
|
||||
for (int y = newHeight - 1 - originY; y >= 0; --y) {
|
||||
int copyFrom = (int) (y * scale);
|
||||
session.setBlock(xr, originY + y, zr, session.getBlock(xr, originY + copyFrom, zr));
|
||||
++blocksChanged;
|
||||
}
|
||||
}
|
||||
} else if (curHeight > newHeight) {
|
||||
// Shrink -- start from bottom
|
||||
for (int y = 0; y < newHeight - originY; ++y) {
|
||||
int copyFrom = (int) (y * scale);
|
||||
session.setBlock(xr, originY + y, zr, session.getBlock(xr, originY + copyFrom, zr));
|
||||
++blocksChanged;
|
||||
}
|
||||
|
||||
// Set the top block of the column to be the same type
|
||||
// (this could otherwise go wrong with rounding)
|
||||
session.setBlock(xr, newHeight, zr, session.getBlock(xr, curHeight, zr));
|
||||
++blocksChanged;
|
||||
|
||||
// Fill rest with air
|
||||
for (int y = newHeight + 1; y <= curHeight; ++y) {
|
||||
session.setBlock(xr, y, zr, fillerAir);
|
||||
++blocksChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocksChanged;
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return HeightMap.class;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user