Better mask parsing + optimize mask union/intersect
This commit is contained in:
parent
ba62563b72
commit
f5f326bf89
@ -57,6 +57,7 @@ import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.entity.ExtentEntityCopy;
|
||||
import com.sk89q.worldedit.function.mask.BlockMask;
|
||||
import com.sk89q.worldedit.function.mask.FuzzyBlockMask;
|
||||
import com.sk89q.worldedit.function.mask.MaskUnion;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.mask.OffsetMask;
|
||||
import com.sk89q.worldedit.function.mask.SolidBlockMask;
|
||||
@ -408,7 +409,8 @@ public class Fawe {
|
||||
FuzzyBlockMask.inject(); // Optimizations
|
||||
OffsetMask.inject(); // Optimizations
|
||||
DefaultMaskParser.inject(); // Add new masks
|
||||
Masks.inject(); //
|
||||
Masks.inject(); // Optimizations
|
||||
MaskUnion.inject(); // Optimizations
|
||||
// Operations
|
||||
Operations.inject(); // Optimizations
|
||||
ForwardExtentCopy.inject(); // Fixes + optimizations
|
||||
|
@ -48,17 +48,18 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
public boolean getAngle(Vector vector) {
|
||||
int x = vector.getBlockX();
|
||||
int z = vector.getBlockZ();
|
||||
int o = getHighestTerrainBlock(x, z, 0, maxY);
|
||||
if (getHighestTerrainBlock(x - 1, z, o + min, o + max) != -1) {
|
||||
// int o = getHighestTerrainBlock(x, z, 0, maxY);
|
||||
int y = vector.getBlockY();
|
||||
if (getHighestTerrainBlock(x - 1, z, y + min, y + max) != -1) {
|
||||
return true;
|
||||
}
|
||||
if (getHighestTerrainBlock(x + 1, z, o + min, o + max) != -1) {
|
||||
if (getHighestTerrainBlock(x + 1, z, y + min, y + max) != -1) {
|
||||
return true;
|
||||
}
|
||||
if (getHighestTerrainBlock(x, z - 1, o + min, o + max) != -1) {
|
||||
if (getHighestTerrainBlock(x, z - 1, y + min, y + max) != -1) {
|
||||
return true;
|
||||
}
|
||||
if (getHighestTerrainBlock(x, z + 1, o + min, o + max) != -1) {
|
||||
if (getHighestTerrainBlock(x, z + 1, y + min, y + max) != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -70,22 +71,22 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
long pair = MathMan.pairInt(x, z);
|
||||
Integer height = heights.get(pair);
|
||||
if (height != null) {
|
||||
if (height >= minY && height <= maxY) {
|
||||
if (height >= minY && height <= maxY && height >= 0 && height <= this.maxY) {
|
||||
return height;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
maxY = Math.min(this.maxY, Math.max(0, maxY));
|
||||
minY = Math.max(0, minY);
|
||||
int maxSearchY = Math.min(this.maxY, Math.max(0, maxY));
|
||||
int minSearchY = Math.min(this.maxY, Math.max(0, minY));
|
||||
mutable.x = x;
|
||||
mutable.z = z;
|
||||
boolean air = false;
|
||||
if (maxY != this.maxY) {
|
||||
mutable.y = maxY + 1;
|
||||
if (maxSearchY != this.maxY) {
|
||||
mutable.y = maxSearchY + 1;
|
||||
air = !super.test(mutable);
|
||||
}
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
for (int y = maxSearchY; y >= minSearchY; --y) {
|
||||
mutable.y = y;
|
||||
if (super.test(mutable)) {
|
||||
if (!air) {
|
||||
@ -98,7 +99,7 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
air = true;
|
||||
}
|
||||
}
|
||||
if (minY == 0 && maxY == this.maxY) {
|
||||
if (minSearchY == 0 && maxSearchY == this.maxY) {
|
||||
heights.put(pair, -1);
|
||||
} else {
|
||||
int value = getHighestTerrainBlock(x, z, 0, this.maxY);
|
||||
|
@ -90,16 +90,35 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
List<Mask> masks = new ArrayList<Mask>();
|
||||
|
||||
for (String component : input.split(" ")) {
|
||||
for (String component : split(input, ' ')) {
|
||||
if (component.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Mask current = getBlockMaskComponent(masks, component, context);
|
||||
|
||||
masks.add(current);
|
||||
HashSet<BaseBlock> blocks = new HashSet<BaseBlock>();
|
||||
List<Mask> masksUnion = new ArrayList<Mask>();
|
||||
for (String elem : split(component, ',')) {
|
||||
ArrayList<Mask> list = new ArrayList<Mask>();
|
||||
list.add(catchSuggestion(input, list, elem, context));
|
||||
if (list.size() == 1) {
|
||||
Mask mask = list.get(0);
|
||||
if (mask.getClass() == BlockMask.class) {
|
||||
blocks.addAll(((BlockMask) mask).getBlocks());
|
||||
} else {
|
||||
masksUnion.add(mask);
|
||||
}
|
||||
} else {
|
||||
masksUnion.add(new MaskIntersection(list));
|
||||
}
|
||||
}
|
||||
if (!blocks.isEmpty()) {
|
||||
masksUnion.add(new BlockMask(Request.request().getExtent(), blocks));
|
||||
}
|
||||
if (masksUnion.size() == 1) {
|
||||
masks.add(masksUnion.get(0));
|
||||
} else {
|
||||
masks.add(new MaskUnion(masksUnion));
|
||||
}
|
||||
}
|
||||
|
||||
switch (masks.size()) {
|
||||
case 0:
|
||||
return null;
|
||||
@ -123,7 +142,6 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
|
||||
private Mask getBlockMaskComponent(List<Mask> masks, String input, ParserContext context) throws InputParseException {
|
||||
Extent extent = Request.request().getExtent();
|
||||
|
||||
final char firstChar = input.charAt(0);
|
||||
switch (firstChar) {
|
||||
case '#':
|
||||
@ -234,8 +252,8 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
|
||||
}
|
||||
try {
|
||||
int y1 = (int) Math.abs(Expression.compile(split[0]).evaluate());
|
||||
int y2 = (int) Math.abs(Expression.compile(split[1]).evaluate());
|
||||
int y1 = (int) (Expression.compile(split[0]).evaluate());
|
||||
int y2 = (int) (Expression.compile(split[1]).evaluate());
|
||||
return new AngleMask(extent, y1, y2);
|
||||
} catch (NumberFormatException | ExpressionException e) {
|
||||
throw new SuggestInputParseException(input, "/<min-angle>:<max-angle>");
|
||||
@ -338,35 +356,11 @@ public class DefaultMaskParser extends FaweParser<Mask> {
|
||||
}
|
||||
}
|
||||
}
|
||||
List<String> split = split(input, ',');
|
||||
if (split.size() == 1) {
|
||||
ParserContext tempContext = new ParserContext(context);
|
||||
tempContext.setRestricted(false);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Combines several masks and requires that all masks return true
|
||||
* when a certain position is tested. It serves as a logical AND operation
|
||||
* on a list of masks.
|
||||
*/
|
||||
public class MaskIntersection extends AbstractMask {
|
||||
|
||||
private final Set<Mask> masks = new HashSet<Mask>();
|
||||
private Mask[] masksArray;
|
||||
|
||||
/**
|
||||
* Create a new intersection.
|
||||
*
|
||||
* @param masks a list of masks
|
||||
*/
|
||||
public MaskIntersection(Collection<Mask> masks) {
|
||||
checkNotNull(masks);
|
||||
this.masks.addAll(masks);
|
||||
formArray();
|
||||
}
|
||||
|
||||
private void formArray() {
|
||||
if (masks.isEmpty()) {
|
||||
masksArray = new Mask[] {Masks.alwaysFalse()};
|
||||
} else {
|
||||
masksArray = masks.toArray(new Mask[masks.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new intersection.
|
||||
*
|
||||
* @param mask a list of masks
|
||||
*/
|
||||
public MaskIntersection(Mask... mask) {
|
||||
this(Arrays.asList(checkNotNull(mask)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some masks to the list.
|
||||
*
|
||||
* @param masks the masks
|
||||
*/
|
||||
public void add(Collection<Mask> masks) {
|
||||
checkNotNull(masks);
|
||||
this.masks.addAll(masks);
|
||||
formArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some masks to the list.
|
||||
*
|
||||
* @param mask the masks
|
||||
*/
|
||||
public void add(Mask... mask) {
|
||||
add(Arrays.asList(checkNotNull(mask)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the masks that are tested with.
|
||||
*
|
||||
* @return the masks
|
||||
*/
|
||||
public Collection<Mask> getMasks() {
|
||||
return masks;
|
||||
}
|
||||
|
||||
public Mask[] getMasksArray() {
|
||||
return masksArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
for (Mask mask : masksArray) {
|
||||
if (!mask.test(vector)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
List<Mask2D> mask2dList = new ArrayList<Mask2D>();
|
||||
for (Mask mask : masks) {
|
||||
Mask2D mask2d = mask.toMask2D();
|
||||
if (mask2d != null) {
|
||||
mask2dList.add(mask2d);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new MaskIntersection2D(mask2dList);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Combines several masks and requires that one or more masks return true
|
||||
* when a certain position is tested. It serves as a logical OR operation
|
||||
* on a list of masks.
|
||||
*/
|
||||
public class MaskUnion extends MaskIntersection {
|
||||
|
||||
/**
|
||||
* Create a new union.
|
||||
*
|
||||
* @param masks a list of masks
|
||||
*/
|
||||
public MaskUnion(Collection<Mask> masks) {
|
||||
super(masks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new union.
|
||||
*
|
||||
* @param mask a list of masks
|
||||
*/
|
||||
public MaskUnion(Mask... mask) {
|
||||
super(mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
for (Mask mask : getMasksArray()) {
|
||||
if (mask.test(vector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
List<Mask2D> mask2dList = new ArrayList<Mask2D>();
|
||||
for (Mask mask : getMasks()) {
|
||||
Mask2D mask2d = mask.toMask2D();
|
||||
if (mask2d != null) {
|
||||
mask2dList.add(mask2d);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new MaskUnion2D(mask2dList);
|
||||
}
|
||||
|
||||
public static Class<MaskUnion> inject() {
|
||||
return MaskUnion.class;
|
||||
}
|
||||
}
|
@ -31,6 +31,10 @@ public final class Masks {
|
||||
return ALWAYS_TRUE;
|
||||
}
|
||||
|
||||
public static Mask alwaysFalse() {
|
||||
return ALWAYS_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a 2D mask that always returns true;
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user