angle patterns (using different blocks based on the angle)
pattern buffering
- only apply once to a block
- resets when the pattern is no longer being used (brushes?)
Anvil
- schematic population with heightmap
new texture patterns (will document later)
fixes texture complexity and block filtering
Some fixes to height based region commands
Surface brush
Fix line brush -s flag
Add optimized local Vector2D set
Tweak and optimize overlay behavior
Print time on command completion (if duration > 1s)
This commit is contained in:
Jesse Boyd 2017-05-04 13:05:25 +10:00
parent 95faf00467
commit 7586e87644
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
39 changed files with 1157 additions and 180 deletions

View File

@ -7,9 +7,12 @@ import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.brush.visualization.VisualQueue;
import com.boydti.fawe.regions.general.plot.PlotSquaredFeature;
import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.CleanTextureUtil;
import com.boydti.fawe.util.FaweTimer;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.RandomTextureUtil;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.TextureUtil;
@ -321,6 +324,13 @@ public class Fawe {
return updater;
}
public TextureUtil getCachedTextureUtil(boolean randomize, int min, int max) {
TextureUtil tu = getTextureUtil();
tu = min == 0 && max == 100 ? tu : new CleanTextureUtil(tu, min, max);
tu = randomize ? new RandomTextureUtil(tu) : new CachedTextureUtil(tu);
return tu;
}
public TextureUtil getTextureUtil() {
TextureUtil tmp = textures;
if (tmp == null) {
@ -685,10 +695,4 @@ public class Fawe {
public Collection<FawePlayer> getCachedPlayers() {
return players.values();
}
/*
* TODO FIXME
* - Async packet sending
* - Optimize lighting updates / chunk sending
*/
}

View File

@ -128,6 +128,7 @@ public enum BBC {
BRUSH_POPULATE("Populate brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
BRUSH_LAYER("Layer brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
BRUSH_STENCIL("Stencil brush equipped (%s0).", "WorldEdit.Brush"),
BRUSH_SURFACE("Surface brush equipped (%s0).", "WorldEdit.Brush"),
BRUSH_LINE("Line brush shape equipped (%s0).", "WorldEdit.Brush"),
BRUSH_SPLINE("Spline brush shape equipped (%s0). Right click an end to add a shape", "WorldEdit.Brush"),
BRUSH_SPLINE_PRIMARY_2("Added position, Click the same spot to join!", "WorldEdit.Brush"),

View File

@ -3,6 +3,8 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.collection.LocalBlockVector2DSet;
import com.boydti.fawe.object.schematic.Schematic;
import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.RandomTextureUtil;
@ -15,9 +17,12 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.biome.BaseBiome;
@ -110,11 +115,59 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
addCaves(region);
}
@Deprecated
public void addSchems(Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, boolean rotate) throws WorldEditException{
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addSchems(region, mask, worldData, clipboards, rarity, rotate);
}
public void addSchems(BufferedImage img, Mask mask, WorldData worldData, ClipboardHolder[] clipboards, int rarity, int distance, boolean randomRotate) throws WorldEditException{
if (img.getWidth() != getWidth() || img.getHeight() != getLength()) throw new IllegalArgumentException("Input image dimensions do not match the current height map!");
double doubleRarity = rarity / 100d;
int index = 0;
AffineTransform identity = new AffineTransform();
LocalBlockVector2DSet placed = new LocalBlockVector2DSet();
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++){
int y = heights[index];
int height = img.getRGB(x, z) & 0xFF;
if (height == 0 || PseudoRandom.random.nextInt(256) > height * doubleRarity) {
continue;
}
mutable.mutX(x);
mutable.mutY(y);
if (!mask.test(mutable)) {
continue;
}
if (placed.containsRadius(x, z, distance)) {
continue;
}
placed.add(x, z);
ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)];
if (randomRotate) {
int rotate = PseudoRandom.random.random(4) * 90;
if (rotate != 0) {
holder.setTransform(new AffineTransform().rotateY(PseudoRandom.random.random(4) * 90));
} else {
holder.setTransform(identity);
}
}
Clipboard clipboard = holder.getClipboard();
Schematic schematic = new Schematic(clipboard);
Transform transform = holder.getTransform();
if (transform.isIdentity()) {
schematic.paste(this, mutable, false);
} else {
schematic.paste(this, worldData, mutable, false, transform);
}
x += distance;
index += distance;
continue;
}
}
}
public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(getWidth(), 255, getLength()));
addOre(region, mask, material, size, frequency, rarity, minY, maxY);

View File

@ -35,6 +35,7 @@ public class SchemGen extends Resource {
mutable.mutX(x);
mutable.mutZ(z);
int y = extent.getNearestSurfaceTerrainBlock(x, z, mutable.getBlockY(), 0, 255);
if (y == -1) return false;
mutable.mutY(y);
if (!mask.test(mutable)) {
return false;

View File

@ -0,0 +1,53 @@
package com.boydti.fawe.object;
import com.boydti.fawe.FaweCache;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
public class DataAngleMask extends AbstractPattern {
public final Extent extent;
public final int maxY;
public final double factor = 1d/255;
public DataAngleMask(Extent extent) {
this.extent = extent;
this.maxY = extent.getMaximumPoint().getBlockY();
}
public int getSlope(BaseBlock block, Vector vector) {
int x = vector.getBlockX();
int y = vector.getBlockY();
int z = vector.getBlockZ();
if (FaweCache.canPassThrough(block.getId(), block.getData())) {
return -1;
}
int slope;
boolean aboveMin;
slope = Math.abs(extent.getNearestSurfaceTerrainBlock(x + 1, z, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x - 1, z, y, 0, maxY)) * 7;
slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x, z + 1, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x, z - 1, y, 0, maxY)) * 7;
slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x + 1, z + 1, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x - 1, z - 1, y, 0, maxY)) * 5;
slope += Math.abs(extent.getNearestSurfaceTerrainBlock(x - 1, z + 1, y, 0, maxY) - extent.getNearestSurfaceTerrainBlock(x + 1, z - 1, y, 0, maxY)) * 5;
return slope;
}
@Override
public BaseBlock apply(Vector position) {
BaseBlock block = extent.getBlock(position);
int slope = getSlope(block, position);
if (slope == -1) return block;
int data = (Math.min(slope, 255)) >> 4;
return FaweCache.getBlock(block.getId(), data);
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
BaseBlock block = extent.getBlock(getPosition);
int slope = getSlope(block, getPosition);
if (slope == -1) return false;
int data = (Math.min(slope, 255)) >> 4;
return extent.setBlock(setPosition, FaweCache.getBlock(block.getId(), data));
}
}

View File

@ -197,6 +197,12 @@ public abstract class FawePlayer<T> extends Metadatable {
}
public boolean runAction(final Runnable ifFree, boolean checkFree, boolean async) {
long[] actionTime = getMeta("lastActionTime");
if (actionTime == null) {
setMeta("lastActionTime", actionTime = new long[2]);
}
actionTime[1] = actionTime[0];
actionTime[0] = Fawe.get().getTimer().getTick();
if (checkFree) {
if (async) {
TaskManager.IMP.taskNow(new Runnable() {

View File

@ -26,9 +26,13 @@ public class LineBrush implements Brush, ResettableTool {
return;
}
editSession.drawLine(pattern, pos1, position, size, !shell, flat);
if (!select && !visual) {
pos1 = null;
return;
if (!visual) {
if (!select) {
pos1 = null;
return;
} else {
pos1 = position;
}
}
}

View File

@ -85,36 +85,6 @@ public class StencilBrush extends HeightBrush {
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,40 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.FaweCache;
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.blocks.BaseBlock;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
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.BreadthFirstSearch;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import java.util.Arrays;
public class SurfaceSphereBrush implements Brush {
@Override
public void build(EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
Mask mask = editSession.getMask();
if (mask == null) {
mask = Masks.alwaysTrue();
}
AdjacentAnyMask adjacent = new AdjacentAnyMask(editSession, Arrays.asList(new BaseBlock(0)));
for (int id = 0; id < 256; id++) {
if (FaweCache.canPassThrough(id, 0)) {
adjacent.add(new BaseBlock(id, -1));
}
}
final SolidBlockMask solid = new SolidBlockMask(editSession);
final RadiusMask radius = new RadiusMask(0, (int) size);
RecursiveVisitor visitor = new RecursiveVisitor(vector -> solid.test(vector) && radius.test(vector) && adjacent.test(vector), vector -> editSession.setBlock(vector, pattern));
visitor.visit(position);
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
Operations.completeBlindly(visitor);
}
}

View File

@ -32,6 +32,7 @@ public class SurfaceSpline implements Brush {
boolean vis = editSession.getExtent() instanceof VisualExtent;
if (path.isEmpty() || !pos.equals(path.get(path.size() - 1))) {
int max = editSession.getNearestSurfaceTerrainBlock(pos.getBlockX(), pos.getBlockZ(), pos.getBlockY(), 0, editSession.getMaxY());
if (max == -1) return;
pos.mutY(max);
path.add(pos);
editSession.getPlayer().sendMessage(BBC.getPrefix() + BBC.BRUSH_SPLINE_PRIMARY_2.s());
@ -56,6 +57,7 @@ public class SurfaceSpline implements Brush {
final int tipz = (int) tipv.getZ();
int tipy = (int) Math.round(tipv.getY());
tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY);
if (tipy == -1) continue;
if (radius == 0) {
editSession.setBlock(tipx, tipy, tipz, pattern.next(tipx, tipy, tipz));
} else {
@ -72,6 +74,7 @@ public class SurfaceSpline implements Brush {
for (int loopz = tipz - ceilrad; loopz <= (tipz + ceilrad); loopz++) {
if (MathMan.hypot2(loopx - tipx, 0, loopz - tipz) <= radius2) {
int y = editSession.getNearestSurfaceTerrainBlock(loopx, loopz, v.getBlockY(), 0, maxY);
if (y == -1) continue;
newSet.add(loopx, y, loopz);
}
}

View File

@ -100,6 +100,7 @@ public interface HeightMap {
height = session.getNearestSurfaceLayer(xx, zz, pos.getBlockY(), 0, maxY);
} else {
height = session.getNearestSurfaceTerrainBlock(xx, zz, pos.getBlockY(), 0, maxY);
if (height == -1) continue;
}
oldData[index] = height;
if (height == 0) {
@ -141,7 +142,8 @@ public interface HeightMap {
if (layers) {
height = session.getNearestSurfaceLayer(xx, zz, height, 0, maxY);
} else {
height = session.getNearestSurfaceTerrainBlock(xx, zz, height, 0, 255);
height = session.getNearestSurfaceTerrainBlock(xx, zz, height, 0, maxY);
if (height == -1) continue;
}
oldData[index] = height;
if (height == 0) {

View File

@ -0,0 +1,278 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.MutableBlockVector2D;
import com.sk89q.worldedit.Vector2D;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* The LocalPartitionedBlockVector2DSet is a Memory and CPU optimized Set for storing Vector2Ds which are all in a local region
* - All Vector2Ds must be within x[0,32768), y[0,32768)
* - This will use 8 bytes for every 64 Vector2Ds (about 800x less than a HashSet)
*/
public class LocalBlockVector2DSet implements Set<Vector2D> {
private boolean chunksValid = true;
private final SparseBitSet set;
private final MutableBlockVector2D mutable = new MutableBlockVector2D();
public LocalBlockVector2DSet() {
this.set = new SparseBitSet();
}
public SparseBitSet getBitSet() {
return set;
}
@Override
public int size() {
return set.cardinality();
}
@Override
public boolean isEmpty() {
return set.isEmpty();
}
public boolean contains(int x, int y) {
return set.get(MathMan.pairSearchCoords(x, y));
}
@Override
public boolean contains(Object o) {
if (o instanceof Vector2D) {
Vector2D v = (Vector2D) o;
return contains(v.getBlockX(), v.getBlockZ());
}
return false;
}
public boolean containsRadius(int x, int y, int radius) {
int size = size();
if (size == 0) return false;
if (radius <= 0 || size == 1) {
return contains(x, y);
}
// int centerIndex = MathMan.pairSearchCoords(x, y);
int length = (radius << 1) + 1;
if (size() < length * length) {
int index = -1;
int count = 0;
while ((index = set.nextSetBit(index + 1)) != -1) {
// if (index == centerIndex) continue;
int curx = MathMan.unpairSearchCoordsX(index);
int cury = MathMan.unpairSearchCoordsY(index);
if (Math.abs(curx - x) <= radius && Math.abs(cury - y) <= radius) {
return true;
}
}
return false;
}
int bcx = Math.max(0, (x - radius) >> 4);
int bcy = Math.max(0, (y - radius) >> 4);
int tcx = Math.min(2047, (x + radius) >> 4);
int tcy = Math.min(2047, (y + radius) >> 4);
for (int cy = bcy; cy <= tcy; cy++) {
for (int cx = bcx; cx <= tcx; cx++) {
int index = MathMan.pairSearchCoords(cx << 4, cy << 4) - 1;
int endIndex = index + 256;
while ((index = set.nextSetBit(index + 1)) <= endIndex && index != -1) {
// if (index == centerIndex) continue;
int curx = MathMan.unpairSearchCoordsX(index);
int cury = MathMan.unpairSearchCoordsY(index);
if (Math.abs(curx - x) <= radius && Math.abs(cury - y) <= radius) {
return true;
}
}
}
}
return false;
}
public Vector2D getIndex(int getIndex) {
int size = size();
if (getIndex > size) {
return null;
}
int index = -1;
for (int i = 0; i <= getIndex; i++) {
index = set.nextSetBit(index + 1);
}
if (index != -1) {
int x = MathMan.unpairSearchCoordsX(index);
int y = MathMan.unpairSearchCoordsY(index);
return mutable.setComponents(x, y);
}
return null;
}
@Override
public Iterator<Vector2D> iterator() {
return new Iterator<Vector2D>() {
int index = set.nextSetBit(0);
int previous = -1;
@Override
public void remove() {
chunksValid = false;
set.clear(previous);
}
@Override
public boolean hasNext() {
return index != -1;
}
@Override
public Vector2D next() {
if (index != -1) {
int x = MathMan.unpairSearchCoordsX(index);
int y = MathMan.unpairSearchCoordsY(index);
mutable.setComponents(x, y);
previous = index;
index = set.nextSetBit(index + 1);
return mutable;
}
return null;
}
};
}
@Override
public Object[] toArray() {
return toArray(null);
}
@Override
public <T> T[] toArray(T[] array) {
int size = size();
if (array == null || array.length < size) {
array = (T[]) new BlockVector2D[size];
}
int index = 0;
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index);
int x = MathMan.unpairSearchCoordsX(index);
int y = MathMan.unpairSearchCoordsY(index);
array[i] = (T) new BlockVector2D(x, y);
index++;
}
return array;
}
public boolean add(int x, int y) {
if (x < 0 || x > 32766 || y < 0 || y > 32766) {
throw new UnsupportedOperationException("LocalVector2DSet can only contain Vector2Ds within 1024 blocks (cuboid) of the first entry. ");
}
int index = getIndex(x, y);
if (set.get(index)) {
return false;
} else {
set.set(index);
return true;
}
}
@Override
public boolean add(Vector2D vector) {
return add(vector.getBlockX(), vector.getBlockZ());
}
private int getIndex(Vector2D vector) {
return MathMan.pairSearchCoords(vector.getBlockX(), vector.getBlockZ());
}
private int getIndex(int x, int y) {
return MathMan.pairSearchCoords(x, y);
}
public boolean remove(int x, int y) {
if (x < 0 || x > 32766 || y < 0 || y > 32766) {
return false;
}
int index = MathMan.pairSearchCoords(x, y);
boolean value = set.get(index);
if (value) {
set.clear(index);
chunksValid = false;
}
return value;
}
@Override
public boolean remove(Object o) {
if (o instanceof Vector2D) {
Vector2D v = (Vector2D) o;
return remove(v.getBlockX(), v.getBlockZ());
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends Vector2D> c) {
boolean result = false;
for (Vector2D v : c) {
result |= add(v);
}
return result;
}
@Override
public boolean retainAll(Collection<?> c) {
boolean result = false;
int size = size();
int index = -1;
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index + 1);
int x = MathMan.unpairSearchCoordsX(index);
int y = MathMan.unpairSearchCoordsY(index);
mutable.setComponents(x, y);
if (!c.contains(mutable)) {
result = true;
set.clear(index);
chunksValid = false;
}
}
return result;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean result = false;
for (Object o : c) {
result |= remove(o);
}
return result;
}
public void forEach(BlockVector2DSetVisitor visitor) {
int size = size();
int index = -1;
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index + 1);
int x = MathMan.unpairSearchCoordsX(index);
int y = MathMan.unpairSearchCoordsY(index);
mutable.setComponents(x, y);
visitor.run(x, y, index);
}
}
public static abstract class BlockVector2DSetVisitor {
public abstract void run(int x, int y, int index);
}
@Override
public void clear() {
set.clear();
chunksValid = true;
}
}

View File

@ -0,0 +1,37 @@
package com.boydti.fawe.object.function;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.FlatRegionFunction;
import com.sk89q.worldedit.function.RegionFunction;
public class SurfaceRegionFunction implements FlatRegionFunction {
private final Extent extent;
private final RegionFunction function;
private final int minY;
private final int maxY;
private int lastY;
private MutableBlockVector mutable = new MutableBlockVector();
public SurfaceRegionFunction(Extent extent, RegionFunction function, int minY, int maxY) {
this.extent = extent;
this.minY = minY;
this.maxY = maxY;
this.lastY = maxY;
this.function = function;
}
@Override
public boolean apply(Vector2D position) throws WorldEditException {
int x = position.getBlockX();
int z = position.getBlockZ();
int layer = extent.getNearestSurfaceTerrainBlock(x, z, lastY, minY, maxY);
if (layer != -1) {
lastY = layer;
return function.apply(mutable.setComponents(x, layer, z));
}
return false;
}
}

View File

@ -9,9 +9,8 @@ import com.sk89q.worldedit.function.mask.SolidBlockMask;
import javax.annotation.Nullable;
public class AngleMask extends SolidBlockMask {
private static double ADJACENT_MOD = 0.5;
private static double DIAGONAL_MOD = 1 / Math.sqrt(8);
public static double ADJACENT_MOD = 0.5;
public static double DIAGONAL_MOD = 1 / Math.sqrt(8);
private final double max;
private final double min;

View File

@ -0,0 +1,53 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.object.DataAngleMask;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
public class AngleColorPattern extends DataAngleMask {
private final TextureUtil util;
private final int maxY;
private final double factor = 1d/196;
public AngleColorPattern(TextureUtil util, Extent extent) {
super(extent);
this.util = util;
this.maxY = extent.getMaximumPoint().getBlockY();
}
public int getColor(int color, int slope) {
if (slope == 0) return color;
double newFactor = (196 - Math.min(196, slope)) * factor;
int newRed = (int) (((color >> 16) & 0xFF) * newFactor);
int newGreen = (int) (((color >> 8) & 0xFF) * newFactor);
int newBlue = (int) (((color >> 0) & 0xFF) * newFactor);
return (((color >> 24) & 0xFF) << 24) + (newRed << 16) + (newGreen << 8) + (newBlue << 0);
}
@Override
public BaseBlock apply(Vector position) {
BaseBlock block = extent.getBlock(position);
int slope = getSlope(block, position);
if (slope == -1) return block;
int color = util.getColor(block);
if (color == 0) return block;
int newColor = getColor(color, slope);
return util.getNearestBlock(newColor);
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
BaseBlock block = extent.getBlock(getPosition);
int slope = getSlope(block, getPosition);
if (slope == -1) return false;
int color = util.getColor(block);
if (color == 0) return false;
int newColor = getColor(color, slope);
BaseBlock newBlock = util.getNearestBlock(newColor);
if (newBlock == null) return false;
return extent.setBlock(setPosition, newBlock);
}
}

View File

@ -0,0 +1,40 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import java.awt.Color;
public class AverageColorPattern extends AbstractPattern {
private final int color;
private final Extent extent;
private final TextureUtil util;
public AverageColorPattern(Extent extent, TextureUtil util, int color) {
this.extent = extent;
this.util = util;
this.color = new Color(color).getRGB();
}
@Override
public BaseBlock apply(Vector position) {
BaseBlock block = extent.getBlock(position);
int currentColor = util.getColor(block);
int newColor = util.averageColor(currentColor, color);
return util.getNearestBlock(newColor);
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
BaseBlock block = extent.getBlock(getPosition);
int currentColor = util.getColor(block);
if (currentColor == 0) return false;
int newColor = util.averageColor(currentColor, color);
BaseBlock newBlock = util.getNearestBlock(newColor);
if (newBlock.equals(block)) return false;
return extent.setBlock(setPosition, newBlock);
}
}

View File

@ -0,0 +1,54 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
import com.boydti.fawe.util.FaweTimer;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
public class BufferedPattern extends AbstractPattern implements ResettablePattern {
private final Pattern pattern;
private final LocalBlockVectorSet set = new LocalBlockVectorSet();
private final FaweTimer timer;
private final long[] actionTime;
public BufferedPattern(FawePlayer fp, Pattern parent) {
long[] actionTime = fp.getMeta("lastActionTime");
if (actionTime == null) fp.setMeta("lastActionTime", actionTime = new long[2]);
this.actionTime = actionTime;
this.pattern = parent;
this.timer = Fawe.get().getTimer();
}
@Override
public BaseBlock apply(Vector position) {
return pattern.apply(position);
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
long now = timer.getTick();
try {
if (!set.add(setPosition)) {
return false;
}
return pattern.apply(extent, setPosition, getPosition);
} catch (UnsupportedOperationException ignore) {}
return false;
}
@Override
public void reset() {
long now = timer.getTick();
if (now - actionTime[1] > 5) {
set.clear();
}
actionTime[1] = actionTime[0];
actionTime[0] = now;
}
}

View File

@ -7,11 +7,16 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
public class DataPattern extends AbstractPattern {
private final Extent extent;
private final Pattern pattern;
public DataPattern(Extent extent, Pattern parent) {
checkNotNull(extent);
checkNotNull(parent);
this.extent = extent;
this.pattern = parent;
}

View File

@ -0,0 +1,58 @@
package com.boydti.fawe.object.pattern;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
public class DesaturatePattern extends AbstractPattern{
private final TextureUtil util;
private final Extent extent;
private final double value;
public DesaturatePattern(Extent extent, TextureUtil util, double value) {
this.extent = extent;
this.util = util;
this.value = Math.max(0, Math.min(1, value));
}
@Override
public BaseBlock apply(Vector position) {
BaseBlock block = extent.getBlock(position);
int color = util.getColor(block);
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = (color >> 0) & 0xFF;
int alpha = (color >> 24) & 0xFF;
double l = 0.3f * r + 0.6f * g + 0.1f * b;
int red = (int) (r + value * (l - r));
int green = (int) (g + value * (l - g));
int blue = (int) (b + value * (l - b));
int newColor = (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
return util.getNearestBlock(newColor);
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
BaseBlock block = extent.getBlock(getPosition);
int color = util.getColor(block);
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = (color >> 0) & 0xFF;
int alpha = (color >> 24) & 0xFF;
double l = 0.3f * r + 0.6f * g + 0.1f * b;
int red = (int) (r + value * (l - r));
int green = (int) (g + value * (l - g));
int blue = (int) (b + value * (l - b));
int newColor = (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
if (newColor == color) {
return false;
}
BaseBlock newBlock = util.getNextNearestBlock(newColor);
if (block.equals(newBlock)) {
return false;
}
return extent.setBlock(setPosition, newBlock);
}
}

View File

@ -7,11 +7,16 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
public class IdPattern extends AbstractPattern {
private final Extent extent;
private final Pattern pattern;
public IdPattern(Extent extent, Pattern parent) {
checkNotNull(extent);
checkNotNull(parent);
this.extent = extent;
this.pattern = parent;
}

View File

@ -6,16 +6,17 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import java.awt.Color;
public class ColorPattern extends AbstractPattern {
public class SaturatePattern extends AbstractPattern {
private final int color;
private final Extent extent;
private final TextureUtil util;
public ColorPattern(Extent extent, TextureUtil util, int color) {
public SaturatePattern(Extent extent, TextureUtil util, int color) {
this.extent = extent;
this.util = util;
this.color = color;
this.color = new Color(color).getRGB();
}
@Override
@ -28,7 +29,7 @@ public class ColorPattern extends AbstractPattern {
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
BaseBlock block = extent.getBlock(setPosition);
BaseBlock block = extent.getBlock(getPosition);
int currentColor = util.getColor(block);
if (currentColor == 0) return false;
int newColor = util.multiplyColor(currentColor, color);
@ -36,4 +37,4 @@ public class ColorPattern extends AbstractPattern {
if (newBlock.equals(block)) return false;
return extent.setBlock(setPosition, newBlock);
}
}
}

View File

@ -2,26 +2,28 @@ package com.boydti.fawe.object.pattern;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import static com.google.common.base.Preconditions.checkNotNull;
public class ShadePattern extends AbstractPattern{
private final TextureUtil util;
private final Extent extent;
private final boolean darken;
public ShadePattern(Extent extent, TextureUtil util) {
public ShadePattern(Extent extent, TextureUtil util, boolean darken) {
checkNotNull(extent);
checkNotNull(util);
this.extent = extent;
this.util = util;
this.darken = darken;
}
@Override
public BaseBlock apply(Vector position) {
return null;
}
@Override
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
return false;
BaseBlock block = extent.getBlock(position);
return darken ? util.getDarkerBlock(block) : util.getLighterBlock(block);
}
}

View File

@ -143,7 +143,7 @@ public class CreateFromImage extends Command {
fp.sendMessage(BBC.getPrefix() + "/2 cfi column [url|mask] <pattern> [white=false]");
fp.sendMessage(BBC.getPrefix() + "/2 cfi caves");
fp.sendMessage(BBC.getPrefix() + "/2 cfi ore[s]");
fp.sendMessage(BBC.getPrefix() + "/2 cfi schem <mask> <schem> <rarity> <rotate>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi schem [url] <mask> <schem> <rarity> <distance> <rotate>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi height <image-url|height>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi waterHeight <height>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi waterId <number-id>");
@ -185,23 +185,35 @@ public class CreateFromImage extends Command {
Request.request().setExtent(generator);
try {
switch (argList.get(0).toLowerCase()) {
// BufferedImage, Mask, WorldData, ClipboardHolder[], rarity, distance, randomRotate
case "schem":
case "schems":
case "addschems": {
if (argList.size() != 5) {
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <mask> <file|folder|url> <rarity> <rotate>");
if (argList.size() != 6 && argList.size() != 7) {
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " [url] <mask> <file|folder|url> <rarity> <distance> <rotate>");
return;
}
int argOffset = 0;
BufferedImage img = null;
if (argList.get(1).startsWith("http")) {
img = getImgurImage(argList.get(1), fp);
argOffset++;
}
World world = fp.getWorld();
WorldData wd = world.getWorldData();
Mask mask = we.getMaskFactory().parseFromInput(argList.get(1), context);
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), wd, argList.get(2), true);
Mask mask = we.getMaskFactory().parseFromInput(argList.get(1 + argOffset), context);
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(fp.getPlayer(), wd, argList.get(2 + argOffset), true);
if (clipboards == null) {
return;
}
int rarity = Integer.parseInt(argList.get(3));
boolean rotate = Boolean.parseBoolean(argList.get(4));
generator.addSchems(mask, wd, clipboards, rarity, rotate);
int rarity = Integer.parseInt(argList.get(3 + argOffset));
int distance = Integer.parseInt(argList.get(4 + argOffset));
boolean rotate = Boolean.parseBoolean(argList.get(5 + argOffset));
if (img == null) {
generator.addSchems(mask, wd, clipboards, rarity, rotate);
} else {
generator.addSchems(img, mask, wd, clipboards, rarity, distance, rotate);
}
player.sendMessage(BBC.getPrefix() + "Added schems, what's next?");
return;
}
@ -530,6 +542,7 @@ public class CreateFromImage extends Command {
} catch (InputParseException e) {
player.sendMessage("Invalid mask " + e.getMessage());
} catch (Throwable e) {
e.printStackTrace();
player.sendMessage("Error " + e.getMessage());
} finally {
Request.reset();

View File

@ -5,12 +5,13 @@ import java.util.Arrays;
public class CleanTextureUtil extends TextureUtil {
public CleanTextureUtil(TextureUtil parent, int minPercent, int maxPercent) {
super(parent.getFolder());
int minIndex = (parent.distances.length * minPercent) / 100;
int maxIndex = (parent.distances.length * maxPercent) / 100;
int minIndex = ((parent.distances.length - 1) * minPercent) / 100;
int maxIndex = ((parent.distances.length - 1) * maxPercent) / 100;
long min = parent.distances[minIndex];
long max = parent.distances[maxIndex];
for (; minIndex > 0 && parent.distances[minIndex - 1] == min; minIndex--);
for (; maxIndex < parent.distances.length - 2 && parent.distances[maxIndex + 1] == max; maxIndex++);
int num = maxIndex - minIndex + 1;
this.validBiomes = parent.validBiomes;
this.blockColors = parent.blockColors;
this.blockDistance = parent.blockDistance;

View File

@ -18,6 +18,16 @@ public class DelegateTextureUtil extends TextureUtil {
return parent.getNearestBlock(color);
}
@Override
public BaseBlock getNearestBlock(BaseBlock block) {
return parent.getNearestBlock(block);
}
@Override
public BaseBlock getNextNearestBlock(int color) {
return parent.getNextNearestBlock(color);
}
@Override
public char[] getNearestLayer(int color) {
return parent.getNearestLayer(color);

View File

@ -90,6 +90,8 @@ public final class DocumentationPrinter {
stream.println();
stream.print("## Content");
stream.println();
stream.print("Click on a category to go to the list of commands, or `More Info` for detailed descriptions ");
stream.println();
StringBuilder builder = new StringBuilder();
writePermissionsWikiTable(stream, builder, "/we ", WorldEditCommands.class);
writePermissionsWikiTable(stream, builder, "/", GeneralCommands.class);
@ -117,7 +119,7 @@ public final class DocumentationPrinter {
stream.append("| --- | --- | --- | --- |\n");
stream.append("| //cancel | fawe.cancel | | Cancels your current operations |\n");
stream.append("| /plot replaceall | plots.replaceall | | Replace all blocks in the plot world |\n");
stream.append("| /plot createfromimage | plots.createfromimage | | Starts world creation from a heightmap image: [More Info](https://www.youtube.com/watch?v=cJZk1GTig7A) |\n");
stream.append("| /plot createfromimage | plots.createfromimage | | Starts world creation from a heightmap image: [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/CreateFromImage) |\n");
stream.print("\n---\n");
stream.print(builder);
@ -139,7 +141,12 @@ public final class DocumentationPrinter {
// //setbiome || worldedit.biome.set || //setbiome || p || Sets the biome of the player's current block or region.
if (title) {
String path = "https://github.com/boy0001/FastAsyncWorldedit/edit/master/core/src/main/java/" + cls.getName().replaceAll("\\.", "/") + ".java";
stream.append("### **" + cls.getSimpleName().replaceAll("(\\p{Ll})(\\p{Lu})","$1 $2") + "** [`✎`](" + path + ")");
stream.append("### **" + cls.getSimpleName().replaceAll("(\\p{Ll})(\\p{Lu})","$1 $2") + "** [`✎`](" + path + ")[`▲`](#overview)");
stream.append("\n");
Command cmd = cls.getAnnotation(Command.class);
if (cmd != null) {
stream.append(" (" + (cmd.help().isEmpty() ? cmd.desc() : cmd.help()) + ")");
}
stream.append("\n");
stream.append("\n");
stream.append("---");

View File

@ -30,4 +30,4 @@ public class FilteredTextureUtil extends TextureUtil {
}
this.calculateLayerArrays();
}
}
}

View File

@ -155,6 +155,18 @@ public class MathMan {
return (long) (round + Math.signum(val - round));
}
public static final int pair(short x, short y) {
return (x << 16) | (y & 0xFFFF);
}
public static final short unpairX(int hash) {
return (short) (hash >> 16);
}
public static final short unpairY(int hash) {
return (short) (hash & 0xFFFF);
}
public static final short pairByte(int x, int y) {
return (short) ((x << 8) | (y & 0xFF));
}
@ -221,6 +233,33 @@ public class MathMan {
;
}
public static int pairSearchCoords(int x, int y) {
byte b1 = (byte) ((x & 0xF) + ((y & 0xF) << 4));
byte b2 = (byte) ((x >> 4) & 0xFF);
byte b3 = (byte) ((y >> 4) & 0xFF);
int x16 = (x >> 12) & 0xF;
int y16 = (y >> 12) & 0xF;
byte b4 = (byte) ((x16 & 0xF) + ((y16 & 0xF) << 4));
return ((b1 & 0xFF)
+ ((b2 & 0xFF) << 8)
+ ((b3 & 0xFF) << 16)
+ ((b4 & 0xFF) << 24));
}
public static int unpairSearchCoordsX(int pair) {
int x1 = (pair >> 24) & 0x7;
int x2 = (pair >> 8) & 0xFF;
int x3 = (pair & 0xF);
return x3 + (x2 << 4) + (x1 << 12);
}
public static int unpairSearchCoordsY(int pair) {
int y1 = ((pair >> 24) & 0x7F) >> 3;
int y2 = (pair >> 16) & 0xFF;
int y3 = (pair & 0xFF) >> 4;
return y3 + (y2 << 4) + (y1 << 12);
}
public static final long chunkXZ2Int(int x, int z) {
return (long)x & 4294967295L | ((long)z & 4294967295L) << 32;
}
@ -360,18 +399,6 @@ public class MathMan {
return count / array.length;
}
public static final int pair(short x, short y) {
return (x << 16) | (y & 0xFFFF);
}
public static final short unpairX(int hash) {
return (short) (hash >> 16);
}
public static final short unpairY(int hash) {
return (short) (hash & 0xFFFF);
}
/**
* Returns [x, y, z]
* @param yaw

View File

@ -344,6 +344,33 @@ public class TextureUtil {
return FaweCache.CACHE_BLOCK[closest];
}
public BaseBlock getNearestBlock(BaseBlock block) {
int color = getColor(block);
if (color == 0) return null;
return getNextNearestBlock(color);
}
public BaseBlock getNextNearestBlock(int color) {
long min = Long.MAX_VALUE;
int closest = 0;
int red1 = (color >> 16) & 0xFF;
int green1 = (color >> 8) & 0xFF;
int blue1 = (color >> 0) & 0xFF;
int alpha = (color >> 24) & 0xFF;
for (int i = 0; i < validColors.length; i++) {
int other = validColors[i];
if (other != color && ((other >> 24) & 0xFF) == alpha) {
long distance = colorDistance(red1, green1, blue1, other);
if (distance < min) {
min = distance;
closest = validBlockIds[i];
}
}
}
if (min == Long.MAX_VALUE) return null;
return FaweCache.CACHE_BLOCK[closest];
}
/**
* Returns the block combined ids as an array
* @param color
@ -374,7 +401,7 @@ public class TextureUtil {
}
public BaseBlock getDarkerBlock(BaseBlock block) {
return getNearestBlock(block, false);
return getNearestBlock(block, true);
}
public int getColor(BaseBlock block) {
@ -644,9 +671,25 @@ public class TextureUtil {
int green2 = (c2 >> 8) & 0xFF;
int blue2 = (c2 >> 0) & 0xFF;
int red = ((red1 * red2)) / 255;
int green = ((green1 * green2)) / 256;
int blue = ((blue1 * blue2)) / 256;
int alpha = ((alpha1 * alpha2)) / 256;
int green = ((green1 * green2)) / 255;
int blue = ((blue1 * blue2)) / 255;
int alpha = ((alpha1 * alpha2)) / 255;
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
}
public int averageColor(int c1, int c2) {
int alpha1 = (c1 >> 24) & 0xFF;
int alpha2 = (c2 >> 24) & 0xFF;
int red1 = (c1 >> 16) & 0xFF;
int green1 = (c1 >> 8) & 0xFF;
int blue1 = (c1 >> 0) & 0xFF;
int red2 = (c2 >> 16) & 0xFF;
int green2 = (c2 >> 8) & 0xFF;
int blue2 = (c2 >> 0) & 0xFF;
int red = ((red1 + red2)) / 2;
int green = ((green1 + green2)) / 2;
int blue = ((blue1 + blue2)) / 2;
int alpha = ((alpha1 + alpha2)) / 2;
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
}
@ -709,14 +752,14 @@ public class TextureUtil {
int green1 = (color >> 8) & 0xFF;
int blue1 = (color >> 0) & 0xFF;
int alpha = (color >> 24) & 0xFF;
int intensity1 = red1 + green1 + blue1;
int intensity1 = 2 * red1 + 4 * green1 + 3 * blue1;
for (int i = 0; i < validColors.length; i++) {
int other = validColors[i];
if (other != color && ((other >> 24) & 0xFF) == alpha) {
int red2 = (other >> 16) & 0xFF;
int green2 = (other >> 8) & 0xFF;
int blue2 = (other >> 0) & 0xFF;
int intensity2 = red2 + green2 + blue2;
int intensity2 = 2 * red2 + 4 * green2 + 3 * blue2;
if (darker ? intensity2 >= intensity1 : intensity1 >= intensity2) {
continue;
}

View File

@ -56,6 +56,7 @@ import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.extent.SingleRegionExtent;
import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.SourceMaskExtent;
import com.boydti.fawe.object.function.SurfaceRegionFunction;
import com.boydti.fawe.object.mask.ResettableMask;
import com.boydti.fawe.object.progress.ChatProgressTracker;
import com.boydti.fawe.object.progress.DefaultProgressTracker;
@ -105,6 +106,7 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.util.RegionOffset;
import com.sk89q.worldedit.function.visitor.DownwardVisitor;
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
import com.sk89q.worldedit.function.visitor.LayerVisitor;
import com.sk89q.worldedit.function.visitor.NonRisingVisitor;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
@ -1901,7 +1903,6 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
@SuppressWarnings("deprecation")
public int overlayCuboidBlocks(final Region region, final BaseBlock block) throws MaxChangedBlocksException {
checkNotNull(block);
return this.overlayCuboidBlocks(region, new BlockPattern(block));
}
@ -1920,10 +1921,12 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
checkNotNull(pattern);
final BlockReplace replace = new BlockReplace(EditSession.this, pattern);
final RegionOffset offset = new RegionOffset(new Vector(0, 1, 0), replace);
final GroundFunction ground = new GroundFunction(new ExistingBlockMask(EditSession.this), offset);
final LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
int minY = region.getMinimumPoint().getBlockY();
int maxY = Math.min(getMaximumPoint().getBlockY(), region.getMaximumPoint().getBlockY() + 1);
SurfaceRegionFunction surface = new SurfaceRegionFunction(this, offset, minY, maxY);
FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface, this);
Operations.completeBlindly(visitor);
return this.changes = ground.getAffected();
return this.changes = visitor.getAffected();
}
/**

View File

@ -43,6 +43,7 @@ import com.boydti.fawe.object.brush.ShatterBrush;
import com.boydti.fawe.object.brush.SplatterBrush;
import com.boydti.fawe.object.brush.SplineBrush;
import com.boydti.fawe.object.brush.StencilBrush;
import com.boydti.fawe.object.brush.SurfaceSphereBrush;
import com.boydti.fawe.object.brush.SurfaceSpline;
import com.boydti.fawe.object.brush.TargetMode;
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
@ -109,7 +110,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Commands to set brush shape.
*/
@Command(aliases = { "brush", "br" }, desc = "Commands to build and draw from far away: [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Brushes)")
@Command(aliases = { "brush", "br" },
desc = "Commands to build and draw from far away. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Brushes)"
)
public class BrushCommands {
private final WorldEdit worldEdit;
@ -285,9 +288,10 @@ public class BrushCommands {
@Command(
aliases = { "blendball", "bb", "blend" },
usage = "[radius]",
desc = "Choose the blend ball brush",
help = "Chooses the blend ball brush",
usage = "[radius=5]",
desc = "Smooths and blends terrain",
help = "Smooths and blends terrain\n" +
"Pic: https://i.imgur.com/cNUQUkj.png -> https://i.imgur.com/hFOFsNf.png",
min = 0,
max = 1
)
@ -302,9 +306,9 @@ public class BrushCommands {
@Command(
aliases = { "erode", "e" },
usage = "[radius]",
desc = "Choose the erode brush",
help = "Chooses the erode brush",
usage = "[radius=5]",
desc = "Erodes terrain",
help = "Erodes terrain",
min = 0,
max = 1
)
@ -319,9 +323,9 @@ public class BrushCommands {
@Command(
aliases = { "pull" },
usage = "[radius]",
desc = "Choose the raise brush",
help = "Chooses the raise brush",
usage = "[radius=5]",
desc = "Pull terrain towards you",
help = "Pull terrain towards you",
min = 0,
max = 1
)
@ -336,14 +340,15 @@ public class BrushCommands {
@Command(
aliases = { "circle" },
usage = "<pattern> [radius]",
desc = "Choose the circle brush",
help = "Chooses the circle brush.",
usage = "<pattern> [radius=5]",
desc = "Creates a circle which revolves around your facing direction",
help = "Creates a circle which revolves around your facing direction.\n" +
"Note: Decrease brush radius, and enabled visualization to assist with placement mid-air",
min = 1,
max = 2
)
@CommandPermissions("worldedit.brush.sphere")
public void circleBrush(Player player, LocalSession session, Pattern fill, @Optional("5") double radius) throws WorldEditException {
public void circleBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("5") double radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setSize(radius);
@ -354,15 +359,16 @@ public class BrushCommands {
@Command(
aliases = { "recursive", "recurse", "r" },
usage = "<pattern-to> [radius]",
desc = "Choose the recursive brush",
help = "Chooses the recursive brush\n" +
"The -d flag Will apply in depth first order",
usage = "<pattern-to> [radius=5]",
desc = "Set all connected blocks",
help = "Set all connected blocks\n" +
"The -d flag Will apply in depth first order\n" +
"Note: Set a mask to recurse along specific blocks",
min = 0,
max = 3
)
@CommandPermissions("worldedit.brush.recursive")
public void recursiveBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, @Optional("2") double radius, @Switch('d') boolean depthFirst) throws WorldEditException {
public void recursiveBrush(Player player, LocalSession session, EditSession editSession, Pattern fill, @Optional("5") double radius, @Switch('d') boolean depthFirst) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setSize(radius);
@ -374,11 +380,11 @@ public class BrushCommands {
@Command(
aliases = { "line", "l" },
usage = "<pattern> [radius]",
usage = "<pattern> [radius=0]",
flags = "hsf",
desc = "Choose the line brush",
desc = "Create lines",
help =
"Chooses the line brush.\n" +
"Create lines.\n" +
"The -h flag creates only a shell\n" +
"The -s flag selects the clicked point after drawing\n" +
"The -f flag creates a flat line",
@ -386,7 +392,7 @@ public class BrushCommands {
max = 2
)
@CommandPermissions("worldedit.brush.line")
public void lineBrush(Player player, LocalSession session, Pattern fill, @Optional("0") double radius, @Switch('h') boolean shell, @Switch('s') boolean select, @Switch('f') boolean flat) throws WorldEditException {
public void lineBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("0") double radius, @Switch('h') boolean shell, @Switch('s') boolean select, @Switch('f') boolean flat) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setFill(fill);
@ -398,13 +404,16 @@ public class BrushCommands {
@Command(
aliases = { "spline", "spl", "curve" },
usage = "<pattern>",
desc = "Choose the spline brush",
help = "Chooses the spline brush",
desc = "Join multiple objects together in a curve",
help = "Click to select some objects,click the same block twice to connect the objects.\n" +
"Insufficient brush radius, or clicking the the wrong spot will result in undesired shapes. The shapes must be simple lines or loops.\n" +
"Pic1: http://i.imgur.com/CeRYAoV.jpg -> http://i.imgur.com/jtM0jA4.png\n" +
"Pic2: http://i.imgur.com/bUeyc72.png -> http://i.imgur.com/tg6MkcF.png",
min = 0,
max = 2
)
@CommandPermissions("worldedit.brush.spline")
public void splineBrush(Player player, LocalSession session, Pattern fill, @Optional("25") double radius) throws WorldEditException {
public void splineBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("25") double radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setFill(fill);
@ -417,14 +426,15 @@ public class BrushCommands {
@Command(
aliases = { "sspl", "sspline", "surfacespline" },
usage = "<pattern> [size] [tension] [bias] [continuity] [quality]",
desc = "Draws a spline on the surface",
help = "Chooses the surface spline brush",
usage = "<pattern> [size=0] [tension=0] [bias=0] [continuity=0] [quality=10]",
desc = "Draws a spline (curved line) on the surface",
help = "Create a spline on the surface\n" +
"Video: https://www.youtube.com/watch?v=zSN-2jJxXlM",
min = 0,
max = 2
)
@CommandPermissions("worldedit.brush.surfacespline") // 0, 0, 0, 10, 0,
public void surfaceSpline(Player player, LocalSession session, Pattern fill, @Optional("0") double radius, @Optional("0") double tension, @Optional("0") double bias, @Optional("0") double continuity, @Optional("10") double quality) throws WorldEditException {
public void surfaceSpline(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("0") double radius, @Optional("0") double tension, @Optional("0") double bias, @Optional("0") double continuity, @Optional("10") double quality) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setFill(fill);
@ -435,17 +445,17 @@ public class BrushCommands {
@Command(
aliases = { "sphere", "s" },
usage = "<pattern> [radius]",
usage = "<pattern> [radius=2]",
flags = "h",
desc = "Choose the sphere brush",
desc = "Creates a sphere",
help =
"Chooses the sphere brush.\n" +
"Creates a sphere.\n" +
"The -h flag creates hollow spheres instead.",
min = 1,
max = 2
)
@CommandPermissions("worldedit.brush.sphere")
public void sphereBrush(Player player, LocalSession session, Pattern fill, @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException {
public void sphereBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
@ -473,10 +483,11 @@ public class BrushCommands {
@Command(
aliases = { "shatter", "partition", "split" },
usage = "<pattern> [radius] [count]",
usage = "<pattern> [radius=10] [count=10]",
desc = "Creates random lines to break the terrain into pieces",
help =
"Chooses the shatter brush",
"Creates uneven lines separating terrain into multiple pieces\n" +
"Pic: https://i.imgur.com/2xKsZf2.png",
min = 1,
max = -1
)
@ -494,10 +505,10 @@ public class BrushCommands {
@Command(
aliases = { "stencil", "color"},
usage = "<pattern> [radius] [file|#clipboard|null] [rotation] [yscale]",
usage = "<pattern> [radius=5] [file|#clipboard|imgur=null] [rotation=360] [yscale=1.0]",
desc = "Use a height map to paint a surface",
help =
"Chooses the stencil brush.\n" +
"Use a height map to paint any surface.\n" +
"The -w flag will only apply at maximum saturation\n" +
"The -r flag will apply random rotation",
min = 1,
@ -523,13 +534,35 @@ public class BrushCommands {
player.print(BBC.getPrefix() + BBC.BRUSH_STENCIL.f(radius));
}
@Command(
aliases = { "surface", "surf"},
usage = "<pattern> [radius=5]",
desc = "Use a height map to paint a surface",
help =
"Use a height map to paint any surface.\n" +
"The -w flag will only apply at maximum saturation\n" +
"The -r flag will apply random rotation",
min = 1,
max = -1
)
@CommandPermissions("worldedit.brush.surface")
public void surfaceBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("5") double radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player);
tool.setFill(fill);
tool.setSize(radius);
tool.setBrush(new SurfaceSphereBrush(), "worldedit.brush.surface");
player.print(BBC.getPrefix() + BBC.BRUSH_SURFACE.f(radius));
}
@Command(
aliases = { "scatter", "scat" },
usage = "<pattern> [radius=5] [points=5] [distance=1]",
desc = "Scatter blocks on a surface",
desc = "Scatter a pattern on a surface",
help =
"Chooses the scatter brush.\n" +
" The -o flag will overlay the block",
"Set a number of blocks randomly on a surface each a certain distance apart.\n" +
" The -o flag will overlay the block\n" +
"Video: https://youtu.be/RPZIaTbqoZw?t=34s",
flags = "o",
min = 1,
max = 4
@ -581,9 +614,11 @@ public class BrushCommands {
@Command(
aliases = { "layer" },
usage = "<radius> <pattern1> <patern2> <pattern3>...",
desc = "Scatter a schematic on a surface",
help = "Chooses the layer brush.",
usage = "<radius> <pattern1> <patern2>...",
desc = "Replaces terrain with a layer.",
help = "Replaces terrain with a layer.\n" +
"Example: /br layer 5 95:1 95:2 35:15 - Places several layers on a surface\n" +
"Pic: https://i.imgur.com/XV0vYoX.png",
min = 3,
max = 999
)
@ -609,9 +644,11 @@ public class BrushCommands {
@Command(
aliases = { "splatter", "splat" },
usage = "<pattern> [radius=5] [seeds=1] [recursion=5] [solid=true]",
desc = "Splatter blocks on a surface",
help =
"Chooses the Splatter brush.",
desc = "Splatter a pattern on a surface",
help = "Sets a bunch of blocks randomly on a surface.\n" +
"Pic: https://i.imgur.com/hMD29oO.png\n" +
"Example: /br splatter stone,dirt 30 15\n" +
"Note: The seeds define how many splotches there are, recursion defines how large, solid defines whether the pattern is applied per seed, else per block.",
min = 1,
max = 5
)
@ -628,9 +665,12 @@ public class BrushCommands {
@Command(
aliases = { "scmd", "scattercmd", "scattercommand", "scommand" },
usage = "<scatter-radius> <points> <cmd-radius=1> <cmd1;cmd2...>",
desc = "Scatter commands on a surface",
desc = "Run commands at random points on a surface",
help =
"Chooses the scatter command brush.",
"Run commands at random points on a surface\n" +
" - The scatter radius is the min distance between each point\n" +
" - Your selection will be expanded to the specified size around each point\n" +
" - Placeholders: {x}, {y}, {z}, {world}, {size}",
min = 1,
max = -1
)
@ -645,17 +685,17 @@ public class BrushCommands {
@Command(
aliases = { "cylinder", "cyl", "c" },
usage = "<block> [radius] [height]",
usage = "<block> [radius=2] [height=1]",
flags = "h",
desc = "Choose the cylinder brush",
desc = "Creates a cylinder",
help =
"Chooses the cylinder brush.\n" +
"Creates a cylinder.\n" +
"The -h flag creates hollow cylinders instead.",
min = 1,
max = 3
)
@CommandPermissions("worldedit.brush.cylinder")
public void cylinderBrush(Player player, LocalSession session, Pattern fill,
public void cylinderBrush(Player player, EditSession editSession, LocalSession session, Pattern fill,
@Optional("2") double radius, @Optional("1") int height, @Switch('h') boolean hollow) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
worldEdit.checkMaxBrushRadius(height);
@ -675,7 +715,7 @@ public class BrushCommands {
@Command(
aliases = { "clipboard"},
usage = "",
desc = "Choose the clipboard brush",
desc = "Choose the clipboard brush (Recommended: `/br copypaste`)",
help =
"Chooses the clipboard brush.\n" +
"The -a flag makes it not paste air.\n" +
@ -701,9 +741,9 @@ public class BrushCommands {
@Command(
aliases = { "smooth" },
usage = "[size] [iterations]",
usage = "[size=2] [iterations=4]",
flags = "n",
desc = "Choose the terrain softener brush",
desc = "Smooths terrain (Recommended: `/br blendball`)",
help =
"Chooses the terrain softener brush.\n" +
"The -n flag makes it only consider naturally occurring blocks.",
@ -729,7 +769,7 @@ public class BrushCommands {
@Command(
aliases = { "ex", "extinguish" },
usage = "[radius]",
usage = "[radius=5]",
desc = "Shortcut fire extinguisher brush",
min = 0,
max = 1
@ -750,7 +790,7 @@ public class BrushCommands {
@Command(
aliases = { "gravity", "grav" },
usage = "[radius]",
usage = "[radius=5]",
flags = "h",
desc = "Gravity brush",
help =
@ -772,14 +812,16 @@ public class BrushCommands {
@Command(
aliases = { "height", "heightmap" },
usage = "[radius] [file|#clipboard|null] [rotation] [yscale]",
usage = "[radius=5] [file|#clipboard|imgur=null] [rotation=0] [yscale=1.00]",
flags = "h",
desc = "Height brush",
desc = "Raise or lower terrain using a heightmap",
help =
"This brush raises and lowers land.\n" +
"The -r flag enables random off-axis rotation\n" +
"The -l flag will work on snow layers\n" +
"The -s flag disables smoothing",
" - The `-r` flag enables random off-axis rotation\n" +
" - The `-l` flag will work on snow layers\n" +
" - The `-s` flag disables smoothing\n" +
"Note: Note: Use a negative yscale to reduce height\n" +
"Snow Pic: https://i.imgur.com/Hrzn0I4.png",
min = 1,
max = 4
)
@ -790,14 +832,14 @@ public class BrushCommands {
@Command(
aliases = { "cliff", "flatcylinder" },
usage = "[radius] [file|#clipboard|null] [rotation] [yscale]",
usage = "[radius=5] [file|#clipboard|imgur=null] [rotation=0] [yscale=1.00]",
flags = "h",
desc = "Cliff brush",
help =
"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\n" +
"The -s flag disables smoothing",
" - The `-r` flag enables random off-axis rotation\n" +
" - The `-l` flag will work on snow layers\n" +
" - The `-s` flag disables smoothing",
min = 1,
max = 4
)
@ -808,12 +850,12 @@ public class BrushCommands {
@Command(
aliases = { "flatten", "flatmap", "flat" },
usage = "[radius] [file|#clipboard|null] [rotation] [yscale]",
usage = "[radius=5] [file|#clipboard|imgur=null] [rotation=0] [yscale=1.00]",
flags = "h",
help = "Flatten brush makes terrain flatter\n" +
"The -r flag enables random off-axis rotation\n" +
"The -l flag will work on snow layers\n" +
"The -s flag disables smoothing",
help = "Flatten brush flattens terrain\n" +
" - The `-r` flag enables random off-axis rotation\n" +
" - The `-l` flag will work on snow layers\n" +
" - The `-s` flag disables smoothing",
desc = "This brush raises and lowers land towards the clicked point\n",
min = 1,
max = 4
@ -884,12 +926,13 @@ public class BrushCommands {
@Command(
aliases = { "copypaste", "copy", "paste", "cp", "copypasta" },
usage = "[depth]",
usage = "[depth=5]",
desc = "Copy Paste brush",
help =
"Left click the base of an object to copy.\n" +
help = "Left click the base of an object to copy.\n" +
"Right click to paste\n" +
"The -r flag Will apply random rotation on paste",
"The -r flag Will apply random rotation on paste\n" +
"Note: Works well with the clipboard scroll action\n" +
"Video: https://www.youtube.com/watch?v=RPZIaTbqoZw",
min = 0,
max = 1
)
@ -907,7 +950,10 @@ public class BrushCommands {
usage = "<radius> [cmd1;cmd2...]",
desc = "Command brush",
help =
"Right click executes the command at the position.\n",
"Run the commands at the clicked position.\n" +
" - Your selection will be expanded to the specified size around each point\n" +
" - Placeholders: {x}, {y}, {z}, {world}, {size}",
min = 2,
max = 99
)
@ -922,7 +968,7 @@ public class BrushCommands {
@Command(
aliases = { "butcher", "kill" },
usage = "[radius]",
usage = "[radius=5]",
flags = "plangbtfr",
desc = "Butcher brush",
help = "Kills nearby mobs within the specified radius.\n" +

View File

@ -24,6 +24,7 @@ import com.boydti.fawe.object.brush.InspectBrush;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@ -151,7 +152,7 @@ public class ToolCommands {
max = 2
)
@CommandPermissions("worldedit.tool.flood-fill")
public void floodFill(Player player, LocalSession session, Pattern pattern, double range) throws WorldEditException {
public void floodFill(Player player, EditSession editSession, LocalSession session, Pattern pattern, double range) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (range > config.maxSuperPickaxeSize) {
BBC.TOOL_RANGE_ERROR.send(player, config.maxSuperPickaxeSize);

View File

@ -188,7 +188,7 @@ public class ToolUtilCommands {
max = 1
)
@CommandPermissions("worldedit.brush.options.material")
public void material(Player player, LocalSession session, Pattern pattern, @Switch('h') boolean offHand) throws WorldEditException {
public void material(Player player, EditSession editSession, LocalSession session, Pattern pattern, @Switch('h') boolean offHand) throws WorldEditException {
Tool tool = session.getTool(player);
if (tool instanceof BrushTool) {
BrushTool bt = (BrushTool) tool;

View File

@ -3,8 +3,14 @@ package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.object.DataAngleMask;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.pattern.AngleColorPattern;
import com.boydti.fawe.object.pattern.AverageColorPattern;
import com.boydti.fawe.object.pattern.BiomePattern;
import com.boydti.fawe.object.pattern.BufferedPattern;
import com.boydti.fawe.object.pattern.DataPattern;
import com.boydti.fawe.object.pattern.DesaturatePattern;
import com.boydti.fawe.object.pattern.ExistingPattern;
import com.boydti.fawe.object.pattern.ExpressionPattern;
import com.boydti.fawe.object.pattern.FullClipboardPattern;
@ -21,11 +27,14 @@ import com.boydti.fawe.object.pattern.PatternExtent;
import com.boydti.fawe.object.pattern.RandomFullClipboardPattern;
import com.boydti.fawe.object.pattern.RandomOffsetPattern;
import com.boydti.fawe.object.pattern.RelativePattern;
import com.boydti.fawe.object.pattern.SaturatePattern;
import com.boydti.fawe.object.pattern.ShadePattern;
import com.boydti.fawe.object.pattern.SolidRandomOffsetPattern;
import com.boydti.fawe.object.pattern.SurfaceRandomOffsetPattern;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession;
@ -124,7 +133,8 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
case '#': {
String[] split2 = input.split(":");
String rest = split2.length > 1 ? input.substring(split2[0].length() + 1) : "";
switch (split2[0].toLowerCase()) {
String arg = split2[0].toLowerCase();
switch (arg) {
case "#*":
case "#existing": {
return new ExistingPattern(Request.request().getExtent());
@ -154,6 +164,40 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
throw new InputParseException("#color:<hex>");
}
}
case "#anglecolor": {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 2 ? true : Boolean.parseBoolean(split2[1]), 0, split2.length < 3 ? 100 : Integer.parseInt(split2[2]));
return new AngleColorPattern(util, Request.request().getExtent());
}
case "#angledata": {
return new DataAngleMask(Request.request().getExtent());
}
case "#saturate":
case "#averagecolor": {
try {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 3 ? true : Boolean.parseBoolean(split2[2]), 0, split2.length < 4 ? 100 : Integer.parseInt(split2[3]));
Color color = Color.web(split2[1]);
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
if (arg.equals("#saturate"))
return new SaturatePattern(Request.request().getExtent(), util, awtColor.getRGB());
else return new AverageColorPattern(Request.request().getExtent(), util, awtColor.getRGB());
} catch (NumberFormatException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#" + arg + "[:<color>:<randomize=true>:<complexity=100>]");
}
}
case "#desaturate": {
try {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 3 ? true : Boolean.parseBoolean(split2[2]), 0, split2.length < 4 ? 100 : Integer.parseInt(split2[3]));
double chance = split2.length < 2 ? 100 : Expression.compile(split2[1]).evaluate();
return new DesaturatePattern(Request.request().getExtent(), util, chance / 100d);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#desaturate[:<percent=100>:<randomize=true>:<complexity=100>]");
}
}
case "#lighten":
case "#darken": {
TextureUtil util = Fawe.get().getCachedTextureUtil(split2.length < 2 ? true : Boolean.parseBoolean(split2[1]), 0, split2.length < 3 ? 100 : Integer.parseInt(split2[2]));
return new ShadePattern(Request.request().getExtent(), util, arg.equals("#darken"));
}
case "#fullcopy": {
LocalSession session = context.requireSession();
if (session != null) {
@ -196,6 +240,9 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
throw new InputParseException("No session is available, so no clipboard is available");
}
}
case "#buffer": {
return new BufferedPattern(FawePlayer.wrap(context.requireActor()), catchSuggestion(input, rest, context));
}
case "#iddatamask": {
String[] split = rest.split(":", 1);
if (split.length != 2) {

View File

@ -424,13 +424,12 @@ public final class CommandManager {
}
} finally {
final EditSession editSession = locals.get(EditSession.class);
boolean hasSession = false;
if (editSession != null) {
editSession.flushQueue();
worldEdit.flushBlockBag(finalActor, editSession);
session.remember(editSession);
final long time = System.currentTimeMillis() - start;
if (time > 250 && hasSession) {
if (time > 1000) {
BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d));
}
Request.reset();

View File

@ -138,10 +138,9 @@ public interface Extent extends InputExtent, OutputExtent {
}
}
}
return maxY;
return maxY >= 255 ? maxY : -1;
}
default public void addCaves(Region region) throws WorldEditException {
generate(region, new CavesGen(8));
}

View File

@ -0,0 +1,93 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.function;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.function.mask.Mask;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Applies a {@link RegionFunction} to the first ground block.
*/
public class GroundFunction implements LayerFunction {
private Mask mask;
private final RegionFunction function;
private int affected;
/**
* Create a new ground function.
*
* @param mask a mask
* @param function the function to apply
*/
public GroundFunction(Mask mask, RegionFunction function) {
checkNotNull(mask);
checkNotNull(function);
this.mask = mask;
this.function = function;
}
/**
* Get the mask that determines what the ground consists of.
*
* @return a mask
*/
public Mask getMask() {
return mask;
}
/**
* Set the mask that determines what the ground consists of.
*
* @param mask a mask
*/
public void setMask(Mask mask) {
checkNotNull(mask);
this.mask = mask;
}
/**
* Get the number of affected objects.
*
* @return the number of affected
*/
public int getAffected() {
return affected;
}
@Override
public boolean isGround(Vector position) {
return mask.test(position);
}
@Override
public boolean apply(Vector position, int depth) throws WorldEditException {
if (depth == 0) {
if (function.apply(position)) {
affected++;
}
}
return false;
}
}

View File

@ -20,6 +20,10 @@
package com.sk89q.worldedit.function.visitor;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.object.visitor.Fast2DIterator;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.function.FlatRegionFunction;
@ -38,6 +42,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class FlatRegionVisitor implements Operation {
private final FlatRegionFunction function;
private MappedFaweQueue queue;
private int affected = 0;
private final Iterable<Vector2D> iterator;
@ -54,6 +59,15 @@ public class FlatRegionVisitor implements Operation {
this.iterator = flatRegion.asFlatRegion();
}
public FlatRegionVisitor(final FlatRegion flatRegion, final FlatRegionFunction function, HasFaweQueue hasFaweQueue) {
checkNotNull(flatRegion);
checkNotNull(function);
this.function = function;
this.iterator = flatRegion.asFlatRegion();
FaweQueue queue = hasFaweQueue.getQueue();
this.queue = (MappedFaweQueue) (queue instanceof MappedFaweQueue ? queue : null);
}
/**
* Get the number of affected objects.
*
@ -65,9 +79,13 @@ public class FlatRegionVisitor implements Operation {
@Override
public Operation resume(final RunContext run) throws WorldEditException {
for (final Vector2D pt : this.iterator) {
if (this.function.apply(pt)) {
affected++;
if (this.queue != null) {
for (final Vector2D pt : new Fast2DIterator(this.iterator, queue)) {
if (this.function.apply(pt)) affected++;
}
} else {
for (final Vector2D pt : this.iterator) {
if (this.function.apply(pt)) affected++;
}
}
return null;

View File

@ -43,6 +43,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
* maximum Y down to a minimum Y), and then applies a {@link LayerFunction} to
* each layer.</p>
*/
@Deprecated
public class LayerVisitor implements Operation {
private final LayerFunction function;