Masking changes

Add light related masks
- #opacity
- #brightness
- #blocklight
- #skylight
- #light
- #nolight
- #haslight
Add mask tab completion
Add source masks
- `/gsmask` and `/smask`
- Masking the source instead of the destination (e.g. with //paste)
- if there is no source, the current block/extent will be used
This commit is contained in:
Jesse Boyd 2016-12-15 18:36:04 +11:00
parent bde4749e2c
commit 30700559db
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
26 changed files with 910 additions and 64 deletions

View File

@ -0,0 +1,44 @@
package com.boydti.fawe.command;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.StringMan;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.DefaultMaskParser;
import com.sk89q.worldedit.util.command.parametric.ParameterData;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MaskBinding extends FaweBinding {
private final WorldEdit worldEdit;
public MaskBinding(WorldEdit worldEdit) {
super(worldEdit);
this.worldEdit = worldEdit;
}
@Override
public List<String> getSuggestions(ParameterData parameter, String prefix) {
int index = prefix.lastIndexOf(",");
String start = index != -1 ? prefix.substring(0, index) : "";
String current = index != -1 ? prefix.substring(index) : prefix;
if (current.isEmpty()) {
return MainUtil.prepend(start, Arrays.asList(DefaultMaskParser.ALL_MASKS));
}
if (current.startsWith("#") || current.startsWith("=")) {
return new ArrayList<>();
}
if (StringMan.isAlphanumeric(current.charAt(0) + "")) {
String[] split2 = current.split(":");
if (split2.length == 2 || current.endsWith(":")) {
start = (start.isEmpty() ? split2[0] : start + " " + split2[0]) + ":";
current = split2.length == 2 ? split2[1] : "";
return MainUtil.prepend(start, MainUtil.filter(current, BundledBlockData.getInstance().getBlockStates(split2[0])));
}
List<String> blocks = BundledBlockData.getInstance().getBlockNames(split2[0]);
return MainUtil.prepend(start, blocks);
}
return new ArrayList<>();
}
}

View File

@ -50,6 +50,8 @@ public enum BBC {
MASK_DISABLED("Global mask disabled", "WorldEdit.General"), MASK_DISABLED("Global mask disabled", "WorldEdit.General"),
MASK("Global mask set", "WorldEdit.General"), MASK("Global mask set", "WorldEdit.General"),
SOURCE_MASK_DISABLED("Global source mask disabled", "WorldEdit.General"),
SOURCE_MASK("Global source mask set", "WorldEdit.General"),
TRANSFORM_DISABLED("Global transform disabled", "WorldEdit.General"), TRANSFORM_DISABLED("Global transform disabled", "WorldEdit.General"),
TRANSFORM("Global transform set", "WorldEdit.General"), TRANSFORM("Global transform set", "WorldEdit.General"),
@ -85,6 +87,7 @@ public enum BBC {
SELECTION_CLEARED("Selection cleared", "WorldEdit.Selection"), SELECTION_CLEARED("Selection cleared", "WorldEdit.Selection"),
SELECTION_NONE("Make a region selection first", "WorldEdit.Selection"), SELECTION_NONE("Make a region selection first", "WorldEdit.Selection"),
BRUSH_NONE("You aren't holding a brush!", "WorldEdit.Brush"),
BRUSH_BUTCHER("Butcher brush equiped (%s0)", "WorldEdit.Brush"), BRUSH_BUTCHER("Butcher brush equiped (%s0)", "WorldEdit.Brush"),
BRUSH_CLIPBOARD("Clipboard brush shape equipped", "WorldEdit.Brush"), BRUSH_CLIPBOARD("Clipboard brush shape equipped", "WorldEdit.Brush"),
BRUSH_CYLINDER("Cylinder brush shape equipped (%s0 by %s1).", "WorldEdit.Brush"), BRUSH_CYLINDER("Cylinder brush shape equipped (%s0 by %s1).", "WorldEdit.Brush"),
@ -110,6 +113,8 @@ public enum BBC {
BRUSH_RANGE("Brush size set", "WorldEdit.Brush"), BRUSH_RANGE("Brush size set", "WorldEdit.Brush"),
BRUSH_MASK_DISABLED("Brush mask disabled", "WorldEdit.Brush"), BRUSH_MASK_DISABLED("Brush mask disabled", "WorldEdit.Brush"),
BRUSH_MASK("Brush mask set", "WorldEdit.Brush"), BRUSH_MASK("Brush mask set", "WorldEdit.Brush"),
BRUSH_SOURCE_MASK_DISABLED("Brush source mask disabled", "WorldEdit.Brush"),
BRUSH_SOURCE_MASK("Brush source mask set", "WorldEdit.Brush"),
BRUSH_TRANSFORM_DISABLED("Brush transform disabled", "WorldEdit.Brush"), BRUSH_TRANSFORM_DISABLED("Brush transform disabled", "WorldEdit.Brush"),
BRUSH_TRANSFORM("Brush transform set", "WorldEdit.Brush"), BRUSH_TRANSFORM("Brush transform set", "WorldEdit.Brush"),
BRUSH_MATERIAL("Brush material set", "WorldEdit.Brush"), BRUSH_MATERIAL("Brush material set", "WorldEdit.Brush"),

View File

@ -30,6 +30,7 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool {
protected static int MAX_RANGE = 500; protected static int MAX_RANGE = 500;
protected int range = -1; protected int range = -1;
private Mask mask = null; private Mask mask = null;
private Mask sourceMask = null;
private ResettableExtent transform = null; private ResettableExtent transform = null;
private DoubleActionBrush brush = null; private DoubleActionBrush brush = null;
@Nullable @Nullable
@ -69,6 +70,15 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool {
return mask; return mask;
} }
/**
* Get the filter.
*
* @return the filter
*/
public Mask getSourceMask() {
return sourceMask;
}
/** /**
* Set the block filter used for identifying blocks to replace. * Set the block filter used for identifying blocks to replace.
* *
@ -78,6 +88,15 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool {
this.mask = filter; this.mask = filter;
} }
/**
* Set the block filter used for identifying blocks to replace.
*
* @param filter the filter to set
*/
public void setSourceMask(Mask filter) {
this.sourceMask = filter;
}
/** /**
* Set the brush. * Set the brush.
* *
@ -178,6 +197,19 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool {
editSession.setMask(newMask); editSession.setMask(newMask);
} }
} }
if (sourceMask != null) {
Mask existingMask = editSession.getSourceMask();
if (existingMask == null) {
editSession.setSourceMask(sourceMask);
} else if (existingMask instanceof MaskIntersection) {
((MaskIntersection) existingMask).add(sourceMask);
} else {
MaskIntersection newMask = new MaskIntersection(existingMask);
newMask.add(sourceMask);
editSession.setSourceMask(newMask);
}
}
if (transform != null) { if (transform != null) {
editSession.addTransform(transform); editSession.addTransform(transform);
} }

View File

@ -40,6 +40,31 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa
return queue; return queue;
} }
@Override
public int getLight(int x, int y, int z) {
return queue.getLight(x, y, z);
}
@Override
public int getBlockLight(int x, int y, int z) {
return queue.getEmmittedLight(x, y, z);
}
@Override
public int getSkyLight(int x, int y, int z) {
return queue.getSkyLight(x, y, z);
}
@Override
public int getBrightness(int x, int y, int z) {
return queue.getBrightness(x, y, z);
}
@Override
public int getOpacity(int x, int y, int z) {
return queue.getOpacity(x, y, z);
}
@Override @Override
public Entity createEntity(final Location loc, final BaseEntity entity) { public Entity createEntity(final Location loc, final BaseEntity entity) {
if (entity != null) { if (entity != null) {

View File

@ -0,0 +1,11 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.extent.Extent;
public interface LightingExtent extends Extent {
int getLight(int x, int y, int z);
int getSkyLight(int x, int y, int z);
int getBlockLight(int x, int y, int z);
int getOpacity(int x, int y, int z);
int getBrightness(int x, int y, int z);
}

View File

@ -0,0 +1,55 @@
package com.boydti.fawe.object.extent;
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.mask.Mask;
import static com.google.common.base.Preconditions.checkNotNull;
public class SourceMaskExtent extends TemporalExtent {
private Mask mask;
private Vector mutable = new Vector();
/**
* Get the mask.
*
* @return the mask
*/
public Mask getMask() {
return mask;
}
/**
* Set a mask.
*
* @param mask a mask
*/
public void setMask(Mask mask) {
checkNotNull(mask);
this.mask = mask;
}
public SourceMaskExtent(Extent extent, Mask mask) {
super(extent);
checkNotNull(mask);
this.mask = mask;
}
@Override
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
set((int) location.x, (int) location.y, (int) location.z, block);
return mask.test(location) && super.setBlock(location, block);
}
@Override
public boolean setBlock(int x, int y, int z, BaseBlock block) throws WorldEditException {
set(x, y, z, block);
mutable.x = x;
mutable.y = y;
mutable.z = z;
return mask.test(mutable) && super.setBlock(x, y, z, block);
}
}

View File

@ -0,0 +1,86 @@
package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockMaterial;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.BundledBlockData;
public class TemporalExtent extends AbstractDelegateExtent {
private int x,y,z = Integer.MAX_VALUE;
private BaseBlock block = EditSession.nullBlock;
private int bx,bz = Integer.MAX_VALUE;
private BaseBiome biome = EditSession.nullBiome;
/**
* Create a new instance.
*
* @param extent the extent
*/
public TemporalExtent(Extent extent) {
super(extent);
}
public void set(int x, int y, int z, BaseBlock block) {
this.x = x;
this.y = y;
this.z = z;
this.block = block;
}
public void set(int x, int z, BaseBiome biome) {
this.bx = x;
this.bz = z;
this.biome = biome;
}
@Override
public int getBrightness(int x, int y, int z) {
if (this.x == x && this.y == y && this.z == z) {
BlockMaterial block = BundledBlockData.getInstance().getMaterialById(this.block.getId());
if (block == null) {
return 15;
}
return Math.min(15, block.getLightValue());
}
return super.getBrightness(x, y, z);
}
@Override
public BaseBlock getBlock(Vector position) {
if (position.x == x && position.y == y && position.z == z) {
return block;
}
return super.getBlock(position);
}
@Override
public BaseBlock getLazyBlock(Vector position) {
if (position.x == x && position.y == y && position.z == z) {
return block;
}
return super.getLazyBlock(position);
}
@Override
public BaseBlock getLazyBlock(int x, int y, int z) {
if (this.x == x && this.y == y && this.z == z) {
return block;
}
return super.getLazyBlock(x, y, z);
}
@Override
public BaseBiome getBiome(Vector2D position) {
if (position.getX() == bx && position.getZ() == bz) {
return biome;
}
return super.getBiome(position);
}
}

View File

@ -0,0 +1,35 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import javax.annotation.Nullable;
public class BlockLightMask implements Mask {
private final Extent extent;
private final int min,max;
public BlockLightMask(Extent extent, int min, int max) {
this.extent = extent;
this.min = min;
this.max = max;
}
@Override
public boolean test(Vector vector) {
if (extent instanceof LightingExtent) {
int light = ((LightingExtent) extent).getBlockLight((int) vector.x, (int) vector.y, (int) vector.z);
return light >= min && light <= max;
}
return false;
}
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}

View File

@ -0,0 +1,35 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import javax.annotation.Nullable;
public class BrightnessMask implements Mask {
private final Extent extent;
private final int min,max;
public BrightnessMask(Extent extent, int min, int max) {
this.extent = extent;
this.min = min;
this.max = max;
}
@Override
public boolean test(Vector vector) {
if (extent instanceof LightingExtent) {
int light = ((LightingExtent) extent).getBrightness((int) vector.x, (int) vector.y, (int) vector.z);
return light >= min && light <= max;
}
return false;
}
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}

View File

@ -0,0 +1,35 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import javax.annotation.Nullable;
public class LightMask implements Mask {
private final Extent extent;
private final int min,max;
public LightMask(Extent extent, int min, int max) {
this.extent = extent;
this.min = min;
this.max = max;
}
@Override
public boolean test(Vector vector) {
if (extent instanceof LightingExtent) {
int light = ((LightingExtent) extent).getLight((int) vector.x, (int) vector.y, (int) vector.z);
return light >= min && light <= max;
}
return false;
}
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}

View File

@ -0,0 +1,35 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import javax.annotation.Nullable;
public class OpacityMask implements Mask {
private final Extent extent;
private final int min,max;
public OpacityMask(Extent extent, int min, int max) {
this.extent = extent;
this.min = min;
this.max = max;
}
@Override
public boolean test(Vector vector) {
if (extent instanceof LightingExtent) {
int light = ((LightingExtent) extent).getOpacity((int) vector.x, (int) vector.y, (int) vector.z);
return light >= min && light <= max;
}
return false;
}
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}

View File

@ -0,0 +1,35 @@
package com.boydti.fawe.object.mask;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import javax.annotation.Nullable;
public class SkyLightMask implements Mask {
private final Extent extent;
private final int min,max;
public SkyLightMask(Extent extent, int min, int max) {
this.extent = extent;
this.min = min;
this.max = max;
}
@Override
public boolean test(Vector vector) {
if (extent instanceof LightingExtent) {
int light = ((LightingExtent) extent).getSkyLight((int) vector.x, (int) vector.y, (int) vector.z);
return light >= min && light <= max;
}
return false;
}
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object.schematic;
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard; import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.MaskTraverser;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
@ -12,6 +13,7 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
@ -114,6 +116,12 @@ public class Schematic {
if (transform != null) { if (transform != null) {
copy.setTransform(transform); copy.setTransform(transform);
} }
Mask sourceMask = editSession.getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(extent);
copy.setSourceMask(sourceMask);
editSession.setSourceMask(null);
}
if (!pasteAir) { if (!pasteAir) {
copy.setSourceMask(new ExistingBlockMask(clipboard)); copy.setSourceMask(new ExistingBlockMask(clipboard));
} }

View File

@ -44,10 +44,12 @@ import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.extent.FastWorldEditExtent; import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.object.extent.FaweRegionExtent; import com.boydti.fawe.object.extent.FaweRegionExtent;
import com.boydti.fawe.object.extent.LightingExtent;
import com.boydti.fawe.object.extent.NullExtent; import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ProcessedWEExtent; import com.boydti.fawe.object.extent.ProcessedWEExtent;
import com.boydti.fawe.object.extent.ResettableExtent; import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.extent.SlowExtent; import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.SourceMaskExtent;
import com.boydti.fawe.object.mask.ResettableMask; import com.boydti.fawe.object.mask.ResettableMask;
import com.boydti.fawe.object.progress.DefaultProgressTracker; import com.boydti.fawe.object.progress.DefaultProgressTracker;
import com.boydti.fawe.util.ExtentTraverser; import com.boydti.fawe.util.ExtentTraverser;
@ -155,7 +157,7 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
* {@link Extent}s that are chained together. For example, history is logged * {@link Extent}s that are chained together. For example, history is logged
* using the {@link ChangeSetExtent}.</p> * using the {@link ChangeSetExtent}.</p>
*/ */
public class EditSession extends AbstractWorld implements HasFaweQueue { public class EditSession extends AbstractWorld implements HasFaweQueue, LightingExtent {
/** /**
* Used by {@link #setBlock(Vector, BaseBlock, Stage)} to * Used by {@link #setBlock(Vector, BaseBlock, Stage)} to
* determine which {@link Extent}s should be bypassed. * determine which {@link Extent}s should be bypassed.
@ -592,6 +594,16 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
return maskingExtent != null ? maskingExtent.get().getMask() : null; return maskingExtent != null ? maskingExtent.get().getMask() : null;
} }
/**
* Get the mask.
*
* @return mask, may be null
*/
public Mask getSourceMask() {
ExtentTraverser<SourceMaskExtent> maskingExtent = new ExtentTraverser(this.extent).find(SourceMaskExtent.class);
return maskingExtent != null ? maskingExtent.get().getMask() : null;
}
public void addTransform(ResettableExtent transform) { public void addTransform(ResettableExtent transform) {
if (transform == null) { if (transform == null) {
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class); ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
@ -607,6 +619,29 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
} }
} }
/**
* Set a mask.
*
* @param mask mask or null
*/
public void setSourceMask(Mask mask) {
if (mask == null) {
mask = Masks.alwaysTrue();
} else {
new MaskTraverser(mask).reset(this);
}
ExtentTraverser<SourceMaskExtent> maskingExtent = new ExtentTraverser(this.extent).find(SourceMaskExtent.class);
if (maskingExtent != null && maskingExtent.get() != null) {
Mask oldMask = maskingExtent.get().getMask();
if (oldMask instanceof ResettableMask) {
((ResettableMask) oldMask).reset();
}
maskingExtent.get().setMask(mask);
} else if (mask != Masks.alwaysTrue()) {
this.extent = new SourceMaskExtent(this.extent, mask);
}
}
/** /**
* Set a mask. * Set a mask.
* *
@ -792,6 +827,31 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
return this.extent.setBiome(position, biome); return this.extent.setBiome(position, biome);
} }
@Override
public int getLight(int x, int y, int z) {
return queue.getLight(x, y, z);
}
@Override
public int getBlockLight(int x, int y, int z) {
return queue.getEmmittedLight(x, y, z);
}
@Override
public int getSkyLight(int x, int y, int z) {
return queue.getSkyLight(x, y, z);
}
@Override
public int getBrightness(int x, int y, int z) {
return queue.getBrightness(x, y, z);
}
@Override
public int getOpacity(int x, int y, int z) {
return queue.getOpacity(x, y, z);
}
@Override @Override
public BaseBlock getLazyBlock(final Vector position) { public BaseBlock getLazyBlock(final Vector position) {
if (position.y > maxY || position.y < 0) { if (position.y > maxY || position.y < 0) {
@ -1794,6 +1854,12 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, EditSession.this, to); final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, EditSession.this, to);
copy.setRepetitions(count); copy.setRepetitions(count);
copy.setTransform(new AffineTransform().translate(dir.multiply(size))); copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
Mask sourceMask = getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(EditSession.this);
copy.setSourceMask(sourceMask);
setSourceMask(null);
}
if (!copyAir) { if (!copyAir) {
copy.setSourceMask(new ExistingBlockMask(EditSession.this)); copy.setSourceMask(new ExistingBlockMask(EditSession.this));
} }
@ -1844,6 +1910,12 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
copy.setTransform(new AffineTransform().translate(dir.multiply(distance))); copy.setTransform(new AffineTransform().translate(dir.multiply(distance)));
copy.setSourceFunction(remove); // Remove copy.setSourceFunction(remove); // Remove
copy.setRemovingEntities(true); copy.setRemovingEntities(true);
Mask sourceMask = getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(EditSession.this);
copy.setSourceMask(sourceMask);
setSourceMask(null);
}
if (!copyAir) { if (!copyAir) {
copy.setSourceMask(new ExistingBlockMask(EditSession.this)); copy.setSourceMask(new ExistingBlockMask(EditSession.this));
} }

View File

@ -139,6 +139,7 @@ public class LocalSession {
private transient int cuiVersion = -1; private transient int cuiVersion = -1;
private transient boolean fastMode = false; private transient boolean fastMode = false;
private transient Mask mask; private transient Mask mask;
private transient Mask sourceMask;
private ResettableExtent transform = null; private ResettableExtent transform = null;
private transient TimeZone timezone = TimeZone.getDefault(); private transient TimeZone timezone = TimeZone.getDefault();
@ -1238,6 +1239,9 @@ public class LocalSession {
if (mask != null) { if (mask != null) {
editSession.setMask(mask); editSession.setMask(mask);
} }
if (sourceMask != null) {
editSession.setSourceMask(sourceMask);
}
if (transform != null) { if (transform != null) {
editSession.addTransform(transform); editSession.addTransform(transform);
} }
@ -1272,6 +1276,15 @@ public class LocalSession {
return mask; return mask;
} }
/**
* Get the mask.
*
* @return mask, may be null
*/
public Mask getSourceMask() {
return sourceMask;
}
/** /**
* Set a mask. * Set a mask.
* *
@ -1281,6 +1294,15 @@ public class LocalSession {
this.mask = mask; this.mask = mask;
} }
/**
* Set a mask.
*
* @param mask mask or null
*/
public void setSourceMask(Mask mask) {
this.sourceMask = mask;
}
/** /**
* Set a mask. * Set a mask.
* *
@ -1291,6 +1313,16 @@ public class LocalSession {
setMask(mask != null ? Masks.wrap(mask) : null); setMask(mask != null ? Masks.wrap(mask) : null);
} }
/**
* Set a mask.
*
* @param mask mask or null
*/
@SuppressWarnings("deprecation")
public void setSourceMask(com.sk89q.worldedit.masks.Mask mask) {
setSourceMask(mask != null ? Masks.wrap(mask) : null);
}
public ResettableExtent getTransform() { public ResettableExtent getTransform() {
return transform; return transform;
} }

View File

@ -25,6 +25,7 @@ import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard; import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.util.ImgurUtility; import com.boydti.fawe.util.ImgurUtility;
import com.boydti.fawe.util.MaskTraverser;
import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.CommandPermissions;
@ -141,6 +142,12 @@ public class ClipboardCommands {
clipboard.setOrigin(session.getPlacementPosition(player)); clipboard.setOrigin(session.getPlacementPosition(player));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
Mask sourceMask = editSession.getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(editSession);
copy.setSourceMask(sourceMask);
editSession.setSourceMask(null);
}
if (mask != null && mask != Masks.alwaysTrue()) { if (mask != null && mask != Masks.alwaysTrue()) {
copy.setSourceMask(mask); copy.setSourceMask(mask);
} }
@ -173,6 +180,12 @@ public class ClipboardCommands {
clipboard.setOrigin(session.getPlacementPosition(player)); clipboard.setOrigin(session.getPlacementPosition(player));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); copy.setSourceFunction(new BlockReplace(editSession, leavePattern));
Mask sourceMask = editSession.getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(editSession);
copy.setSourceMask(sourceMask);
editSession.setSourceMask(null);
}
if (mask != null) { if (mask != null) {
copy.setSourceMask(mask); copy.setSourceMask(mask);
} }
@ -253,7 +266,7 @@ public class ClipboardCommands {
@Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
@Switch('s') boolean selectPasted) throws WorldEditException { @Switch('s') boolean selectPasted) throws WorldEditException {
ClipboardHolder holder = session.getClipboard(); ClipboardHolder holder = session.getClipboard();
if (holder.getTransform().isIdentity()) { if (holder.getTransform().isIdentity() && editSession.getSourceMask() == null) {
place(player, session, editSession, ignoreAirBlocks, atOrigin, selectPasted); place(player, session, editSession, ignoreAirBlocks, atOrigin, selectPasted);
return; return;
} }

View File

@ -101,7 +101,7 @@ public class GeneralCommands {
} }
@Command( @Command(
aliases = { "/gmask", "gmask" }, aliases = { "/gmask", "gmask", "globalmask", "/globalmask" },
usage = "[mask]", usage = "[mask]",
desc = "Set the global mask", desc = "Set the global mask",
min = 0, min = 0,
@ -124,6 +124,30 @@ public class GeneralCommands {
} }
} }
@Command(
aliases = { "/gsmask", "gsmask", "globalsourcemask", "/globalsourcemask" },
usage = "[mask]",
desc = "Set the global source mask",
min = 0,
max = -1
)
@CommandPermissions("worldedit.global-mask")
public void gsmask(Player player, LocalSession session, EditSession editSession, @Optional CommandContext context) throws WorldEditException {
if (context == null || context.argsLength() == 0) {
session.setSourceMask((Mask) null);
BBC.SOURCE_MASK_DISABLED.send(player);
} else {
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
Mask mask = worldEdit.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext);
session.setSourceMask(mask);
BBC.SOURCE_MASK.send(player);
}
}
@Command( @Command(
aliases = { "/gtransform", "gtransform" }, aliases = { "/gtransform", "gtransform" },
usage = "[transform]", usage = "[transform]",

View File

@ -577,11 +577,15 @@ public class RegionCommands {
@Logging(REGION) @Logging(REGION)
public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException { public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException {
Mask mask = session.getMask(); Mask mask = session.getMask();
Mask sourceMask = session.getSourceMask();
try { try {
session.setMask((Mask) null); session.setMask((Mask) null);
session.setSourceMask((Mask) null);
player.getWorld().regenerate(region, editSession); player.getWorld().regenerate(region, editSession);
} finally { } finally {
session.setMask(mask); session.setMask(mask);
session.setSourceMask(mask);
} }
BBC.COMMAND_REGEN.send(player); BBC.COMMAND_REGEN.send(player);
} }

View File

@ -61,7 +61,7 @@ public class ToolUtilCommands {
} }
@Command( @Command(
aliases = { "mask" }, aliases = { "mask", "/mask" },
usage = "[mask]", usage = "[mask]",
desc = "Set the brush mask", desc = "Set the brush mask",
min = 0, min = 0,
@ -71,6 +71,7 @@ public class ToolUtilCommands {
public void mask(Player player, LocalSession session, EditSession editSession, @Optional CommandContext context) throws WorldEditException { public void mask(Player player, LocalSession session, EditSession editSession, @Optional CommandContext context) throws WorldEditException {
Tool tool = session.getTool(player.getItemInHand()); Tool tool = session.getTool(player.getItemInHand());
if (tool == null) { if (tool == null) {
player.print(BBC.BRUSH_NONE.f());
return; return;
} }
if (context == null || context.argsLength() == 0) { if (context == null || context.argsLength() == 0) {
@ -96,6 +97,43 @@ public class ToolUtilCommands {
} }
} }
@Command(
aliases = { "smask", "/smask", "/sourcemask", "sourcemask" },
usage = "[mask]",
desc = "Set the brush mask",
min = 0,
max = -1
)
@CommandPermissions("worldedit.brush.options.mask")
public void smask(Player player, LocalSession session, EditSession editSession, @Optional CommandContext context) throws WorldEditException {
Tool tool = session.getTool(player.getItemInHand());
if (tool == null) {
player.print(BBC.BRUSH_NONE.f());
return;
}
if (context == null || context.argsLength() == 0) {
if (tool instanceof BrushTool) {
((BrushTool) tool).setSourceMask(null);
} else if (tool instanceof DoubleActionBrushTool) {
((DoubleActionBrushTool) tool).setMask(null);
}
BBC.BRUSH_SOURCE_MASK_DISABLED.send(player);
} else {
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
Mask mask = we.getMaskFactory().parseFromInput(context.getJoinedStrings(0), parserContext);
if (tool instanceof BrushTool) {
((BrushTool) tool).setSourceMask(mask);
} else if (tool instanceof DoubleActionBrushTool) {
((DoubleActionBrushTool) tool).setSourceMask(mask);
}
BBC.BRUSH_SOURCE_MASK.send(player);
}
}
@Command( @Command(
aliases = { "transform" }, aliases = { "transform" },
usage = "[transform]", usage = "[transform]",

View File

@ -29,6 +29,7 @@ public class BrushTool implements TraceTool {
protected static int MAX_RANGE = 500; protected static int MAX_RANGE = 500;
protected int range = -1; protected int range = -1;
private Mask mask = null; private Mask mask = null;
private Mask sourceMask = null;
private ResettableExtent transform = null; private ResettableExtent transform = null;
private Brush brush = new SphereBrush(); private Brush brush = new SphereBrush();
@Nullable @Nullable
@ -77,6 +78,24 @@ public class BrushTool implements TraceTool {
this.mask = filter; this.mask = filter;
} }
/**
* Get the filter.
*
* @return the filter
*/
public Mask getSourceMask() {
return sourceMask;
}
/**
* Set the block filter used for identifying blocks to replace.
*
* @param filter the filter to set
*/
public void setSourceMask(Mask filter) {
this.sourceMask = filter;
}
/** /**
* Set the brush. * Set the brush.
* *
@ -178,6 +197,19 @@ public class BrushTool implements TraceTool {
editSession.setMask(newMask); editSession.setMask(newMask);
} }
} }
if (sourceMask != null) {
Mask existingMask = editSession.getMask();
if (existingMask == null) {
editSession.setSourceMask(sourceMask);
} else if (existingMask instanceof MaskIntersection) {
((MaskIntersection) existingMask).add(sourceMask);
} else {
MaskIntersection newMask = new MaskIntersection(existingMask);
newMask.add(sourceMask);
editSession.setSourceMask(newMask);
}
}
if (transform != null) { if (transform != null) {
editSession.addTransform(transform); editSession.addTransform(transform);
} }

View File

@ -1,24 +1,16 @@
package com.sk89q.worldedit.extension.factory; package com.sk89q.worldedit.extension.factory;
import com.boydti.fawe.command.FaweParser; import com.boydti.fawe.command.FaweParser;
import com.boydti.fawe.object.mask.AdjacentMask; import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.object.mask.AngleMask; import com.boydti.fawe.object.mask.*;
import com.boydti.fawe.object.mask.CustomMask; import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.object.mask.DataMask; import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.object.mask.IdDataMask;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.object.mask.RadiusMask;
import com.boydti.fawe.object.mask.WallMask;
import com.boydti.fawe.object.mask.XAxisMask;
import com.boydti.fawe.object.mask.YAxisMask;
import com.boydti.fawe.object.mask.ZAxisMask;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BiomeMask2D; import com.sk89q.worldedit.function.mask.BiomeMask2D;
@ -27,6 +19,7 @@ import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.ExpressionMask; import com.sk89q.worldedit.function.mask.ExpressionMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.MaskUnion;
import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.NoiseFilter; import com.sk89q.worldedit.function.mask.NoiseFilter;
import com.sk89q.worldedit.function.mask.OffsetMask; import com.sk89q.worldedit.function.mask.OffsetMask;
@ -58,16 +51,24 @@ public class DefaultMaskParser extends FaweParser<Mask> {
public static final String[] EXPRESSION_MASK = new String[] { "=<expression>" }; public static final String[] EXPRESSION_MASK = new String[] { "=<expression>" };
public static final String[] BLOCK_MASK = new String[] { "<block>" }; public static final String[] BLOCK_MASK = new String[] { "<blocks>" };
public static final String[] SIMPLE_MASK = new String[] { public static final String[] SIMPLE_MASK = new String[] {
"#existing", "#solid", "#dregion", "#dselection", "#dsel", "#selection", "#region", "#sel", "#xaxis", "#yaxis", "#zaxis", "#id", "#data", "#wall", "#surface", "#nolight", "#haslight", "#existing", "#solid", "#dregion", "#dselection", "#dsel", "#selection", "#region", "#sel", "#xaxis", "#yaxis", "#zaxis", "#id", "#data", "#wall", "#surface",
}; };
public static final String[] MISC_PATTERNS = new String[] { public static final String[] DELEGATE_MASKS = new String[] {
"hand", "pos1", "#offset:", "#light:", "#blocklight:", "#skylight:", "#brightness:", "#opacity:"
}; };
public static final String[] CHARACTER_MASKS= new String[] {
"/", "{", "|", "~", ">", "<", "$", "%", "=", "!",
};
public static final String[] HASHTAG_MASKS = MainUtil.joinArrayGeneric(SIMPLE_MASK, DELEGATE_MASKS);
public static final String[] ALL_MASKS = MainUtil.joinArrayGeneric(EXPRESSION_MASK, BLOCK_MASK, SIMPLE_MASK, DELEGATE_MASKS, CHARACTER_MASKS);
public DefaultMaskParser(WorldEdit worldEdit) { public DefaultMaskParser(WorldEdit worldEdit) {
super(worldEdit); super(worldEdit);
} }
@ -111,19 +112,83 @@ public class DefaultMaskParser extends FaweParser<Mask> {
} }
} }
private Mask getBlockMaskComponent(List<Mask> masks, String component, ParserContext context) throws InputParseException { public Mask catchSuggestion(String currentInput, List<Mask> masks, String nextInput, ParserContext context) throws InputParseException {
try {
return getBlockMaskComponent(masks, nextInput, context);
} catch (SuggestInputParseException e) {
e.prepend(currentInput.substring(0, currentInput.length() - nextInput.length()));
throw e;
}
}
private Mask getBlockMaskComponent(List<Mask> masks, String input, ParserContext context) throws InputParseException {
Extent extent = Request.request().getExtent(); Extent extent = Request.request().getExtent();
final char firstChar = component.charAt(0); final char firstChar = input.charAt(0);
switch (firstChar) { switch (firstChar) {
case '#': case '#':
int colon = component.indexOf(':'); int colon = input.indexOf(':');
String component = input;
if (colon != -1) { if (colon != -1) {
String rest = component.substring(colon + 1);
component = component.substring(0, colon); component = component.substring(0, colon);
masks.add(getBlockMaskComponent(masks, rest, context)); String rest = input.substring(colon + 1);
switch (component.toLowerCase()) {
case "#light":
case "#skylight":
case "#blocklight":
case "#emittedlight":
case "#opacity":
case "#brightness":
String[] split = rest.split(":");
if (split.length < 2) {
throw new SuggestInputParseException(input, component + ":<min>:<max>");
} else if (split.length > 2) {
masks.add(catchSuggestion(input, masks, StringMan.join(Arrays.copyOfRange(split, 2, split.length), ":"), context));
}
try {
int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate());
int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate());
switch (component.toLowerCase()) {
case "#light":
return new LightMask(extent, y1, y2);
case "#skylight":
return new SkyLightMask(extent, y1, y2);
case "#blocklight":
case "#emittedlight":
return new BlockLightMask(extent, y1, y2);
case "#opacity":
return new OpacityMask(extent, y1, y2);
case "#brightness":
return new BrightnessMask(extent, y1, y2);
}
} catch (NumberFormatException | ExpressionException e) {
e.printStackTrace();
throw new SuggestInputParseException(input, component + ":<min>:<max>");
}
case "#~":
case "#rel":
case "#relative":
case "#offset":
try {
List<String> split3 = suggestRemaining(rest, "#offset", "<dx>", "<dy>", "<dz>", "<mask>");
int x = (int) Expression.compile(split3.get(0)).evaluate();
int y = (int) Expression.compile(split3.get(1)).evaluate();
int z = (int) Expression.compile(split3.get(2)).evaluate();
rest = StringMan.join(split3.subList(3, split3.size()), ":");
Mask mask = catchSuggestion(input, masks, rest, context);
return new OffsetMask(mask, new Vector(x, y, z));
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
throw new SuggestInputParseException(null, "#offset:<dx>:<dy>:<dz>:<mask>");
}
}
Mask mask = catchSuggestion(input, masks, rest, context);
masks.add(mask);
} }
switch (component.toLowerCase()) { switch (component.toLowerCase()) {
case "#haslight":
return new LightMask(extent, 1, Integer.MAX_VALUE);
case "#nolight":
return new LightMask(extent, 0, 0);
case "#existing": case "#existing":
return new ExistingBlockMask(extent); return new ExistingBlockMask(extent);
case "#solid": case "#solid":
@ -160,38 +225,38 @@ public class DefaultMaskParser extends FaweParser<Mask> {
masks.add(new ExistingBlockMask(extent)); masks.add(new ExistingBlockMask(extent));
return new AdjacentMask(extent, Arrays.asList(new BaseBlock(0)), 1, 8); return new AdjacentMask(extent, Arrays.asList(new BaseBlock(0)), 1, 8);
default: default:
throw new NoMatchException("Unrecognized mask '" + component + "'"); throw new SuggestInputParseException(input, HASHTAG_MASKS);
} }
case '\\': case '\\':
case '/': { case '/': {
String[] split = component.substring(1).split(","); String[] split = input.substring(1).split(":");
if (split.length != 2) { if (split.length != 2) {
throw new InputParseException("Unknown angle '" + component + "' (not in form `/#,#`)"); throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
} }
try { try {
int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate()); int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate());
int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate()); int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate());
return new AngleMask(extent, y1, y2); return new AngleMask(extent, y1, y2);
} catch (NumberFormatException | ExpressionException e) { } catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("Unknown angle '" + component + "' (not in form `/#,#`)"); throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
} }
} }
case '{': { case '{': {
String[] split = component.substring(1).split(","); String[] split = input.substring(1).split(":");
if (split.length != 2) { if (split.length != 2) {
throw new InputParseException("Unknown range '" + component + "' (not in form `{#,#`)"); throw new SuggestInputParseException(input, "{<min-radius>:<max-radius>");
} }
try { try {
int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate()); int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate());
int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate()); int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate());
return new RadiusMask(y1, y2); return new RadiusMask(y1, y2);
} catch (NumberFormatException | ExpressionException e) { } catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("Unknown range '" + component + "' (not in form `{#,#`)"); throw new SuggestInputParseException(input, "{<min-radius>:<max-radius>");
} }
} }
case '|': case '|':
case '~': { case '~': {
String[] split = component.substring(1).split("="); String[] split = input.substring(1).split("=");
ParserContext tempContext = new ParserContext(context); ParserContext tempContext = new ParserContext(context);
tempContext.setRestricted(false); tempContext.setRestricted(false);
tempContext.setPreferringWildcard(true); tempContext.setPreferringWildcard(true);
@ -206,19 +271,19 @@ public class DefaultMaskParser extends FaweParser<Mask> {
} }
} }
if (firstChar == '~') { if (firstChar == '~') {
return new AdjacentMask(extent, worldEdit.getBlockFactory().parseFromListInput(component.substring(1), tempContext), requiredMin, requiredMax); return new AdjacentMask(extent, worldEdit.getBlockFactory().parseFromListInput(input.substring(1), tempContext), requiredMin, requiredMax);
} else { } else {
return new WallMask(extent, worldEdit.getBlockFactory().parseFromListInput(component.substring(1), tempContext), requiredMin, requiredMax); return new WallMask(extent, worldEdit.getBlockFactory().parseFromListInput(input.substring(1), tempContext), requiredMin, requiredMax);
} }
} catch (NumberFormatException | ExpressionException e) { } catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("Unknown adjacent mask '" + component + "' (not in form `~<ids>[=count]`)"); throw new SuggestInputParseException(input, "~<blocks>=<amount>");
} }
} }
case '>': case '>':
case '<': case '<':
Mask submask; Mask submask;
if (component.length() > 1) { if (input.length() > 1) {
submask = getBlockMaskComponent(masks, component.substring(1), context); submask = getBlockMaskComponent(masks, input.substring(1), context);
} else { } else {
submask = new ExistingBlockMask(extent); submask = new ExistingBlockMask(extent);
} }
@ -227,58 +292,80 @@ public class DefaultMaskParser extends FaweParser<Mask> {
case '$': case '$':
Set<BaseBiome> biomes = new HashSet<BaseBiome>(); Set<BaseBiome> biomes = new HashSet<BaseBiome>();
String[] biomesList = component.substring(1).split(","); String[] biomesList = input.substring(1).split(",");
BiomeRegistry biomeRegistry = context.requireWorld().getWorldData().getBiomeRegistry(); BiomeRegistry biomeRegistry = context.requireWorld().getWorldData().getBiomeRegistry();
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes(); List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
for (String biomeName : biomesList) { for (String biomeName : biomesList) {
BaseBiome biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry); BaseBiome biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry);
if (biome == null) { if (biome == null) {
throw new InputParseException("Unknown biome '" + biomeName + "'"); throw new SuggestInputParseException(input, "$<biome>");
} }
biomes.add(biome); biomes.add(biome);
} }
return Masks.asMask(new BiomeMask2D(context.requireExtent(), biomes)); return Masks.asMask(new BiomeMask2D(context.requireExtent(), biomes));
case '%': case '%':
try { try {
double i = Math.abs(Expression.compile(component.substring(1)).evaluate()); double i = Math.abs(Expression.compile(input.substring(1)).evaluate());
return new NoiseFilter(new RandomNoise(), (i) / 100); return new NoiseFilter(new RandomNoise(), (i) / 100);
} catch (NumberFormatException | ExpressionException e) { } catch (NumberFormatException | ExpressionException e) {
throw new InputParseException("Unknown percentage '" + component.substring(1) + "'"); throw new SuggestInputParseException(input, "%<percent>");
} }
case '=': case '=':
try { try {
Expression exp = Expression.compile(component.substring(1), "x", "y", "z"); Expression exp = Expression.compile(input.substring(1), "x", "y", "z");
WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment(
Request.request().getEditSession(), Vector.ONE, Vector.ZERO); Request.request().getEditSession(), Vector.ONE, Vector.ZERO);
exp.setEnvironment(env); exp.setEnvironment(env);
return new ExpressionMask(exp); return new ExpressionMask(exp);
} catch (ExpressionException e) { } catch (ExpressionException e) {
throw new InputParseException("Invalid expression: " + e.getMessage()); throw new SuggestInputParseException(input, "=<expression>");
} }
case '!': case '!':
if (component.length() > 1) { if (input.length() > 1) {
return Masks.negate(getBlockMaskComponent(masks, component.substring(1), context)); return Masks.negate(getBlockMaskComponent(masks, input.substring(1), context));
} }
throw new SuggestInputParseException(input, "!<mask>");
default: default:
for (CustomMask mask : customMasks) { for (CustomMask mask : customMasks) {
if (mask.accepts(component)) { if (mask.accepts(input)) {
try { try {
Constructor<? extends CustomMask> constructor = mask.getClass().getDeclaredConstructor(List.class, String.class, ParserContext.class); Constructor<? extends CustomMask> constructor = mask.getClass().getDeclaredConstructor(List.class, String.class, ParserContext.class);
return constructor.newInstance(masks, component, context); return constructor.newInstance(masks, input, context);
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
List<String> split = split(input, ',');
ParserContext tempContext = new ParserContext(context); if (split.size() == 1) {
tempContext.setRestricted(false); ParserContext tempContext = new ParserContext(context);
tempContext.setPreferringWildcard(true); tempContext.setRestricted(false);
return new BlockMask(extent, worldEdit.getBlockFactory().parseFromListInput(component, tempContext)); tempContext.setPreferringWildcard(true);
return new BlockMask(extent, worldEdit.getBlockFactory().parseFromListInput(input, tempContext));
}
HashSet<BaseBlock> blocks = new HashSet<BaseBlock>();
ArrayList<Mask> maskUnion = new ArrayList<Mask>();
for (String elem : split) {
ArrayList<Mask> list = new ArrayList<Mask>();
list.add(catchSuggestion(input, list, elem, context));
if (list.size() == 1) {
Mask mask = list.get(0);
if (mask instanceof BlockMask) {
blocks.addAll(((BlockMask) mask).getBlocks());
} else {
maskUnion.add(mask);
}
}
}
if (!blocks.isEmpty()) {
maskUnion.add(new BlockMask(extent, blocks));
}
if (maskUnion.size() == 1) {
return maskUnion.get(0);
}
return new MaskUnion(maskUnion);
} }
} }

View File

@ -145,10 +145,10 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
case "#offset": case "#offset":
try { try {
List<String> split3 = suggestRemaining(rest, "#offset", "<dx>", "<dy>", "<dz>", "<pattern>"); List<String> split3 = suggestRemaining(rest, "#offset", "<dx>", "<dy>", "<dz>", "<pattern>");
int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); int x = (int) Expression.compile(split3.get(0)).evaluate();
int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); int y = (int) Expression.compile(split3.get(1)).evaluate();
int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); int z = (int) Expression.compile(split3.get(2)).evaluate();
rest = StringMan.join(split3.subList(3, split3.size() - 1), ":"); rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context); Pattern pattern = catchSuggestion(input, rest, context);
return new OffsetPattern(pattern, x, y, z); return new OffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
@ -160,7 +160,7 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate());
int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate());
int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate());
rest = StringMan.join(split3.subList(3, split3.size() - 1), ":"); rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context); Pattern pattern = catchSuggestion(input, rest, context);
return new SurfaceRandomOffsetPattern(pattern, x, y, z); return new SurfaceRandomOffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
@ -173,7 +173,7 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate());
int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate());
int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate());
rest = StringMan.join(split3.subList(3, split3.size() - 1), ":"); rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context); Pattern pattern = catchSuggestion(input, rest, context);
return new SolidRandomOffsetPattern(pattern, x, y, z); return new SolidRandomOffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {
@ -187,7 +187,7 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate()); int x = (int) Math.abs(Expression.compile(split3.get(0)).evaluate());
int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate()); int y = (int) Math.abs(Expression.compile(split3.get(1)).evaluate());
int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate()); int z = (int) Math.abs(Expression.compile(split3.get(2)).evaluate());
rest = StringMan.join(split3.subList(3, split3.size() - 1), ":"); rest = StringMan.join(split3.subList(3, split3.size()), ":");
Pattern pattern = catchSuggestion(input, rest, context); Pattern pattern = catchSuggestion(input, rest, context);
return new RandomOffsetPattern(pattern, x, y, z); return new RandomOffsetPattern(pattern, x, y, z);
} catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) { } catch (NumberFormatException | ExpressionException | IndexOutOfBoundsException e) {

View File

@ -21,6 +21,7 @@ package com.sk89q.worldedit.extension.platform;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.AnvilCommands; import com.boydti.fawe.command.AnvilCommands;
import com.boydti.fawe.command.MaskBinding;
import com.boydti.fawe.command.PatternBinding; import com.boydti.fawe.command.PatternBinding;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
@ -130,6 +131,7 @@ public final class CommandManager {
builder.addBinding(new WorldEditBinding(worldEdit)); builder.addBinding(new WorldEditBinding(worldEdit));
builder.addBinding(new PatternBinding(worldEdit), com.sk89q.worldedit.function.pattern.Pattern.class); builder.addBinding(new PatternBinding(worldEdit), com.sk89q.worldedit.function.pattern.Pattern.class);
builder.addBinding(new MaskBinding(worldEdit), com.sk89q.worldedit.function.mask.Mask.class);
builder.addInvokeListener(new LegacyCommandsHandler()); builder.addInvokeListener(new LegacyCommandsHandler());
builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog)); builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog));

View File

@ -19,10 +19,12 @@
package com.sk89q.worldedit.extent; package com.sk89q.worldedit.extent;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockMaterial;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
@ -30,6 +32,7 @@ import com.sk89q.worldedit.function.operation.OperationQueue;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.util.List; import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -39,7 +42,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* A base class for {@link Extent}s that merely passes extents onto another. * A base class for {@link Extent}s that merely passes extents onto another.
*/ */
public abstract class AbstractDelegateExtent implements Extent { public abstract class AbstractDelegateExtent implements LightingExtent {
private final Extent extent; private final Extent extent;
@ -53,6 +56,50 @@ public abstract class AbstractDelegateExtent implements Extent {
this.extent = extent; this.extent = extent;
} }
public int getSkyLight(int x, int y, int z) {
if (extent instanceof LightingExtent) {
return ((LightingExtent) extent).getSkyLight(x, y, z);
}
return 0;
}
public int getBlockLight(int x, int y, int z) {
if (extent instanceof LightingExtent) {
return ((LightingExtent) extent).getBlockLight(x, y, z);
}
return getBrightness(x, y, z);
}
public int getOpacity(int x, int y, int z) {
if (extent instanceof LightingExtent) {
return ((LightingExtent) extent).getOpacity(x, y, z);
}
BlockMaterial block = BundledBlockData.getInstance().getMaterialById(getLazyBlock(x, y, z).getId());
if (block == null) {
return 15;
}
return Math.min(15, block.getLightOpacity());
}
@Override
public int getLight(int x, int y, int z) {
if (extent instanceof LightingExtent) {
return ((LightingExtent) extent).getLight(x, y, z);
}
return 0;
}
public int getBrightness(int x, int y, int z) {
if (extent instanceof LightingExtent) {
return ((LightingExtent) extent).getBrightness(x, y, z);
}
BlockMaterial block = BundledBlockData.getInstance().getMaterialById(getLazyBlock(x, y, z).getId());
if (block == null) {
return 15;
}
return Math.min(15, block.getLightValue());
}
/** /**
* Get the extent. * Get the extent.
* *

View File

@ -23,18 +23,21 @@ import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
import com.boydti.fawe.object.clipboard.FaweClipboard; import com.boydti.fawe.object.clipboard.FaweClipboard;
import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard; import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockMaterial;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -48,7 +51,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
* Stores block data as a multi-dimensional array of {@link BaseBlock}s and * Stores block data as a multi-dimensional array of {@link BaseBlock}s and
* other data as lists or maps. * other data as lists or maps.
*/ */
public class BlockArrayClipboard implements Clipboard { public class BlockArrayClipboard implements Clipboard, LightingExtent {
private Region region; private Region region;
public FaweClipboard IMP; public FaweClipboard IMP;
@ -57,6 +60,7 @@ public class BlockArrayClipboard implements Clipboard {
private int my; private int my;
private int mz; private int mz;
private Vector origin; private Vector origin;
private Vector mutable = new Vector();
public BlockArrayClipboard(Region region) { public BlockArrayClipboard(Region region) {
checkNotNull(region); checkNotNull(region);
@ -227,4 +231,43 @@ public class BlockArrayClipboard implements Clipboard {
public static Class<?> inject() { public static Class<?> inject() {
return BlockArrayClipboard.class; return BlockArrayClipboard.class;
} }
@Override
public int getLight(int x, int y, int z) {
return getBlockLight(x, y, z);
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getBlockLight(int x, int y, int z) {
return getBrightness(x, y, z);
}
@Override
public int getOpacity(int x, int y, int z) {
mutable.x = x;
mutable.y = y;
mutable.z = z;
BlockMaterial block = BundledBlockData.getInstance().getMaterialById(getBlock(mutable).getId());
if (block == null) {
return 15;
}
return Math.min(15, block.getLightOpacity());
}
@Override
public int getBrightness(int x, int y, int z) {
mutable.x = x;
mutable.y = y;
mutable.z = z;
BlockMaterial block = BundledBlockData.getInstance().getMaterialById(getBlock(mutable).getId());
if (block == null) {
return 15;
}
return Math.min(15, block.getLightValue());
}
} }

View File

@ -19,11 +19,14 @@
package com.sk89q.worldedit.session; package com.sk89q.worldedit.session;
import com.boydti.fawe.util.MaskTraverser;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
@ -97,6 +100,14 @@ public class PasteBuilder {
} }
ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to); ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to);
copy.setTransform(transform); copy.setTransform(transform);
if (targetExtent instanceof EditSession) {
Mask sourceMask = ((EditSession) targetExtent).getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(extent);
copy.setSourceMask(sourceMask);
((EditSession) targetExtent).setSourceMask(null);
}
}
if (ignoreAirBlocks) { if (ignoreAirBlocks) {
copy.setSourceMask(new ExistingBlockMask(clipboard)); copy.setSourceMask(new ExistingBlockMask(clipboard));
} }