Various minor

Stencil/Color brush can now be used on any surface, not just the top
Optimize adjacency and radius mask
This commit is contained in:
Jesse Boyd 2017-03-11 00:27:39 +11:00
parent 0434755333
commit 5bbc381dd0
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
8 changed files with 194 additions and 41 deletions

View File

@ -119,7 +119,6 @@ public class FawePrimitiveBinding extends BindingHelper {
try {
return Double.parseDouble(input);
} catch (NumberFormatException e1) {
System.out.println("NUMBER FORMAT EXCEPTION " + e1);
try {
Expression expression = Expression.compile(input);
return expression.evaluate();

View File

@ -1,56 +1,117 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.RadiusMask;
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.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import java.io.InputStream;
import java.util.Arrays;
public class StencilBrush extends HeightBrush {
private final boolean onlyWhite;
private final int depth;
public StencilBrush(InputStream stream, int depth, int rotation, double yscale, boolean onlyWhite, Clipboard clipboard) {
public StencilBrush(InputStream stream, int rotation, double yscale, boolean onlyWhite, Clipboard clipboard) {
super(stream, rotation, yscale, clipboard);
this.onlyWhite = onlyWhite;
this.depth = depth;
}
@Override
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
final int cx = position.getBlockX();
final int cy = position.getBlockY();
final int cz = position.getBlockZ();
int size = (int) sizeDouble;
Mask mask = new ExistingBlockMask(editSession);
int maxY = editSession.getMaxY();
double scale = (yscale / sizeDouble) * (maxY + 1);
heightMap.setSize(size);
int cutoff = onlyWhite ? maxY : 0;
for (int x = -size; x <= size; x++) {
int xx = position.getBlockX() + x;
for (int z = -size; z <= size; z++) {
double raise;
switch (rotation) {
default:raise = heightMap.getHeight(x, z); break;
case 1: raise = heightMap.getHeight(z, x); break;
case 2: raise = heightMap.getHeight(-x, -z); break;
case 3: raise = heightMap.getHeight(-z, -x);break;
}
int val = (int) Math.ceil(raise * scale);
if (val <= cutoff) {
continue;
}
if (val >= 255 || PseudoRandom.random.random(maxY) < val) {
int zz = position.getBlockZ() + z;
int y = editSession.getNearestSurfaceTerrainBlock(xx, zz, position.getBlockY(), 0, maxY);
for (int i = 0; i < depth; i++) {
editSession.setBlock(xx, y - i, zz, pattern);
final AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
final SolidBlockMask solid = new SolidBlockMask(editSession);
final RadiusMask radius = new RadiusMask(0, size);
RecursiveVisitor visitor = new RecursiveVisitor(new Mask() {
@Override
public boolean test(Vector vector) {
if (solid.test(vector) && radius.test(vector)) {
Vector dir = adjacent.direction(vector);
if (dir != null) {
int dx = vector.getBlockX() - cx;
int dy = vector.getBlockY() - cy;
int dz = vector.getBlockZ() - cz;
if (dy != 0) {
if (dir.getBlockX() != 0) {
dx += dir.getBlockX() * dy;
} else if (dir.getBlockZ() != 0) {
dz += dir.getBlockZ() * dy;
}
}
double raise = heightMap.getHeight(dx, dz);
int val = (int) Math.ceil(raise * scale);
if (val <= cutoff) {
return true;
}
if (val >= 255 || PseudoRandom.random.random(maxY) < val) {
editSession.setBlock(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), pattern);
}
return true;
}
}
return false;
}
}
}, new RegionFunction() {
@Override
public boolean apply(Vector vector) throws WorldEditException {
return true;
}
}, Integer.MAX_VALUE, editSession);
visitor.setDirections(Arrays.asList(visitor.DIAGONAL_DIRECTIONS));
visitor.visit(position);
Operations.completeBlindly(visitor);
// Mask mask = new ExistingBlockMask(editSession);
// int maxY = editSession.getMaxY();
// double scale = (yscale / sizeDouble) * (maxY + 1);
// heightMap.setSize(size);
// int cutoff = onlyWhite ? maxY : 0;
//
// for (int x = -size; x <= size; x++) {
// int xx = position.getBlockX() + x;
// for (int z = -size; z <= size; z++) {
// double raise;
// switch (rotation) {
// default:raise = heightMap.getHeight(x, z); break;
// case 1: raise = heightMap.getHeight(z, x); break;
// case 2: raise = heightMap.getHeight(-x, -z); break;
// case 3: raise = heightMap.getHeight(-z, -x);break;
// }
// int val = (int) Math.ceil(raise * scale);
// if (val <= cutoff) {
// continue;
// }
// if (val >= 255 || PseudoRandom.random.random(maxY) < val) {
// int zz = position.getBlockZ() + z;
// int y = editSession.getNearestSurfaceTerrainBlock(xx, zz, position.getBlockY(), 0, maxY);
// for (int i = 0; i < depth; i++) {
// editSession.setBlock(xx, y - i, zz, pattern);
// }
// }
// }
// }
}
private void apply(double val) {
}
}

View File

@ -0,0 +1,62 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMask;
import java.util.Collection;
/**
* Just an optimized version of the Adjacent Mask for single adjacency
*/
public class AdjacentAnyMask extends BlockMask {
public AdjacentAnyMask(Extent extent, Collection<BaseBlock> blocks) {
super(extent, blocks);
}
@Override
public boolean test(Vector v) {
int x = v.getBlockX();
int y = v.getBlockY();
int z = v.getBlockZ();
v.mutY(y + 1);
if (super.test(v)) { v.mutY(y); return true; }
v.mutY(y - 1);
if (super.test(v)) { v.mutY(y); return true; }
v.mutY(y);
v.mutX(x + 1);
if (super.test(v)) { v.mutX(x); return true; }
v.mutX(x - 1);
if (super.test(v)) { v.mutX(x); return true; }
v.mutX(x);
v.mutZ(z + 1);
if (super.test(v)) { v.mutZ(z); return true; }
v.mutZ(z - 1);
if (super.test(v)) { v.mutZ(z); return true; }
v.mutZ(z);
return false;
}
public Vector direction(Vector v) {
int x = v.getBlockX();
int y = v.getBlockY();
int z = v.getBlockZ();
v.mutY(y + 1);
if (super.test(v)) { v.mutY(y); return MutableBlockVector.get(0, 1, 0); }
v.mutY(y - 1);
if (super.test(v)) { v.mutY(y); return MutableBlockVector.get(0, -1, 0); }
v.mutY(y);
v.mutX(x + 1);
if (super.test(v)) { v.mutX(x); return MutableBlockVector.get(1, 0, 0); }
v.mutX(x - 1);
if (super.test(v)) { v.mutX(x); return MutableBlockVector.get(-1, 0, 0); }
v.mutX(x);
v.mutZ(z + 1);
if (super.test(v)) { v.mutZ(z); return MutableBlockVector.get(0, 0, 1); }
v.mutZ(z - 1);
if (super.test(v)) { v.mutZ(z); return MutableBlockVector.get(0, 0, - 1); }
v.mutZ(z);
return null;
}
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.object.mask;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
@ -24,19 +25,19 @@ public class RadiusMask implements Mask, ResettableMask{
@Override
public boolean test(Vector to) {
if (pos == null) {
pos = new Vector(to);
pos = new MutableBlockVector(to);
}
int dx = Math.abs((int) (pos.getX() - to.getX()));
int dy = Math.abs((int) (pos.getY() - to.getY()));
int dz = Math.abs((int) (pos.getZ() - to.getZ()));
int dx = pos.getBlockX() - to.getBlockX();
int d = dx * dx;
if (d < minSqr || d > maxSqr) {
if (d > maxSqr) {
return false;
}
int dz = pos.getBlockZ() - to.getBlockZ();
d += dz * dz;
if (d < minSqr || d > maxSqr) {
if (d > maxSqr) {
return false;
}
int dy = pos.getBlockY() - to.getBlockY();
d += dy * dy;
if (d < minSqr || d > maxSqr) {
return false;

View File

@ -542,16 +542,16 @@ public class BrushCommands {
max = -1
)
@CommandPermissions("worldedit.brush.stencil")
public void stencilBrush(Player player, LocalSession session, Pattern fill, @Optional("5") double radius, @Optional("1") double depth, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('w') boolean onlyWhite) throws WorldEditException {
public void stencilBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('w') boolean onlyWhite) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
InputStream stream = getHeightmapStream(filename);
tool.setFill(fill);
tool.setSize(radius);
try {
tool.setBrush(new StencilBrush(stream, (int) depth, rotation, yscale, onlyWhite, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height", player);
tool.setBrush(new StencilBrush(stream, rotation, yscale, onlyWhite, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height", player);
} catch (EmptyClipboardException ignore) {
tool.setBrush(new StencilBrush(stream, (int) depth, rotation, yscale, onlyWhite, null), "worldedit.brush.height", player);
tool.setBrush(new StencilBrush(stream, rotation, yscale, onlyWhite, null), "worldedit.brush.height", player);
}
player.print(BBC.getPrefix() + BBC.BRUSH_STENCIL.f(radius));

View File

@ -241,7 +241,7 @@ public class DefaultMaskParser extends FaweParser<Mask> {
return new WallMask(extent, Arrays.asList(new BaseBlock(0)), 1, 8);
case "#surface":
masks.add(new ExistingBlockMask(extent));
return new AdjacentMask(extent, Arrays.asList(new BaseBlock(0)), 1, 8);
return new AdjacentAnyMask(extent, Arrays.asList(new BaseBlock(0)));
default:
throw new SuggestInputParseException(input, HASHTAG_MASKS);
}
@ -297,6 +297,9 @@ public class DefaultMaskParser extends FaweParser<Mask> {
}
}
if (firstChar == '~') {
if (requiredMax >= 8 && requiredMin == 1) {
return new AdjacentAnyMask(extent, worldEdit.getBlockFactory().parseFromListInput(split[0], tempContext));
}
return new AdjacentMask(extent, worldEdit.getBlockFactory().parseFromListInput(split[0], tempContext), requiredMin, requiredMax);
} else {
return new WallMask(extent, worldEdit.getBlockFactory().parseFromListInput(input.substring(1), tempContext), requiredMin, requiredMax);

View File

@ -45,7 +45,9 @@ public interface Mask extends com.sk89q.worldedit.masks.Mask {
* @return a 2D mask version or {@code null} if this mask can't be 2D
*/
@Nullable
Mask2D toMask2D();
default Mask2D toMask2D() {
return null;
}
default void prepare(LocalSession session, LocalPlayer player, Vector target) {}

View File

@ -16,11 +16,14 @@ import com.sk89q.worldedit.function.operation.RunContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public abstract class BreadthFirstSearch implements Operation {
public static Vector[] DEFAULT_DIRECTIONS = new Vector[6];
public static final Vector[] DEFAULT_DIRECTIONS = new Vector[6];
public static final Vector[] DIAGONAL_DIRECTIONS;
static {
DEFAULT_DIRECTIONS[0] = (new MutableBlockVector(0, -1, 0));
DEFAULT_DIRECTIONS[1] = (new MutableBlockVector(0, 1, 0));
@ -28,10 +31,30 @@ public abstract class BreadthFirstSearch implements Operation {
DEFAULT_DIRECTIONS[3] = (new MutableBlockVector(1, 0, 0));
DEFAULT_DIRECTIONS[4] = (new MutableBlockVector(0, 0, -1));
DEFAULT_DIRECTIONS[5] = (new MutableBlockVector(0, 0, 1));
List<MutableBlockVector> list = new ArrayList<>();
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
if (x != 0 || y != 0 || z != 0) {
MutableBlockVector pos = new MutableBlockVector(x, y, z);
if (!list.contains(pos)) {
list.add(pos);
}
}
}
}
}
Collections.sort(list, new Comparator<Vector>() {
@Override
public int compare(Vector o1, Vector o2) {
return (int) Math.signum(o1.lengthSq() - o2.lengthSq());
}
});
DIAGONAL_DIRECTIONS = list.toArray(new Vector[list.size()]);
}
private final RegionFunction function;
private final List<Vector> directions = new ArrayList<>();
private List<Vector> directions = new ArrayList<>();
private BlockVectorSet visited;
private final MappedFaweQueue mFaweQueue;
private BlockVectorSet queue;
@ -62,6 +85,10 @@ public abstract class BreadthFirstSearch implements Operation {
return this.directions;
}
public void setDirections(List<Vector> directions) {
this.directions = directions;
}
private IntegerTrio[] getIntDirections() {
IntegerTrio[] array = new IntegerTrio[directions.size()];
for (int i = 0; i < array.length; i++) {
@ -91,8 +118,6 @@ public abstract class BreadthFirstSearch implements Operation {
return visited.contains(pos);
}
@Override
public Operation resume(RunContext run) throws WorldEditException {
MutableBlockVector mutable = new MutableBlockVector();