mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-06 20:56:41 +00:00
Copy paste/merge FAWE classes to this WorldEdit fork
- so certain people can look at the diff and complain about my sloppy code :( Signed-off-by: Jesse Boyd <jessepaleg@gmail.com>
This commit is contained in:
@ -19,22 +19,19 @@
|
||||
|
||||
package com.sk89q.worldedit.function;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Executes several region functions in order.
|
||||
*/
|
||||
public class CombinedRegionFunction implements RegionFunction {
|
||||
|
||||
private final List<RegionFunction> functions = new ArrayList<>();
|
||||
private RegionFunction[] functions;
|
||||
|
||||
/**
|
||||
* Create a combined region function.
|
||||
@ -49,7 +46,8 @@ public class CombinedRegionFunction implements RegionFunction {
|
||||
*/
|
||||
public CombinedRegionFunction(Collection<RegionFunction> functions) {
|
||||
checkNotNull(functions);
|
||||
this.functions.addAll(functions);
|
||||
this.functions = functions.toArray(new RegionFunction[functions.size()]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +56,21 @@ public class CombinedRegionFunction implements RegionFunction {
|
||||
* @param function an array of functions to match
|
||||
*/
|
||||
public CombinedRegionFunction(RegionFunction... function) {
|
||||
this(Arrays.asList(checkNotNull(function)));
|
||||
this.functions = function;
|
||||
}
|
||||
|
||||
public static CombinedRegionFunction combine(RegionFunction function, RegionFunction add) {
|
||||
CombinedRegionFunction combined;
|
||||
if (function instanceof CombinedRegionFunction) {
|
||||
combined = ((CombinedRegionFunction) function);
|
||||
combined.add(add);
|
||||
} else if (add instanceof CombinedRegionFunction) {
|
||||
combined = new CombinedRegionFunction(function);
|
||||
combined.add(((CombinedRegionFunction) add).functions);
|
||||
} else {
|
||||
combined = new CombinedRegionFunction(function, add);
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +80,9 @@ public class CombinedRegionFunction implements RegionFunction {
|
||||
*/
|
||||
public void add(Collection<RegionFunction> functions) {
|
||||
checkNotNull(functions);
|
||||
this.functions.addAll(functions);
|
||||
ArrayList<RegionFunction> functionsList = new ArrayList<>(Arrays.asList(this.functions));
|
||||
functionsList.addAll(functions);
|
||||
this.functions = functionsList.toArray(new RegionFunction[functionsList.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,4 +105,8 @@ public class CombinedRegionFunction implements RegionFunction {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public static Class<?> inject() {
|
||||
return CombinedRegionFunction.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.function;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class EditContext {
|
||||
|
||||
private Extent destination;
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Passes calls to {@link #apply(com.sk89q.worldedit.Vector2D)} to the
|
||||
* delegate {@link com.sk89q.worldedit.function.FlatRegionFunction} if they
|
||||
|
@ -19,12 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -37,7 +38,7 @@ public class GroundFunction implements LayerFunction {
|
||||
/**
|
||||
* Create a new ground function.
|
||||
*
|
||||
* @param mask a mask
|
||||
* @param mask a mask
|
||||
* @param function the function to apply
|
||||
*/
|
||||
public GroundFunction(Mask mask, RegionFunction function) {
|
||||
@ -87,7 +88,6 @@ public class GroundFunction implements LayerFunction {
|
||||
affected++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 com.sk89q.worldedit.regions.Region;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Passes calls to {@link #apply(com.sk89q.worldedit.Vector)} to the
|
||||
* delegate {@link com.sk89q.worldedit.function.RegionFunction} if they
|
||||
* match the given mask.
|
||||
*/
|
||||
public class RegionMaskTestFunction implements RegionFunction {
|
||||
|
||||
private final RegionFunction pass,fail;
|
||||
private Mask mask;
|
||||
|
||||
/**
|
||||
* Create a new masking filter.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
*/
|
||||
public RegionMaskTestFunction(Mask mask, RegionFunction success, RegionFunction failure) {
|
||||
checkNotNull(success);
|
||||
checkNotNull(failure);
|
||||
checkNotNull(mask);
|
||||
this.pass = success;
|
||||
this.fail = failure;
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
if (mask.test(position)) {
|
||||
return pass.apply(position);
|
||||
} else {
|
||||
return fail.apply(position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Passes calls to {@link #apply(com.sk89q.worldedit.Vector)} to the
|
||||
* delegate {@link com.sk89q.worldedit.function.RegionFunction} if they
|
||||
|
@ -19,14 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.function.biome;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
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.world.biome.BaseBiome;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Replaces the biome at the locations that this function is applied to.
|
||||
*/
|
||||
|
@ -19,14 +19,15 @@
|
||||
|
||||
package com.sk89q.worldedit.function.block;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Replaces blocks with a given pattern.
|
||||
*/
|
||||
@ -38,7 +39,7 @@ public class BlockReplace implements RegionFunction {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent an extent
|
||||
* @param extent an extent
|
||||
* @param pattern a pattern
|
||||
*/
|
||||
public BlockReplace(Extent extent, Pattern pattern) {
|
||||
@ -50,7 +51,11 @@ public class BlockReplace implements RegionFunction {
|
||||
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
return extent.setBlock(position, pattern.apply(position));
|
||||
return pattern.apply(extent, position, position);
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return BlockReplace.class;
|
||||
}
|
||||
|
||||
}
|
@ -19,19 +19,26 @@
|
||||
|
||||
package com.sk89q.worldedit.function.block;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompoundTagBuilder;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.internal.helper.MCDirections;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.Direction.Flag;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Copies blocks from one extent to another.
|
||||
@ -47,11 +54,11 @@ public class ExtentBlockCopy implements RegionFunction {
|
||||
/**
|
||||
* Make a new copy.
|
||||
*
|
||||
* @param source the source extent
|
||||
* @param from the source offset
|
||||
* @param source the source extent
|
||||
* @param from the source offset
|
||||
* @param destination the destination extent
|
||||
* @param to the destination offset
|
||||
* @param transform a transform to apply to positions (after source offset, before destination offset)
|
||||
* @param to the destination offset
|
||||
* @param transform a transform to apply to positions (after source offset, before destination offset)
|
||||
*/
|
||||
public ExtentBlockCopy(Extent source, Vector from, Extent destination, Vector to, Transform transform) {
|
||||
checkNotNull(source);
|
||||
@ -68,12 +75,11 @@ public class ExtentBlockCopy implements RegionFunction {
|
||||
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
BaseBlock block = source.getFullBlock(position);
|
||||
Vector orig = position.subtract(from);
|
||||
Vector transformed = transform.apply(orig);
|
||||
|
||||
// Apply transformations to NBT data if necessary
|
||||
block = transformNbtData(block);
|
||||
BlockStateHolder block = transformNbtData(source.getBlock(position));
|
||||
|
||||
return destination.setBlock(transformed.add(to), block);
|
||||
}
|
||||
@ -85,9 +91,8 @@ public class ExtentBlockCopy implements RegionFunction {
|
||||
* @param state the existing state
|
||||
* @return a new state or the existing one
|
||||
*/
|
||||
private BaseBlock transformNbtData(BaseBlock state) {
|
||||
private BlockState transformNbtData(BlockState state) {
|
||||
CompoundTag tag = state.getNbtData();
|
||||
|
||||
if (tag != null) {
|
||||
// Handle blocks which store their rotation in NBT
|
||||
if (tag.containsKey("Rot")) {
|
||||
@ -96,21 +101,26 @@ public class ExtentBlockCopy implements RegionFunction {
|
||||
Direction direction = MCDirections.fromRotation(rot);
|
||||
|
||||
if (direction != null) {
|
||||
Vector vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector.ZERO)).normalize();
|
||||
Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL | Flag.ORDINAL | Flag.SECONDARY_ORDINAL);
|
||||
Vector applyAbsolute = transform.apply(direction.toVector());
|
||||
Vector applyOrigin = transform.apply(Vector.ZERO);
|
||||
applyAbsolute.mutX(applyAbsolute.getX() - applyOrigin.getX());
|
||||
applyAbsolute.mutY(applyAbsolute.getY() - applyOrigin.getY());
|
||||
applyAbsolute.mutZ(applyAbsolute.getZ() - applyOrigin.getZ());
|
||||
|
||||
Direction newDirection = Direction.findClosest(applyAbsolute, Flag.CARDINAL | Flag.ORDINAL | Flag.SECONDARY_ORDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
CompoundTagBuilder builder = tag.createBuilder();
|
||||
|
||||
builder.putByte("Rot", (byte) MCDirections.toRotation(newDirection));
|
||||
|
||||
return state.toBaseBlock(builder.build());
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return ExtentBlockCopy.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,16 +19,19 @@
|
||||
|
||||
package com.sk89q.worldedit.function.block;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.mask.BlockTypeMask;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.function.LayerFunction;
|
||||
import com.sk89q.worldedit.function.mask.BlockMask;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Makes a layer of grass on top, three layers of dirt below, and smooth stone
|
||||
@ -49,11 +52,7 @@ public class Naturalizer implements LayerFunction {
|
||||
public Naturalizer(EditSession editSession) {
|
||||
checkNotNull(editSession);
|
||||
this.editSession = editSession;
|
||||
this.mask = new BlockMask(editSession, Sets.newHashSet(
|
||||
BlockTypes.GRASS_BLOCK.getDefaultState(),
|
||||
BlockTypes.DIRT.getDefaultState(),
|
||||
BlockTypes.STONE.getDefaultState()
|
||||
));
|
||||
this.mask = new BlockTypeMask(editSession, BlockTypes.GRASS, BlockTypes.DIRT, BlockTypes.STONE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,15 +75,15 @@ public class Naturalizer implements LayerFunction {
|
||||
affected++;
|
||||
switch (depth) {
|
||||
case 0:
|
||||
editSession.setBlock(position, BlockTypes.GRASS_BLOCK.getDefaultState());
|
||||
editSession.setBlock(position, BlockTypes.GRASS);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
editSession.setBlock(position, BlockTypes.DIRT.getDefaultState());
|
||||
editSession.setBlock(position, BlockTypes.DIRT);
|
||||
break;
|
||||
default:
|
||||
editSession.setBlock(position, BlockTypes.STONE.getDefaultState());
|
||||
editSession.setBlock(position, BlockTypes.STONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,10 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function.entity;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompoundTagBuilder;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
@ -34,6 +37,11 @@ import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.Direction.Flag;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Copies entities provided to the function to the provided destination
|
||||
@ -50,10 +58,10 @@ public class ExtentEntityCopy implements EntityFunction {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param from the from position
|
||||
* @param from the from position
|
||||
* @param destination the destination {@code Extent}
|
||||
* @param to the destination position
|
||||
* @param transform the transformation to apply to both position and orientation
|
||||
* @param to the destination position
|
||||
* @param transform the transformation to apply to both position and orientation
|
||||
*/
|
||||
public ExtentEntityCopy(Vector from, Extent destination, Vector to, Transform transform) {
|
||||
checkNotNull(from);
|
||||
@ -94,19 +102,19 @@ public class ExtentEntityCopy implements EntityFunction {
|
||||
Vector pivot = from.round().add(0.5, 0.5, 0.5);
|
||||
Vector newPosition = transform.apply(location.toVector().subtract(pivot));
|
||||
Vector newDirection;
|
||||
|
||||
newDirection = transform.isIdentity() ?
|
||||
entity.getLocation().getDirection()
|
||||
: transform.apply(location.getDirection()).subtract(transform.apply(Vector.ZERO)).normalize();
|
||||
newLocation = new Location(destination, newPosition.add(to.round().add(0.5, 0.5, 0.5)), newDirection);
|
||||
|
||||
// Some entities store their position data in NBT
|
||||
state = transformNbtData(state);
|
||||
if (transform.isIdentity()) {
|
||||
newDirection = entity.getLocation().getDirection();
|
||||
newLocation = new Location(destination, newPosition.add(to.round().add(0.5, 0.5, 0.5)), newDirection);
|
||||
} else {
|
||||
newDirection = new Vector(transform.apply(location.getDirection())).subtract(transform.apply(Vector.ZERO)).normalize();
|
||||
newLocation = new Location(destination, newPosition.add(to.round().add(0.5, 0.5, 0.5)), newDirection);
|
||||
state = transformNbtData(state);
|
||||
}
|
||||
|
||||
boolean success = destination.createEntity(newLocation, state) != null;
|
||||
|
||||
// Remove
|
||||
if (isRemoving() && success) {
|
||||
if (isRemoving()) {
|
||||
entity.remove();
|
||||
}
|
||||
|
||||
@ -125,22 +133,27 @@ public class ExtentEntityCopy implements EntityFunction {
|
||||
*/
|
||||
private BaseEntity transformNbtData(BaseEntity state) {
|
||||
CompoundTag tag = state.getNbtData();
|
||||
|
||||
if (tag != null) {
|
||||
boolean changed = false;
|
||||
// Handle hanging entities (paintings, item frames, etc.)
|
||||
|
||||
tag = tag.createBuilder().build();
|
||||
|
||||
Map<String, Tag> values = ReflectionUtils.getMap(tag.getValue());
|
||||
|
||||
boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ");
|
||||
boolean hasDirection = tag.containsKey("Direction");
|
||||
boolean hasLegacyDirection = tag.containsKey("Dir");
|
||||
boolean hasFacing = tag.containsKey("Facing");
|
||||
|
||||
if (hasTilePosition) {
|
||||
changed = true;
|
||||
Vector tilePosition = new Vector(tag.asInt("TileX"), tag.asInt("TileY"), tag.asInt("TileZ"));
|
||||
Vector newTilePosition = transform.apply(tilePosition.subtract(from)).add(to);
|
||||
|
||||
CompoundTagBuilder builder = tag.createBuilder()
|
||||
.putInt("TileX", newTilePosition.getBlockX())
|
||||
.putInt("TileY", newTilePosition.getBlockY())
|
||||
.putInt("TileZ", newTilePosition.getBlockZ());
|
||||
values.put("TileX", new IntTag(newTilePosition.getBlockX()));
|
||||
values.put("TileY", new IntTag(newTilePosition.getBlockY()));
|
||||
values.put("TileZ", new IntTag(newTilePosition.getBlockZ()));
|
||||
|
||||
if (hasDirection || hasLegacyDirection || hasFacing) {
|
||||
int d;
|
||||
@ -160,18 +173,38 @@ public class ExtentEntityCopy implements EntityFunction {
|
||||
|
||||
if (newDirection != null) {
|
||||
byte hangingByte = (byte) MCDirections.toHanging(newDirection);
|
||||
builder.putByte("Direction", hangingByte);
|
||||
builder.putByte("Facing", hangingByte);
|
||||
builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection)));
|
||||
values.put("Direction", new ByteTag(hangingByte));
|
||||
values.put("Facing", new ByteTag(hangingByte));
|
||||
values.put("Dir", new ByteTag(MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new BaseEntity(state.getType(), builder.build());
|
||||
ListTag rotation = tag.getListTag("Rotation");
|
||||
if (rotation != null && rotation.getValue().size() >= 2) {
|
||||
changed = true;
|
||||
double yaw = Math.toRadians(rotation.getFloat(0));
|
||||
double pitch = Math.toRadians(rotation.getFloat(1));
|
||||
|
||||
double xz = Math.cos(pitch);
|
||||
Vector direction = new Vector(-xz * Math.sin(yaw), -Math.sin(pitch), xz * Math.cos(yaw));
|
||||
direction = transform.apply(direction);
|
||||
FloatTag yawTag = new FloatTag(direction.toYaw());
|
||||
FloatTag pitchTag = new FloatTag(direction.toPitch());
|
||||
values.put("Rotation", new ListTag(FloatTag.class, Arrays.asList(yawTag, pitchTag)));
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
return new BaseEntity(state.getType(), tag);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return ExtentEntityCopy.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,9 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.factory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
|
||||
|
||||
import com.sk89q.worldedit.function.Contextual;
|
||||
import com.sk89q.worldedit.function.EditContext;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
@ -30,6 +27,9 @@ import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.regions.NullRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
|
||||
|
||||
public class Apply implements Contextual<Operation> {
|
||||
|
||||
private final Region region;
|
||||
|
@ -19,9 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.factory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
@ -37,6 +34,9 @@ import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
|
||||
|
||||
public class Deform implements Contextual<Operation> {
|
||||
|
||||
private Extent destination;
|
||||
|
@ -19,12 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.factory;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
|
||||
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
|
||||
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
|
||||
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.NullExtent;
|
||||
import com.sk89q.worldedit.function.Contextual;
|
||||
@ -39,6 +33,10 @@ import com.sk89q.worldedit.math.noise.RandomNoise;
|
||||
import com.sk89q.worldedit.regions.NullRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.regions.Regions.*;
|
||||
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
|
||||
|
||||
public class Paint implements Contextual<Operation> {
|
||||
|
||||
private final Extent destination;
|
||||
|
@ -22,12 +22,12 @@ package com.sk89q.worldedit.function.generator;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
/**
|
||||
* Generates flora (which may include tall grass, flowers, etc.).
|
||||
@ -106,7 +106,7 @@ public class FloraGenerator implements RegionFunction {
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
BlockStateHolder block = editSession.getBlock(position);
|
||||
|
||||
if (block.getBlockType() == BlockTypes.GRASS_BLOCK) {
|
||||
if (block.getBlockType() == BlockTypes.GRASS) {
|
||||
editSession.setBlock(position.add(0, 1, 0), temperatePattern.apply(position));
|
||||
return true;
|
||||
} else if (block.getBlockType() == BlockTypes.SAND) {
|
||||
|
@ -22,11 +22,11 @@ package com.sk89q.worldedit.function.generator;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
|
||||
/**
|
||||
* Generates forests by searching for the ground starting from the given upper Y
|
||||
@ -53,10 +53,10 @@ public class ForestGenerator implements RegionFunction {
|
||||
BlockStateHolder block = editSession.getBlock(position);
|
||||
BlockType t = block.getBlockType();
|
||||
|
||||
if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT) {
|
||||
if (t == BlockTypes.GRASS || t == BlockTypes.DIRT) {
|
||||
treeType.generate(editSession, position.add(0, 1, 0));
|
||||
return true;
|
||||
} else if (t == BlockTypes.GRASS || t == BlockTypes.DEAD_BUSH || t == BlockTypes.POPPY || t == BlockTypes.DANDELION) { // TODO: This list needs to be moved
|
||||
} else if (t == BlockTypes.TALL_GRASS || t == BlockTypes.DEAD_BUSH || t == BlockTypes.POPPY || t == BlockTypes.DANDELION) { // TODO: This list needs to be moved
|
||||
editSession.setBlock(position, BlockTypes.AIR.getDefaultState());
|
||||
treeType.generate(editSession, position);
|
||||
return true;
|
||||
|
@ -26,8 +26,8 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.Random;
|
||||
@ -104,7 +104,7 @@ public class GardenPatchGenerator implements RegionFunction {
|
||||
int h = random.nextInt(3) - 1;
|
||||
Vector p;
|
||||
|
||||
BlockState log = BlockTypes.OAK_LOG.getDefaultState();
|
||||
BlockStateHolder log = BlockTypes.OAK_LOG.getDefaultState();
|
||||
|
||||
switch (t) {
|
||||
case 0:
|
||||
@ -163,11 +163,11 @@ public class GardenPatchGenerator implements RegionFunction {
|
||||
position = position.add(0, 1, 0);
|
||||
}
|
||||
|
||||
if (editSession.getBlock(position.add(0, -1, 0)).getBlockType() != BlockTypes.GRASS_BLOCK) {
|
||||
if (editSession.getBlock(position.add(0, -1, 0)).getBlockType() != BlockTypes.GRASS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState();
|
||||
BlockStateHolder leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState();
|
||||
|
||||
if (editSession.getBlock(position).getBlockType() == BlockTypes.AIR) {
|
||||
editSession.setBlock(position, leavesBlock);
|
||||
@ -187,7 +187,7 @@ public class GardenPatchGenerator implements RegionFunction {
|
||||
* @return a pumpkin pattern
|
||||
*/
|
||||
public static Pattern getPumpkinPattern() {
|
||||
return new BlockPattern(BlockTypes.PUMPKIN.getDefaultState());
|
||||
return new BlockPattern(BlockTypes.CARVED_PUMPKIN.getDefaultState());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,61 +1,25 @@
|
||||
/*
|
||||
* 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 static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
/**
|
||||
* An abstract implementation of {@link Mask} that takes uses an {@link Extent}.
|
||||
*/
|
||||
public abstract class AbstractExtentMask extends AbstractMask {
|
||||
private transient Extent extent;
|
||||
|
||||
private Extent extent;
|
||||
|
||||
/**
|
||||
* Construct a new mask.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
protected AbstractExtentMask(Extent extent) {
|
||||
setExtent(extent);
|
||||
this.setExtent(extent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extent.
|
||||
*
|
||||
* @return the extent
|
||||
*/
|
||||
public Extent getExtent() {
|
||||
return extent;
|
||||
return this.extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extent.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public void setExtent(Extent extent) {
|
||||
checkNotNull(extent);
|
||||
Preconditions.checkNotNull(extent);
|
||||
this.extent = extent;
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return AbstractExtentMask.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A base class of {@link Mask} that all masks should inherit from.
|
||||
*/
|
||||
public abstract class AbstractMask implements Mask {
|
||||
public abstract class AbstractMask implements Mask, Serializable {
|
||||
public static Class<?> inject() {
|
||||
return AbstractMask.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
@ -30,6 +28,8 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Tests true if the biome at applied points is the same as the one given.
|
||||
*/
|
||||
|
@ -1,108 +1,193 @@
|
||||
/*
|
||||
* 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 static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.collection.FastBitSet;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.registry.state.AbstractProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A mask that checks whether blocks at the given positions are matched by
|
||||
* a block in a list.
|
||||
*
|
||||
* <p>
|
||||
* <p>This mask checks for both an exact block ID and data value match, as well
|
||||
* for a block with the same ID but a data value of -1.</p>
|
||||
*/
|
||||
public class BlockMask extends AbstractExtentMask {
|
||||
|
||||
private final Set<BlockStateHolder> blocks = new HashSet<>();
|
||||
private final long[][] bitSets;
|
||||
protected final static long[] ALL = new long[0];
|
||||
|
||||
/**
|
||||
* Create a new block mask.
|
||||
*
|
||||
* @param extent the extent
|
||||
* @param blocks a list of blocks to match
|
||||
*/
|
||||
public BlockMask(Extent extent, Collection<BlockStateHolder> blocks) {
|
||||
@Deprecated
|
||||
public BlockMask(Extent extent, BaseBlock... blocks) {
|
||||
super(extent);
|
||||
checkNotNull(blocks);
|
||||
this.blocks.addAll(blocks);
|
||||
MainUtil.warnDeprecated(BlockMaskBuilder.class);
|
||||
this.bitSets = new BlockMaskBuilder().addBlocks(blocks).optimize().getBits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new block mask.
|
||||
*
|
||||
* @param extent the extent
|
||||
* @param block an array of blocks to match
|
||||
*/
|
||||
public BlockMask(Extent extent, BlockStateHolder... block) {
|
||||
this(extent, Arrays.asList(checkNotNull(block)));
|
||||
protected BlockMask(Extent extent, long[][] bitSets) {
|
||||
super(extent);
|
||||
this.bitSets = bitSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given blocks to the list of criteria.
|
||||
*
|
||||
* @param blocks a list of blocks
|
||||
*/
|
||||
public void add(Collection<BlockStateHolder> blocks) {
|
||||
checkNotNull(blocks);
|
||||
this.blocks.addAll(blocks);
|
||||
@Override
|
||||
public Mask optimize() {
|
||||
Map<Object, Integer> states = new HashMap<>();
|
||||
int indexFound = -1;
|
||||
{
|
||||
int indexNull = -1;
|
||||
int indexAll = -1;
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
long[] bs = bitSets[i];
|
||||
if (bs == null) {
|
||||
indexNull = i;
|
||||
states.put(null, states.getOrDefault(null, 0) + 1);
|
||||
} else if (bs.length == 0) {
|
||||
indexAll = i;
|
||||
states.put(ALL, states.getOrDefault(ALL, 0) + 1);
|
||||
} else if (indexFound == -1) {
|
||||
indexFound = i;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
// Only types, no states
|
||||
if (indexFound == -1) {
|
||||
if (states.size() == 1) {
|
||||
return states.keySet().iterator().next() == null ? Masks.alwaysFalse() : Masks.alwaysTrue();
|
||||
}
|
||||
if (states.get(ALL) == 1) return new SingleBlockTypeMask(getExtent(), BlockTypes.get(indexAll));
|
||||
if (states.get(null) == 1)
|
||||
return new SingleBlockTypeMask(getExtent(), BlockTypes.get(indexNull)).inverse();
|
||||
|
||||
boolean[] types = new boolean[BlockTypes.size()];
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
if (bitSets[i].length == 0) types[i] = true;
|
||||
}
|
||||
return new BlockTypeMask(getExtent(), types);
|
||||
}
|
||||
}
|
||||
BlockType type = BlockTypes.get(indexFound);
|
||||
{
|
||||
Mask mask = getOptimizedMask(type, bitSets[indexFound]);
|
||||
if (mask == null) { // Try with inverse
|
||||
long[] newBitSet = bitSets[indexFound];
|
||||
for (int i = 0; i < newBitSet.length; i++) newBitSet[i] = ~newBitSet[i];
|
||||
mask = getOptimizedMask(type, bitSets[indexFound]);
|
||||
if (mask != null) mask = mask.inverse();
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given blocks to the list of criteria.
|
||||
*
|
||||
* @param block an array of blocks
|
||||
*/
|
||||
public void add(BlockStateHolder... block) {
|
||||
add(Arrays.asList(checkNotNull(block)));
|
||||
private Mask getOptimizedMask(BlockType type, long[] bitSet) {
|
||||
boolean single = true;
|
||||
int and = type.getInternalId();
|
||||
List<? extends Property> properties = type.getProperties();
|
||||
for (AbstractProperty prop : (List<AbstractProperty>) type.getProperties()) {
|
||||
List values = prop.getValues();
|
||||
int numSet = 0;
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
int localI = i << prop.getBitOffset();
|
||||
if (FastBitSet.get(bitSet, localI)) {
|
||||
numSet++;
|
||||
and |= prop.modify(and, i);
|
||||
}
|
||||
}
|
||||
// Cannot optimize multiple property values - use current mask (null)
|
||||
if (numSet != values.size() && numSet != 1) {
|
||||
return null;
|
||||
}
|
||||
single = single && numSet == 1;
|
||||
}
|
||||
if (single)
|
||||
return new SingleBlockStateMask(getExtent(), BlockState.get(and));
|
||||
return new SingleBlockStateBitMask(getExtent(), and);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of blocks that are tested with.
|
||||
*
|
||||
* @return a list of blocks
|
||||
*/
|
||||
public Collection<BlockStateHolder> getBlocks() {
|
||||
return blocks;
|
||||
@Override
|
||||
public Mask and(Mask other) {
|
||||
if (other instanceof BlockMask) {
|
||||
long[][] otherBitSets = ((BlockMask) other).bitSets;
|
||||
for (int i = 0; i < otherBitSets.length; i++) {
|
||||
long[] otherBitSet = otherBitSets[i];
|
||||
long[] bitSet = bitSets[i];
|
||||
if (otherBitSet == null) bitSets[i] = null;
|
||||
else if (otherBitSet.length == 0) continue;
|
||||
else if (bitSet == null) continue;
|
||||
else if (bitSet.length == 0) bitSets[i] = otherBitSet;
|
||||
else for (int j = 0; j < otherBitSet.length; j++) bitSet[j] &= otherBitSet[j];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
if (other instanceof SingleBlockStateMask) {
|
||||
return new BlockMaskBuilder(bitSets).filter(((SingleBlockStateMask) other).getBlockState()).build(getExtent());
|
||||
}
|
||||
if (other instanceof SingleBlockTypeMask) {
|
||||
return new BlockMaskBuilder(bitSets).filter(((SingleBlockTypeMask) other).getBlockType()).build(getExtent());
|
||||
}
|
||||
// TODO FIXME BlockTypeMask
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask or(Mask other) {
|
||||
if (other instanceof BlockMask) {
|
||||
long[][] otherBitSets = ((BlockMask) other).bitSets;
|
||||
for (int i = 0; i < otherBitSets.length; i++) {
|
||||
long[] otherBitSet = otherBitSets[i];
|
||||
long[] bitSet = bitSets[i];
|
||||
if (otherBitSet == null) continue;
|
||||
else if (otherBitSet.length == 0) bitSets[i] = ALL;
|
||||
else if (bitSet == null) bitSets[i] = otherBitSet;
|
||||
else if (bitSet.length == 0) continue;
|
||||
else for (int j = 0; j < otherBitSet.length; j++) bitSet[j] |= otherBitSet[j];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
if (other instanceof SingleBlockStateMask) {
|
||||
return new BlockMaskBuilder(bitSets).add(((SingleBlockStateMask) other).getBlockState()).build(getExtent());
|
||||
}
|
||||
if (other instanceof SingleBlockTypeMask) {
|
||||
return new BlockMaskBuilder(bitSets).add(((SingleBlockTypeMask) other).getBlockType()).build(getExtent());
|
||||
}
|
||||
// TODO FIXME BlockTypeMask
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask inverse() {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
if (bitSets[i] == null) bitSets[i] = ALL;
|
||||
else if (bitSets[i] == ALL) bitSets[i] = null;
|
||||
else {
|
||||
for (int j = 0; j < bitSets[i].length; j++)
|
||||
bitSets[i][j] = ~bitSets[i][j];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
BlockStateHolder block = getExtent().getBlock(vector);
|
||||
for (BlockStateHolder testBlock : blocks) {
|
||||
if (testBlock.equalsFuzzy(block)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
long[] bitSet = bitSets[block.getInternalBlockTypeId()];
|
||||
if (bitSet == null) return false;
|
||||
if (bitSet.length == 0) return true;
|
||||
return FastBitSet.get(bitSet, block.getInternalPropertiesId());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -111,4 +196,7 @@ public class BlockMask extends AbstractExtentMask {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
public static Class<?> inject() {
|
||||
return BlockMask.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,490 @@
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.boydti.fawe.object.collection.FastBitSet;
|
||||
import com.boydti.fawe.object.string.MutableCharSequence;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.registry.state.AbstractProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.registry.state.PropertyKey;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class BlockMaskBuilder {
|
||||
private static final Operator GREATER = (a, b) -> a > b;
|
||||
private static final Operator LESS = (a, b) -> a < b;
|
||||
private static final Operator EQUAL = (a, b) -> a == b;
|
||||
private static final Operator EQUAL_OR_NULL = (a, b) -> a == b;
|
||||
private static final Operator GREATER_EQUAL = (a, b) -> a >= b;
|
||||
private static final Operator LESS_EQUAL = (a, b) -> a <= b;
|
||||
private static final Operator NOT = (a, b) -> a != b;
|
||||
|
||||
private interface Operator {
|
||||
boolean test(int left, int right);
|
||||
}
|
||||
|
||||
public BlockMaskBuilder filterRegex(BlockType blockType, PropertyKey key, String regex) {
|
||||
Property property = blockType.getProperty(key);
|
||||
if (property == null) return this;
|
||||
List values = property.getValues();
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
Object value = values.get(i);
|
||||
if (!value.toString().matches(regex)) {
|
||||
filter(blockType, property, i);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void filterOperator(BlockType blockType, PropertyKey key, Operator operator, CharSequence value) {
|
||||
Property property = blockType.getProperty(key);
|
||||
if (property == null) return;
|
||||
int index = property.getIndexFor(value);
|
||||
List values = property.getValues();
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
if (!operator.test(index, i)) {
|
||||
filter(blockType, property, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void filterRegexOrOperator(BlockType type, PropertyKey key, Operator operator, CharSequence value) {
|
||||
if (!type.hasProperty(key)) {
|
||||
if (operator == EQUAL) remove(type);
|
||||
} else if (value.length() == 0) {
|
||||
|
||||
} else if ((operator == EQUAL || operator == EQUAL_OR_NULL) && !StringMan.isAlphanumericUnd(value)) {
|
||||
filterRegex(type, key, value.toString());
|
||||
} else {
|
||||
filterOperator(type, key, operator, value);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addRegex(String input) {
|
||||
if (input.charAt(input.length() - 1) == ']') {
|
||||
int propStart = StringMan.findMatchingBracket(input, input.length() - 1);
|
||||
if (propStart == -1) return this;
|
||||
|
||||
MutableCharSequence charSequence = MutableCharSequence.getTemporal();
|
||||
charSequence.setString(input);
|
||||
charSequence.setSubstring(0, propStart);
|
||||
|
||||
BlockTypes type = null;
|
||||
List<BlockTypes> blockTypeList = null;
|
||||
if (StringMan.isAlphanumericUnd(charSequence)) {
|
||||
type = BlockTypes.get(charSequence);
|
||||
add(type);
|
||||
} else {
|
||||
String regex = charSequence.toString();
|
||||
blockTypeList = new ArrayList<>();
|
||||
for (BlockTypes myType : BlockTypes.values) {
|
||||
if (myType.getId().matches(regex)) {
|
||||
blockTypeList.add(myType);
|
||||
add(myType);
|
||||
}
|
||||
}
|
||||
if (blockTypeList.size() == 1) type = blockTypeList.get(0);
|
||||
}
|
||||
|
||||
PropertyKey key = null;
|
||||
int length = input.length();
|
||||
int last = propStart + 1;
|
||||
Operator operator = null;
|
||||
for (int i = last; i < length; i++) {
|
||||
char c = input.charAt(i);
|
||||
switch (c) {
|
||||
case '[':
|
||||
case '{':
|
||||
case '(':
|
||||
int next = StringMan.findMatchingBracket(input, i);
|
||||
if (next != -1) i = next;
|
||||
break;
|
||||
case ']':
|
||||
case ',': {
|
||||
charSequence.setSubstring(last, i);
|
||||
char firstChar = input.charAt(last + 1);
|
||||
if (type != null) filterRegexOrOperator(type, key, operator, charSequence);
|
||||
else {
|
||||
for (BlockTypes myType : blockTypeList) {
|
||||
filterRegexOrOperator(myType, key, operator, charSequence);
|
||||
}
|
||||
}
|
||||
last = i + 1;
|
||||
break;
|
||||
}
|
||||
case '~':
|
||||
case '!':
|
||||
case '=':
|
||||
case '<':
|
||||
case '>': {
|
||||
charSequence.setSubstring(last, i);
|
||||
boolean extra = input.charAt(i + 1) == '=';
|
||||
if (extra) i++;
|
||||
switch (c) {
|
||||
case '~':
|
||||
operator = EQUAL_OR_NULL;
|
||||
break;
|
||||
case '!':
|
||||
operator = NOT;
|
||||
break;
|
||||
case '=':
|
||||
operator = EQUAL;
|
||||
break;
|
||||
case '<':
|
||||
operator = extra ? LESS_EQUAL : LESS;
|
||||
break;
|
||||
case '>':
|
||||
operator = extra ? GREATER_EQUAL : GREATER;
|
||||
break;
|
||||
}
|
||||
if (charSequence.length() > 0) key = PropertyKey.get(charSequence);
|
||||
last = i + 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (StringMan.isAlphanumericUnd(input)) {
|
||||
add(BlockTypes.get(input));
|
||||
} else {
|
||||
for (BlockTypes myType : BlockTypes.values) {
|
||||
if (myType.getId().matches(input)) {
|
||||
add(myType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
///// end test /////
|
||||
|
||||
private long[][] bitSets;
|
||||
|
||||
private boolean optimizedStates = true;
|
||||
|
||||
public boolean isEmpty() {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
if (bitSets[i] != null) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder() {
|
||||
this(new long[BlockTypes.size()][]);
|
||||
}
|
||||
|
||||
protected BlockMaskBuilder(long[][] bitSets) {
|
||||
this.bitSets = bitSets;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder parse(String input) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addAll() {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
bitSets[i] = BlockMask.ALL;
|
||||
}
|
||||
optimizedStates = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder clear() {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
bitSets[i] = null;
|
||||
}
|
||||
optimizedStates = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder remove(BlockType type) {
|
||||
bitSets[type.getInternalId()] = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder remove(BlockStateHolder state) {
|
||||
BlockType type = state.getBlockType();
|
||||
int i = type.getInternalId();
|
||||
long[] states = bitSets[i];
|
||||
if (states != null) {
|
||||
if (states == BlockMask.ALL) {
|
||||
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
Arrays.fill(states, -1);
|
||||
}
|
||||
int stateId = state.getInternalPropertiesId();
|
||||
FastBitSet.clear(states, stateId);
|
||||
optimizedStates = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder filter(BlockType type) {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
if (i != type.getInternalId()) bitSets[i] = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder filter(BlockStateHolder state) {
|
||||
filter(state.getBlockType());
|
||||
BlockType type = state.getBlockType();
|
||||
int i = type.getInternalId();
|
||||
long[] states = bitSets[i];
|
||||
if (states != null) {
|
||||
int stateId = state.getInternalPropertiesId();
|
||||
boolean set = true;
|
||||
if (states == BlockMask.ALL) {
|
||||
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
} else {
|
||||
set = FastBitSet.get(states, stateId);
|
||||
Arrays.fill(states, 0);
|
||||
}
|
||||
if (set)
|
||||
FastBitSet.set(states, stateId);
|
||||
else
|
||||
bitSets[i] = null;
|
||||
optimizedStates = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder filter(Predicate<BlockType> allow) {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
BlockType type = BlockTypes.get(i);
|
||||
if (!allow.test(type)) {
|
||||
bitSets[i] = null;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> BlockMaskBuilder filter(Predicate<BlockType> typePredicate, BiPredicate<BlockType, Map.Entry<Property<T>, T>> allowed) {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
long[] states = bitSets[i];
|
||||
if (states == null) continue;
|
||||
BlockType type = BlockTypes.get(i);
|
||||
if (!typePredicate.test(type)) {
|
||||
bitSets[i] = null;
|
||||
continue;
|
||||
}
|
||||
List<AbstractProperty> properties = (List<AbstractProperty>) type.getProperties();
|
||||
for (AbstractProperty prop : properties) {
|
||||
List values = prop.getValues();
|
||||
for (int j = 0; j < values.size(); j++) {
|
||||
int localI = j << prop.getBitOffset() >> BlockTypes.BIT_OFFSET;
|
||||
if (states == BlockMask.ALL || FastBitSet.get(states, localI)) {
|
||||
if (!allowed.test(type, new AbstractMap.SimpleEntry(prop, values.get(j)))) {
|
||||
if (states == BlockMask.ALL) {
|
||||
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
FastBitSet.setAll(states);
|
||||
}
|
||||
FastBitSet.clear(states, localI);
|
||||
optimizedStates = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder add(BlockType type) {
|
||||
bitSets[type.getInternalId()] = BlockMask.ALL;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder add(BlockStateHolder state) {
|
||||
BlockType type = state.getBlockType();
|
||||
int i = type.getInternalId();
|
||||
long[] states = bitSets[i];
|
||||
if (states != BlockMask.ALL) {
|
||||
if (states == null) {
|
||||
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
}
|
||||
int stateId = state.getInternalPropertiesId();
|
||||
FastBitSet.set(states, stateId);
|
||||
optimizedStates = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addBlocks(Collection<BlockStateHolder> blocks) {
|
||||
for (BlockStateHolder block : blocks) add(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addTypes(Collection<BlockType> blocks) {
|
||||
for (BlockType block : blocks) add(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addBlocks(BlockStateHolder... blocks) {
|
||||
for (BlockStateHolder block : blocks) add(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addTypes(BlockType... blocks) {
|
||||
for (BlockType block : blocks) add(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addAll(Predicate<BlockType> allow) {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
BlockType type = BlockTypes.get(i);
|
||||
if (allow.test(type)) {
|
||||
bitSets[i] = BlockMask.ALL;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder addAll(Predicate<BlockType> typePredicate, BiPredicate<BlockType, Map.Entry<Property<?>, ?>> propPredicate) {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
long[] states = bitSets[i];
|
||||
if (states == BlockMask.ALL) continue;
|
||||
BlockType type = BlockTypes.get(i);
|
||||
if (!typePredicate.test(type)) {
|
||||
continue;
|
||||
}
|
||||
for (AbstractProperty prop : (List<AbstractProperty>) type.getProperties()) {
|
||||
List values = prop.getValues();
|
||||
for (int j = 0; j < values.size(); j++) {
|
||||
int localI = j << prop.getBitOffset() >> BlockTypes.BIT_OFFSET;
|
||||
if (states == null || !FastBitSet.get(states, localI)) {
|
||||
if (propPredicate.test(type, new AbstractMap.SimpleEntry(prop, values.get(j)))) {
|
||||
if (states == null) {
|
||||
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
}
|
||||
FastBitSet.set(states, localI);
|
||||
optimizedStates = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder add(BlockType type, Property property, int index) {
|
||||
AbstractProperty prop = (AbstractProperty) property;
|
||||
long[] states = bitSets[type.getInternalId()];
|
||||
if (states == BlockMask.ALL) return this;
|
||||
|
||||
List values = property.getValues();
|
||||
int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET;
|
||||
if (states == null || !FastBitSet.get(states, localI)) {
|
||||
if (states == null) {
|
||||
bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
}
|
||||
set(type, states, property, index);
|
||||
optimizedStates = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMaskBuilder filter(BlockType type, Property property, int index) {
|
||||
AbstractProperty prop = (AbstractProperty) property;
|
||||
long[] states = bitSets[type.getInternalId()];
|
||||
if (states == null) return this;
|
||||
List values = property.getValues();
|
||||
int localI = index << prop.getBitOffset() >> BlockTypes.BIT_OFFSET;
|
||||
if (states == BlockMask.ALL || FastBitSet.get(states, localI)) {
|
||||
if (states == BlockMask.ALL) {
|
||||
bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1);
|
||||
FastBitSet.setAll(states);
|
||||
}
|
||||
clear(type, states, property, index);
|
||||
optimizedStates = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void applyRecursive(List<Property> properties, int propertiesIndex, int state, long[] states, boolean set) {
|
||||
AbstractProperty current = (AbstractProperty) properties.get(propertiesIndex);
|
||||
List values = current.getValues();
|
||||
if (propertiesIndex + 1 < properties.size()) {
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
int newState = current.modifyIndex(state, i);
|
||||
applyRecursive(properties, propertiesIndex + 1, newState, states, set);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
int index = current.modifyIndex(state, i) >> BlockTypes.BIT_OFFSET;
|
||||
if (set) FastBitSet.set(states, index);
|
||||
else FastBitSet.clear(states, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void set(BlockType type, long[] bitSet, Property property, int index) {
|
||||
FastBitSet.set(bitSet, index);
|
||||
if (type.getProperties().size() > 1) {
|
||||
ArrayList<Property> properties = new ArrayList<>(type.getProperties());
|
||||
properties.remove(property);
|
||||
int state = ((AbstractProperty) property).modifyIndex(type.getInternalId(), index);
|
||||
applyRecursive(properties, 0, state, bitSet, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void clear(BlockType type, long[] bitSet, Property property, int index) {
|
||||
FastBitSet.clear(bitSet, index);
|
||||
if (type.getProperties().size() > 1) {
|
||||
ArrayList<Property> properties = new ArrayList<>(type.getProperties());
|
||||
properties.remove(property);
|
||||
int state = ((AbstractProperty) property).modifyIndex(type.getInternalId(), index);
|
||||
applyRecursive(properties, 0, state, bitSet, false);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockMaskBuilder optimize() {
|
||||
if (!optimizedStates) {
|
||||
for (int i = 0; i < bitSets.length; i++) {
|
||||
long[] bitSet = bitSets[i];
|
||||
if (bitSet == null || bitSet == BlockMask.ALL) continue;
|
||||
BlockType type = BlockTypes.get(i);
|
||||
int maxStateId = type.getMaxStateId();
|
||||
if (maxStateId == 0) {
|
||||
if (bitSet[0] == 0) {
|
||||
bitSets[i] = null;
|
||||
continue;
|
||||
} else {
|
||||
bitSets[i] = BlockMask.ALL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int set = 0;
|
||||
int clear = 0;
|
||||
for (AbstractProperty prop : (List<AbstractProperty>) type.getProperties()) {
|
||||
List values = prop.getValues();
|
||||
for (int j = 0; j < values.size(); j++) {
|
||||
int localI = j << prop.getBitOffset() >> BlockTypes.BIT_OFFSET;
|
||||
if (FastBitSet.get(bitSet, localI)) set++;
|
||||
else clear++;
|
||||
}
|
||||
}
|
||||
if (set == 0) bitSets[i] = null;
|
||||
else if (clear == 0) bitSets[i] = BlockMask.ALL;
|
||||
}
|
||||
optimizedStates = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected long[][] getBits() {
|
||||
return this.bitSets;
|
||||
}
|
||||
|
||||
public Mask build(Extent extent) {
|
||||
optimize();
|
||||
return new BlockMask(extent, bitSets);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
public class BlockTypeMask extends AbstractExtentMask {
|
||||
private final boolean[] types;
|
||||
|
||||
protected BlockTypeMask(Extent extent, boolean[] types) {
|
||||
super(extent);
|
||||
this.types = types;
|
||||
}
|
||||
|
||||
public BlockTypeMask(Extent extent, BlockType... types) {
|
||||
super(extent);
|
||||
this.types = new boolean[BlockTypes.size()];
|
||||
for (BlockType type : types) this.types[type.getInternalId()] = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return types[getExtent().getBlockType(vector).getInternalId()];
|
||||
}
|
||||
}
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
/**
|
||||
* Has the criteria where the Y value of passed positions must be within
|
||||
* a certain range of Y values (inclusive).
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
@ -29,6 +27,8 @@ import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A mask that evaluates an expression.
|
||||
*
|
||||
|
@ -19,13 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ExpressionMask2D extends AbstractMask2D {
|
||||
|
||||
private final Expression expression;
|
||||
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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 com.sk89q.worldedit.blocks.Blocks;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class FuzzyBlockMask extends BlockMask {
|
||||
|
||||
public FuzzyBlockMask(Extent extent, Collection<BlockStateHolder> blocks) {
|
||||
super(extent, blocks);
|
||||
}
|
||||
|
||||
public FuzzyBlockMask(Extent extent, BlockStateHolder... block) {
|
||||
super(extent, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
Extent extent = getExtent();
|
||||
Collection<BlockStateHolder> blocks = getBlocks();
|
||||
return Blocks.containsFuzzy(blocks, extent.getFullBlock(vector));
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class InverseMask extends AbstractMask {
|
||||
private final Mask mask;
|
||||
|
||||
public InverseMask(Mask other) {
|
||||
this.mask = other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return !mask.test(vector);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
Mask2D mask2d = mask.toMask2D();
|
||||
if (mask2d != null) {
|
||||
return Masks.negate(mask2d);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask inverse() {
|
||||
return mask;
|
||||
}
|
||||
}
|
@ -19,13 +19,19 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Link;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.command.UtilityCommands;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.sk89q.worldedit.function.mask.Masks.negate;
|
||||
|
||||
/**
|
||||
* Tests whether a given vector meets a criteria.
|
||||
*/
|
||||
@Link(clazz = UtilityCommands.class, value = "masks")
|
||||
public interface Mask {
|
||||
|
||||
/**
|
||||
@ -42,6 +48,28 @@ public interface Mask {
|
||||
* @return a 2D mask version or {@code null} if this mask can't be 2D
|
||||
*/
|
||||
@Nullable
|
||||
Mask2D toMask2D();
|
||||
default Mask2D toMask2D() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Mask optimize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Mask and(Mask other) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Mask or(Mask other) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Mask inverse() {
|
||||
if (this instanceof Masks.AlwaysTrue) {
|
||||
return Masks.ALWAYS_FALSE;
|
||||
} else if (this instanceof Masks.AlwaysFalse) {
|
||||
return Masks.ALWAYS_TRUE;
|
||||
}
|
||||
return new InverseMask(this);
|
||||
}
|
||||
}
|
||||
|
@ -19,18 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
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 javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Combines several masks and requires that all masks return true
|
||||
@ -39,7 +34,8 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class MaskIntersection extends AbstractMask {
|
||||
|
||||
private final Set<Mask> masks = new HashSet<>();
|
||||
private final Set<Mask> masks = new LinkedHashSet<>();
|
||||
private Mask[] masksArray;
|
||||
|
||||
/**
|
||||
* Create a new intersection.
|
||||
@ -49,6 +45,82 @@ public class MaskIntersection extends AbstractMask {
|
||||
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()]);
|
||||
}
|
||||
}
|
||||
|
||||
public Function<Map.Entry<Mask, Mask>, Mask> pairingFunction() {
|
||||
return input -> input.getKey().and(input.getValue());
|
||||
}
|
||||
|
||||
private void optimizeMasks(Set<Mask> ignore) {
|
||||
LinkedHashSet<Mask> newMasks = null;
|
||||
for (Mask mask : masks) {
|
||||
if (ignore.contains(mask)) continue;
|
||||
Mask newMask = mask.optimize();
|
||||
if (newMask != null) {
|
||||
if (newMask != mask) {
|
||||
if (newMasks == null) newMasks = new LinkedHashSet<>();
|
||||
newMasks.add(newMask);
|
||||
}
|
||||
} else {
|
||||
ignore.add(mask);
|
||||
}
|
||||
if (newMasks != null) {
|
||||
masks.clear();
|
||||
masks.addAll(newMasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask optimize() {
|
||||
Set<Mask> optimized = new HashSet<>();
|
||||
Set<Map.Entry<Mask, Mask>> failedCombines = new HashSet<>();
|
||||
// Combine the masks
|
||||
while (combine(pairingFunction(), failedCombines));
|
||||
// Optimize / combine
|
||||
do optimizeMasks(optimized);
|
||||
while (combine(pairingFunction(), failedCombines));
|
||||
// Return result
|
||||
formArray();
|
||||
if (masks.size() == 0) return Masks.alwaysTrue();
|
||||
if (masks.size() == 1) return masks.iterator().next();
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean combine(Function<Map.Entry<Mask, Mask>, Mask> pairing, Set<Map.Entry<Mask, Mask>> failedCombines) {
|
||||
boolean hasOptimized = false;
|
||||
while (true) {
|
||||
Mask[] result = null;
|
||||
outer:
|
||||
for (Mask mask : masks) {
|
||||
for (Mask other : masks) {
|
||||
AbstractMap.SimpleEntry pair = new AbstractMap.SimpleEntry(mask, other);
|
||||
if (failedCombines.contains(pair)) continue;
|
||||
Mask combined = pairing.apply(pair);
|
||||
if (combined != null) {
|
||||
result = new Mask[]{combined, mask, other};
|
||||
break outer;
|
||||
} else {
|
||||
failedCombines.add(pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) break;
|
||||
masks.remove(result[1]);
|
||||
masks.remove(result[2]);
|
||||
masks.add(result[0]);
|
||||
hasOptimized = true;
|
||||
}
|
||||
return hasOptimized;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,6 +140,7 @@ public class MaskIntersection extends AbstractMask {
|
||||
public void add(Collection<Mask> masks) {
|
||||
checkNotNull(masks);
|
||||
this.masks.addAll(masks);
|
||||
formArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,25 +161,24 @@ public class MaskIntersection extends AbstractMask {
|
||||
return masks;
|
||||
}
|
||||
|
||||
public final Mask[] getMasksArray() {
|
||||
return masksArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
if (masks.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Mask mask : masks) {
|
||||
for (Mask mask : masksArray) {
|
||||
if (!mask.test(vector)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
List<Mask2D> mask2dList = new ArrayList<>();
|
||||
List<Mask2D> mask2dList = new ArrayList<Mask2D>();
|
||||
for (Mask mask : masks) {
|
||||
Mask2D mask2d = mask.toMask2D();
|
||||
if (mask2d != null) {
|
||||
@ -117,5 +189,4 @@ public class MaskIntersection extends AbstractMask {
|
||||
}
|
||||
return new MaskIntersection2D(mask2dList);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -28,6 +26,8 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Tests true if all contained masks test true.
|
||||
*/
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@ -53,10 +53,13 @@ public class MaskUnion extends MaskIntersection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
Collection<Mask> masks = getMasks();
|
||||
public Function<Map.Entry<Mask, Mask>, Mask> pairingFunction() {
|
||||
return input -> input.getKey().or(input.getValue());
|
||||
}
|
||||
|
||||
for (Mask mask : masks) {
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
for (Mask mask : getMasksArray()) {
|
||||
if (mask.test(vector)) {
|
||||
return true;
|
||||
}
|
||||
@ -68,7 +71,7 @@ public class MaskUnion extends MaskIntersection {
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
List<Mask2D> mask2dList = new ArrayList<>();
|
||||
List<Mask2D> mask2dList = new ArrayList<Mask2D>();
|
||||
for (Mask mask : getMasks()) {
|
||||
Mask2D mask2d = mask.toMask2D();
|
||||
if (mask2d != null) {
|
||||
@ -79,4 +82,8 @@ public class MaskUnion extends MaskIntersection {
|
||||
}
|
||||
return new MaskUnion2D(mask2dList);
|
||||
}
|
||||
|
||||
public static Class<MaskUnion> inject() {
|
||||
return MaskUnion.class;
|
||||
}
|
||||
}
|
||||
|
@ -1,42 +1,27 @@
|
||||
/*
|
||||
* 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 static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Various utility functions related to {@link Mask} and {@link Mask2D}.
|
||||
*/
|
||||
public final class Masks {
|
||||
|
||||
private static final AlwaysTrue ALWAYS_TRUE = new AlwaysTrue();
|
||||
private static final AlwaysFalse ALWAYS_FALSE = new AlwaysFalse();
|
||||
protected static final AlwaysTrue ALWAYS_TRUE = new AlwaysTrue();
|
||||
protected static final AlwaysFalse ALWAYS_FALSE = new AlwaysFalse();
|
||||
|
||||
private Masks() {
|
||||
}
|
||||
|
||||
public static boolean isNull(Mask mask) {
|
||||
return mask == null || mask == ALWAYS_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a 3D mask that always returns true;
|
||||
*
|
||||
@ -46,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;
|
||||
*
|
||||
@ -58,34 +47,11 @@ public final class Masks {
|
||||
/**
|
||||
* Negate the given mask.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param finalMask the mask
|
||||
* @return a new mask
|
||||
*/
|
||||
public static Mask negate(final Mask mask) {
|
||||
if (mask instanceof AlwaysTrue) {
|
||||
return ALWAYS_FALSE;
|
||||
} else if (mask instanceof AlwaysFalse) {
|
||||
return ALWAYS_TRUE;
|
||||
}
|
||||
|
||||
checkNotNull(mask);
|
||||
return new AbstractMask() {
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return !mask.test(vector);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
Mask2D mask2d = mask.toMask2D();
|
||||
if (mask2d != null) {
|
||||
return negate(mask2d);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
public static Mask negate(final Mask finalMask) {
|
||||
return finalMask.inverse();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,7 +97,7 @@ public final class Masks {
|
||||
};
|
||||
}
|
||||
|
||||
private static class AlwaysTrue implements Mask, Mask2D {
|
||||
protected static class AlwaysTrue implements Mask, Mask2D {
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return true;
|
||||
@ -147,9 +113,19 @@ public final class Masks {
|
||||
public Mask2D toMask2D() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask and(Mask other) {
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask or(Mask other) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AlwaysFalse implements Mask, Mask2D {
|
||||
protected static class AlwaysFalse implements Mask, Mask2D {
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return false;
|
||||
@ -165,6 +141,19 @@ public final class Masks {
|
||||
public Mask2D toMask2D() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask and(Mask other) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask or(Mask other) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public static Class<?> inject() {
|
||||
return Masks.class;
|
||||
}
|
||||
}
|
@ -19,14 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.math.noise.NoiseGenerator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A mask that uses a noise generator and returns true whenever the noise
|
||||
* generator returns a value above the given density.
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.math.noise.NoiseGenerator;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A mask that uses a noise generator and returns true whenever the noise
|
||||
* generator returns a value above the given density.
|
||||
|
@ -1,30 +1,12 @@
|
||||
/*
|
||||
* 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 static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Checks whether another mask tests true for a position that is offset
|
||||
* a given vector.
|
||||
@ -33,11 +15,12 @@ public class OffsetMask extends AbstractMask {
|
||||
|
||||
private Mask mask;
|
||||
private Vector offset;
|
||||
private MutableBlockVector mutable = new MutableBlockVector();
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param mask the mask
|
||||
* @param offset the offset
|
||||
*/
|
||||
public OffsetMask(Mask mask, Vector offset) {
|
||||
@ -87,7 +70,10 @@ public class OffsetMask extends AbstractMask {
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return getMask().test(vector.add(offset));
|
||||
mutable.mutX((vector.getX() + offset.getX()));
|
||||
mutable.mutY((vector.getY() + offset.getY()));
|
||||
mutable.mutZ((vector.getZ() + offset.getZ()));
|
||||
return getMask().test(mutable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -101,4 +87,7 @@ public class OffsetMask extends AbstractMask {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return OffsetMask.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Checks whether another mask tests true for a position that is offset
|
||||
* a given vector.
|
||||
|
@ -19,13 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A mask that tests whether given positions are contained within a region.
|
||||
*/
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class SingleBlockStateBitMask extends AbstractExtentMask {
|
||||
private final int bitMask;
|
||||
|
||||
protected SingleBlockStateBitMask(Extent extent, int bitMask) {
|
||||
super(extent);
|
||||
this.bitMask = bitMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
int internalId = getExtent().getBlock(vector).getInternalId();
|
||||
return (internalId & bitMask) == internalId;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
public class SingleBlockStateMask extends AbstractExtentMask {
|
||||
private final BlockStateHolder state;
|
||||
|
||||
public BlockStateHolder getBlockState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public SingleBlockStateMask(Extent extent, BlockStateHolder state) {
|
||||
super(extent);
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return state.equals(getExtent().getBlock(vector));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask inverse() {
|
||||
return new BlockMaskBuilder().add(state).build(getExtent()).inverse();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.sk89q.worldedit.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
public class SingleBlockTypeMask extends AbstractExtentMask {
|
||||
private final int internalId;
|
||||
|
||||
public SingleBlockTypeMask(Extent extent, BlockType type) {
|
||||
super(extent);
|
||||
this.internalId = type.getInternalId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return getExtent().getBlockType(vector).getInternalId() == internalId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask inverse() {
|
||||
return new BlockMaskBuilder().add(BlockTypes.get(internalId)).build(getExtent()).inverse();
|
||||
}
|
||||
|
||||
public BlockType getBlockType() {
|
||||
return BlockTypes.get(internalId);
|
||||
}
|
||||
}
|
@ -1,41 +1,25 @@
|
||||
/*
|
||||
* 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 com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.blocks.BlockType;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SolidBlockMask extends AbstractExtentMask {
|
||||
public class SolidBlockMask extends BlockTypeMask {
|
||||
|
||||
public SolidBlockMask(Extent extent) {
|
||||
super(extent);
|
||||
public static boolean[] getTypes() {
|
||||
boolean[] types = new boolean[BlockTypes.size()];
|
||||
for (BlockTypes type : BlockTypes.values) {
|
||||
types[type.ordinal()] = type.getMaterial().isSolid();
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
Extent extent = getExtent();
|
||||
BlockState block = extent.getBlock(vector);
|
||||
return block.getBlockType().getMaterial().isMovementBlocker();
|
||||
public SolidBlockMask(Extent extent) {
|
||||
super(extent, getTypes());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -44,4 +28,7 @@ public class SolidBlockMask extends AbstractExtentMask {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
public static Class<?> inject() {
|
||||
return SolidBlockMask.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import java.util.List;
|
||||
|
||||
public class BackwardsExtentBlockCopy implements Operation {
|
||||
private final Region region;
|
||||
private final Transform transform;
|
||||
private final Extent destination;
|
||||
private final Extent source;
|
||||
private final RegionFunction function;
|
||||
private final Vector origin;
|
||||
|
||||
private Vector mutable = new MutableBlockVector();
|
||||
|
||||
public BackwardsExtentBlockCopy(Extent source, Region region, Extent destination, Vector origin, Transform transform, RegionFunction function) {
|
||||
this.source = source;
|
||||
this.region = region;
|
||||
this.destination = destination;
|
||||
this.transform = transform;
|
||||
this.function = function;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
CuboidRegion destRegion = transform(this.transform, this.region);
|
||||
Transform inverse = this.transform.inverse();
|
||||
for (Vector pt : destRegion) {
|
||||
Vector copyFrom = transform(inverse, pt);
|
||||
if (region.contains(copyFrom)) {
|
||||
function.apply(pt);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CuboidRegion transform(Transform transform, Region region) {
|
||||
Vector min = new MutableBlockVector(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
Vector max = new MutableBlockVector(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
|
||||
Vector pos1 = region.getMinimumPoint();
|
||||
Vector pos2 = region.getMaximumPoint();
|
||||
for (int x : new int[] { pos1.getBlockX(), pos2.getBlockX() }) {
|
||||
for (int y : new int[] { pos1.getBlockY(), pos2.getBlockY() }) {
|
||||
for (int z : new int[] { pos1.getBlockZ(), pos2.getBlockZ() }) {
|
||||
Vector pt = transform(transform, new Vector(x, y, z)).toBlockVector();
|
||||
min = Vector.getMinimum(min, pt);
|
||||
max = Vector.getMaximum(max, pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new CuboidRegion(min, max);
|
||||
}
|
||||
|
||||
private Vector transform(Transform transform, Vector pt) {
|
||||
mutable.mutX(((pt.getBlockX() - origin.getBlockX())));
|
||||
mutable.mutY(((pt.getBlockY() - origin.getBlockY())));
|
||||
mutable.mutZ(((pt.getBlockZ() - origin.getBlockZ())));
|
||||
Vector tmp = transform.apply(mutable);
|
||||
tmp.mutX((tmp.getBlockX() + origin.getBlockX()));
|
||||
tmp.mutY((tmp.getBlockY() + origin.getBlockY()));
|
||||
tmp.mutZ((tmp.getBlockZ() + origin.getBlockZ()));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
|
||||
}
|
||||
}
|
@ -19,18 +19,20 @@
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Sets block from an iterator of {@link Map.Entry} containing a
|
||||
* {@link BlockVector} as the key and a {@link BaseBlock} as the value.
|
||||
|
@ -19,16 +19,18 @@
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.history.UndoContext;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.history.changeset.ChangeSet;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Performs an undo or redo from a given {@link ChangeSet}.
|
||||
*/
|
||||
@ -44,18 +46,18 @@ public class ChangeSetExecutor implements Operation {
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param changeSet the change set
|
||||
* @param type type of change
|
||||
* @param context the undo context
|
||||
* @param type type of change
|
||||
* @param context the undo context
|
||||
*/
|
||||
private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context) {
|
||||
private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context, BlockBag blockBag, int inventory) {
|
||||
checkNotNull(changeSet);
|
||||
checkNotNull(type);
|
||||
checkNotNull(context);
|
||||
|
||||
this.type = type;
|
||||
this.context = context;
|
||||
|
||||
if (type == Type.UNDO) {
|
||||
if (changeSet instanceof FaweChangeSet) {
|
||||
iterator = ((FaweChangeSet) changeSet).getIterator(blockBag, inventory, type == Type.REDO);
|
||||
} else if (type == Type.UNDO) {
|
||||
iterator = changeSet.backwardIterator();
|
||||
} else {
|
||||
iterator = changeSet.forwardIterator();
|
||||
@ -64,15 +66,15 @@ public class ChangeSetExecutor implements Operation {
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
while (iterator.hasNext()) {
|
||||
Change change = iterator.next();
|
||||
if (type == Type.UNDO) {
|
||||
change.undo(context);
|
||||
} else {
|
||||
change.redo(context);
|
||||
if (type == Type.UNDO) {
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().undo(context);
|
||||
}
|
||||
} else {
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().redo(context);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -84,26 +86,35 @@ public class ChangeSetExecutor implements Operation {
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
}
|
||||
|
||||
public static ChangeSetExecutor create(ChangeSet changeSet, UndoContext context, Type type, BlockBag blockBag, int inventory) {
|
||||
return new ChangeSetExecutor(changeSet, type, context, blockBag, inventory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new undo operation.
|
||||
*
|
||||
* @param changeSet the change set
|
||||
* @param context an undo context
|
||||
* @param context an undo context
|
||||
* @return an operation
|
||||
*/
|
||||
@Deprecated
|
||||
public static ChangeSetExecutor createUndo(ChangeSet changeSet, UndoContext context) {
|
||||
return new ChangeSetExecutor(changeSet, Type.UNDO, context);
|
||||
return new ChangeSetExecutor(changeSet, Type.UNDO, context, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new redo operation.
|
||||
*
|
||||
* @param changeSet the change set
|
||||
* @param context an undo context
|
||||
* @param context an undo context
|
||||
* @return an operation
|
||||
*/
|
||||
@Deprecated
|
||||
public static ChangeSetExecutor createRedo(ChangeSet changeSet, UndoContext context) {
|
||||
return new ChangeSetExecutor(changeSet, Type.REDO, context);
|
||||
return new ChangeSetExecutor(changeSet, Type.REDO, context, null, 0);
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return ChangeSetExecutor.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Executes a delegete operation, but returns to another operation upon
|
||||
* completing the delegate.
|
||||
|
@ -19,33 +19,45 @@
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.boydti.fawe.example.MappedFaweQueue;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.extent.BlockTranslateExtent;
|
||||
import com.boydti.fawe.object.extent.PositionTransformExtent;
|
||||
import com.boydti.fawe.object.function.block.BiomeCopy;
|
||||
import com.boydti.fawe.object.function.block.CombinedBlockCopy;
|
||||
import com.boydti.fawe.object.function.block.SimpleBlockCopy;
|
||||
import com.boydti.fawe.util.MaskTraverser;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.metadata.EntityProperties;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.function.CombinedRegionFunction;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.RegionMaskTestFunction;
|
||||
import com.sk89q.worldedit.function.RegionMaskingFilter;
|
||||
import com.sk89q.worldedit.function.block.ExtentBlockCopy;
|
||||
import com.sk89q.worldedit.function.entity.ExtentEntityCopy;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.visitor.EntityVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.IntersectRegionFunction;
|
||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
import com.sk89q.worldedit.math.transform.Identity;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Makes a copy of a portion of one extent to another extent or another point.
|
||||
*
|
||||
* <p>
|
||||
* <p>This is a forward extent copy, meaning that it iterates over the blocks
|
||||
* in the source extent, and will copy as many blocks as there are in the
|
||||
* source. Therefore, interpolation will not occur to fill in the gaps.</p>
|
||||
@ -60,21 +72,22 @@ public class ForwardExtentCopy implements Operation {
|
||||
private int repetitions = 1;
|
||||
private Mask sourceMask = Masks.alwaysTrue();
|
||||
private boolean removingEntities;
|
||||
private boolean copyingEntities = true; // default to true for backwards compatibility, sort of
|
||||
private RegionFunction sourceFunction = null;
|
||||
private Transform transform = new Identity();
|
||||
private Transform currentTransform = null;
|
||||
private RegionVisitor lastVisitor;
|
||||
private int affected;
|
||||
private boolean copyEntities = true;
|
||||
private boolean copyBiomes = false;
|
||||
private RegionFunction filterFunction;
|
||||
|
||||
/**
|
||||
* Create a new copy using the region's lowest minimum point as the
|
||||
* "from" position.
|
||||
*
|
||||
* @param source the source extent
|
||||
* @param region the region to copy
|
||||
* @param source the source extent
|
||||
* @param region the region to copy
|
||||
* @param destination the destination extent
|
||||
* @param to the destination position
|
||||
* @param to the destination position
|
||||
* @see #ForwardExtentCopy(Extent, Region, Vector, Extent, Vector) the main constructor
|
||||
*/
|
||||
public ForwardExtentCopy(Extent source, Region region, Extent destination, Vector to) {
|
||||
@ -84,11 +97,11 @@ public class ForwardExtentCopy implements Operation {
|
||||
/**
|
||||
* Create a new copy.
|
||||
*
|
||||
* @param source the source extent
|
||||
* @param region the region to copy
|
||||
* @param from the source position
|
||||
* @param source the source extent
|
||||
* @param region the region to copy
|
||||
* @param from the source position
|
||||
* @param destination the destination extent
|
||||
* @param to the destination position
|
||||
* @param to the destination position
|
||||
*/
|
||||
public ForwardExtentCopy(Extent source, Region region, Vector from, Extent destination, Vector to) {
|
||||
checkNotNull(source);
|
||||
@ -105,7 +118,7 @@ public class ForwardExtentCopy implements Operation {
|
||||
|
||||
/**
|
||||
* Get the transformation that will occur on every point.
|
||||
*
|
||||
* <p>
|
||||
* <p>The transformation will stack with each repetition.</p>
|
||||
*
|
||||
* @return a transformation
|
||||
@ -127,7 +140,7 @@ public class ForwardExtentCopy implements Operation {
|
||||
|
||||
/**
|
||||
* Get the mask that gets applied to the source extent.
|
||||
*
|
||||
* <p>
|
||||
* <p>This mask can be used to filter what will be copied from the source.</p>
|
||||
*
|
||||
* @return a source mask
|
||||
@ -136,6 +149,22 @@ public class ForwardExtentCopy implements Operation {
|
||||
return sourceMask;
|
||||
}
|
||||
|
||||
public void setCopyEntities(boolean copyEntities) {
|
||||
this.copyEntities = copyEntities;
|
||||
}
|
||||
|
||||
public boolean isCopyEntities() {
|
||||
return copyEntities;
|
||||
}
|
||||
|
||||
public void setCopyBiomes(boolean copyBiomes) {
|
||||
this.copyBiomes = copyBiomes;
|
||||
}
|
||||
|
||||
public boolean isCopyBiomes() {
|
||||
return copyBiomes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a mask that gets applied to the source extent.
|
||||
*
|
||||
@ -147,6 +176,10 @@ public class ForwardExtentCopy implements Operation {
|
||||
this.sourceMask = sourceMask;
|
||||
}
|
||||
|
||||
public void setFilterFunction(RegionFunction filterFunction) {
|
||||
this.filterFunction = filterFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function that gets applied to all source blocks <em>after</em>
|
||||
* the copy has been made.
|
||||
@ -163,6 +196,7 @@ public class ForwardExtentCopy implements Operation {
|
||||
*
|
||||
* @param function a source function, or null if none is to be applied
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSourceFunction(RegionFunction function) {
|
||||
this.sourceFunction = function;
|
||||
}
|
||||
@ -186,24 +220,6 @@ public class ForwardExtentCopy implements Operation {
|
||||
this.repetitions = repetitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether entities should be copied along with blocks.
|
||||
*
|
||||
* @return true if copying
|
||||
*/
|
||||
public boolean isCopyingEntities() {
|
||||
return copyingEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether entities should be copied along with blocks.
|
||||
*
|
||||
* @param copyingEntities true if copying
|
||||
*/
|
||||
public void setCopyingEntities(boolean copyingEntities) {
|
||||
this.copyingEntities = copyingEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether entities that are copied should be removed.
|
||||
*
|
||||
@ -233,43 +249,124 @@ public class ForwardExtentCopy implements Operation {
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
if (lastVisitor != null) {
|
||||
affected += lastVisitor.getAffected();
|
||||
lastVisitor = null;
|
||||
if (currentTransform == null) {
|
||||
currentTransform = transform;
|
||||
}
|
||||
FaweQueue queue;
|
||||
if (source instanceof EditSession) {
|
||||
queue = ((EditSession) source).getQueue();
|
||||
} else if (destination instanceof EditSession) {
|
||||
queue = ((EditSession) destination).getQueue();
|
||||
} else {
|
||||
queue = null;
|
||||
}
|
||||
|
||||
if (repetitions > 0) {
|
||||
repetitions--;
|
||||
Extent finalDest = destination;
|
||||
Vector translation = to.subtract(from);
|
||||
|
||||
if (currentTransform == null) {
|
||||
currentTransform = transform;
|
||||
if (!translation.equals(Vector.ZERO)) {
|
||||
finalDest = new BlockTranslateExtent(finalDest, translation.getBlockX(), translation.getBlockY(), translation.getBlockZ());
|
||||
}
|
||||
|
||||
RegionFunction copy;
|
||||
Operation blockCopy = null;
|
||||
PositionTransformExtent transExt = null;
|
||||
if (!currentTransform.isIdentity()) {
|
||||
if (!(currentTransform instanceof AffineTransform) || ((AffineTransform) currentTransform).isOffAxis()) {
|
||||
transExt = new PositionTransformExtent(source, currentTransform.inverse());
|
||||
transExt.setOrigin(from);
|
||||
copy = new SimpleBlockCopy(transExt, finalDest);
|
||||
if (this.filterFunction != null) {
|
||||
copy = new IntersectRegionFunction(filterFunction, copy);
|
||||
}
|
||||
if (sourceFunction != null) {
|
||||
copy = CombinedRegionFunction.combine(copy, sourceFunction);
|
||||
}
|
||||
if (sourceMask != Masks.alwaysTrue()) {
|
||||
new MaskTraverser(sourceMask).reset(transExt);
|
||||
copy = new RegionMaskingFilter(sourceMask, copy);
|
||||
}
|
||||
if (copyBiomes && (!(source instanceof BlockArrayClipboard) || ((BlockArrayClipboard) source).IMP.hasBiomes())) {
|
||||
copy = CombinedRegionFunction.combine(copy, new BiomeCopy(source, finalDest));
|
||||
}
|
||||
blockCopy = new BackwardsExtentBlockCopy(transExt, region, finalDest, from, transform, copy);
|
||||
} else {
|
||||
currentTransform = currentTransform.combine(transform);
|
||||
transExt = new PositionTransformExtent(finalDest, currentTransform);
|
||||
transExt.setOrigin(from);
|
||||
finalDest = transExt;
|
||||
}
|
||||
}
|
||||
|
||||
ExtentBlockCopy blockCopy = new ExtentBlockCopy(source, from, destination, to, currentTransform);
|
||||
RegionMaskingFilter filter = new RegionMaskingFilter(sourceMask, blockCopy);
|
||||
RegionFunction function = sourceFunction != null ? new CombinedRegionFunction(filter, sourceFunction) : filter;
|
||||
RegionVisitor blockVisitor = new RegionVisitor(region, function);
|
||||
if (blockCopy == null) {
|
||||
RegionFunction maskFunc = null;
|
||||
|
||||
lastVisitor = blockVisitor;
|
||||
if (sourceFunction != null) {
|
||||
Vector disAbs = translation.positive();
|
||||
Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
|
||||
boolean overlap = (disAbs.getBlockX() < size.getBlockX() && disAbs.getBlockY() < size.getBlockY() && disAbs.getBlockZ() < size.getBlockZ());
|
||||
|
||||
if (copyingEntities) {
|
||||
RegionFunction copySrcFunc = sourceFunction;
|
||||
if (overlap && translation.length() != 0) {
|
||||
MutableBlockVector mutable = new MutableBlockVector();
|
||||
|
||||
int x = translation.getBlockX();
|
||||
int y = translation.getBlockY();
|
||||
int z = translation.getBlockZ();
|
||||
|
||||
maskFunc = position -> {
|
||||
mutable.setComponents(position.getBlockX() + x, position.getBlockY() + y, position.getBlockZ() + z);
|
||||
if (region.contains(mutable)) {
|
||||
return sourceFunction.apply(mutable);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
copySrcFunc = position -> {
|
||||
mutable.setComponents(position.getBlockX() - x, position.getBlockY() - y, position.getBlockZ() - z);
|
||||
if (!region.contains(mutable)) {
|
||||
return sourceFunction.apply(position);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
copy = new CombinedBlockCopy(source, finalDest, copySrcFunc);
|
||||
}
|
||||
else {
|
||||
copy = new SimpleBlockCopy(source, finalDest);
|
||||
}
|
||||
if (this.filterFunction != null) {
|
||||
copy = new IntersectRegionFunction(filterFunction, copy);
|
||||
}
|
||||
if (sourceMask != Masks.alwaysTrue()) {
|
||||
if (maskFunc != null) copy = new RegionMaskTestFunction(sourceMask, copy, maskFunc);
|
||||
else copy = new RegionMaskingFilter(sourceMask, copy);
|
||||
}
|
||||
if (copyBiomes && (!(source instanceof BlockArrayClipboard) || ((BlockArrayClipboard) source).IMP.hasBiomes())) {
|
||||
copy = CombinedRegionFunction.combine(copy, new BiomeCopy(source, finalDest));
|
||||
}
|
||||
blockCopy = new RegionVisitor(region, copy, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);
|
||||
}
|
||||
|
||||
List<? extends Entity> entities = isCopyEntities() ? source.getEntities(region) : new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < repetitions; i++) {
|
||||
Operations.completeBlindly(blockCopy);
|
||||
|
||||
if (!entities.isEmpty()) {
|
||||
ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform);
|
||||
entityCopy.setRemoving(removingEntities);
|
||||
List<? extends Entity> entities = Lists.newArrayList(source.getEntities(region));
|
||||
entities.removeIf(entity -> {
|
||||
EntityProperties properties = entity.getFacet(EntityProperties.class);
|
||||
return properties != null && !properties.isPasteable();
|
||||
});
|
||||
EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy);
|
||||
return new DelegateOperation(this, new OperationQueue(blockVisitor, entityVisitor));
|
||||
} else {
|
||||
return new DelegateOperation(this, blockVisitor);
|
||||
Operations.completeBlindly(entityVisitor);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
|
||||
if (transExt != null) {
|
||||
currentTransform = currentTransform.combine(transform);
|
||||
transExt.setTransform(currentTransform);
|
||||
}
|
||||
|
||||
}
|
||||
affected = region.getArea();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -280,4 +377,7 @@ public class ForwardExtentCopy implements Operation {
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return ForwardExtentCopy.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.operation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
@ -29,6 +27,8 @@ import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Executes multiple queues in order.
|
||||
*/
|
||||
|
@ -30,15 +30,17 @@ public final class Operations {
|
||||
private Operations() {
|
||||
}
|
||||
|
||||
private static RunContext context = new RunContext();
|
||||
|
||||
/**
|
||||
* Complete a given operation synchronously until it completes.
|
||||
*
|
||||
* @param op operation to execute
|
||||
* @param operation operation to execute
|
||||
* @throws WorldEditException WorldEdit exception
|
||||
*/
|
||||
public static void complete(Operation op) throws WorldEditException {
|
||||
while (op != null) {
|
||||
op = op.resume(new RunContext());
|
||||
public static void complete(Operation operation) throws WorldEditException {
|
||||
while (operation != null) {
|
||||
operation = operation.resume(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,19 +48,11 @@ public final class Operations {
|
||||
* Complete a given operation synchronously until it completes. Catch all
|
||||
* errors that is not {@link MaxChangedBlocksException} for legacy reasons.
|
||||
*
|
||||
* @param op operation to execute
|
||||
* @param operation operation to execute
|
||||
* @throws MaxChangedBlocksException thrown when too many blocks have been changed
|
||||
*/
|
||||
public static void completeLegacy(Operation op) throws MaxChangedBlocksException {
|
||||
while (op != null) {
|
||||
try {
|
||||
op = op.resume(new RunContext());
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
throw e;
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
public static void completeLegacy(Operation operation) throws MaxChangedBlocksException {
|
||||
completeBlindly(operation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,16 +60,27 @@ public final class Operations {
|
||||
* {@link com.sk89q.worldedit.WorldEditException} exceptions as
|
||||
* {@link java.lang.RuntimeException}s.
|
||||
*
|
||||
* @param op operation to execute
|
||||
* @param operation operation to execute
|
||||
*/
|
||||
public static void completeBlindly(Operation op) {
|
||||
while (op != null) {
|
||||
try {
|
||||
op = op.resume(new RunContext());
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
public static void completeBlindly(Operation operation) {
|
||||
try {
|
||||
while (operation != null) {
|
||||
operation = operation.resume(context);
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void completeSmart(final Operation op, final Runnable whenDone, final boolean threadsafe) {
|
||||
completeBlindly(op);
|
||||
if (whenDone != null) {
|
||||
whenDone.run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,12 @@
|
||||
/*
|
||||
* 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.pattern;
|
||||
|
||||
/**
|
||||
* An abstract implementation for {@link Pattern}s.
|
||||
*/
|
||||
public abstract class AbstractPattern implements Pattern {
|
||||
import java.io.Serializable;
|
||||
|
||||
public abstract class AbstractPattern implements Pattern, Serializable {
|
||||
public AbstractPattern() {
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return AbstractPattern.class;
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +1,30 @@
|
||||
/*
|
||||
* 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.pattern;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
/**
|
||||
* A pattern that returns the same {@link BaseBlock} each time.
|
||||
* @deprecated Just use BaseBlock directly
|
||||
*/
|
||||
public class BlockPattern extends AbstractPattern {
|
||||
@Deprecated
|
||||
public class BlockPattern implements Pattern {
|
||||
|
||||
private BlockStateHolder block;
|
||||
|
||||
/**
|
||||
* Create a new pattern with the given block.
|
||||
*
|
||||
* @param block the block
|
||||
*/
|
||||
public BlockPattern(BlockStateHolder block) {
|
||||
setBlock(block);
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockStateHolder apply(Vector position) {
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,9 +46,7 @@ public class BlockPattern extends AbstractPattern {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockStateHolder apply(Vector position) {
|
||||
return block;
|
||||
public static Class<BlockPattern> inject() {
|
||||
return BlockPattern.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,37 +1,24 @@
|
||||
/*
|
||||
* 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.pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A pattern that reads from {@link Clipboard}.
|
||||
*/
|
||||
public class ClipboardPattern extends AbstractPattern {
|
||||
|
||||
private final Clipboard clipboard;
|
||||
private final Vector size;
|
||||
private final int sx, sy, sz;
|
||||
private final Vector min;
|
||||
private MutableBlockVector mutable = new MutableBlockVector();
|
||||
|
||||
/**
|
||||
* Create a new clipboard pattern.
|
||||
@ -41,16 +28,28 @@ public class ClipboardPattern extends AbstractPattern {
|
||||
public ClipboardPattern(Clipboard clipboard) {
|
||||
checkNotNull(clipboard);
|
||||
this.clipboard = clipboard;
|
||||
this.size = clipboard.getMaximumPoint().subtract(clipboard.getMinimumPoint()).add(1, 1, 1);
|
||||
Vector size = clipboard.getMaximumPoint().subtract(clipboard.getMinimumPoint()).add(1, 1, 1);
|
||||
this.sx = size.getBlockX();
|
||||
this.sy = size.getBlockY();
|
||||
this.sz = size.getBlockZ();
|
||||
this.min = clipboard.getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockStateHolder apply(Vector position) {
|
||||
int xp = Math.abs(position.getBlockX()) % size.getBlockX();
|
||||
int yp = Math.abs(position.getBlockY()) % size.getBlockY();
|
||||
int zp = Math.abs(position.getBlockZ()) % size.getBlockZ();
|
||||
|
||||
return clipboard.getFullBlock(clipboard.getMinimumPoint().add(new Vector(xp, yp, zp)));
|
||||
int xp = position.getBlockX() % sx;
|
||||
int yp = position.getBlockY() % sy;
|
||||
int zp = position.getBlockZ() % sz;
|
||||
if (xp < 0) xp += sx;
|
||||
if (yp < 0) yp += sy;
|
||||
if (zp < 0) zp += sz;
|
||||
mutable.mutX((min.getX() + xp));
|
||||
mutable.mutY((min.getY() + yp));
|
||||
mutable.mutZ((min.getZ() + zp));
|
||||
return clipboard.getBlock(mutable);
|
||||
}
|
||||
|
||||
}
|
||||
public static Class<?> inject() {
|
||||
return ClipboardPattern.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.sk89q.worldedit.function.pattern;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Link;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.command.UtilityCommands;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.NullExtent;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
/**
|
||||
* Returns a {@link BlockStateHolder} for a given position.
|
||||
* - Adapts the vector apply to integer
|
||||
*/
|
||||
@Link(clazz = UtilityCommands.class, value = "patterns")
|
||||
public interface FawePattern extends Pattern {
|
||||
|
||||
@Deprecated
|
||||
default BlockStateHolder apply(Vector position) {
|
||||
throw new UnsupportedOperationException("Please use apply(extent, get, set)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link BlockStateHolder} for the given position.
|
||||
*
|
||||
* @return a block
|
||||
*/
|
||||
@Override
|
||||
boolean apply(Extent extent, Vector get, Vector set) throws WorldEditException;
|
||||
}
|
||||
|
@ -19,13 +19,36 @@
|
||||
|
||||
package com.sk89q.worldedit.function.pattern;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Link;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.command.UtilityCommands;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.NullExtent;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Return;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
/**
|
||||
* Returns a {@link BlockStateHolder} for a given position.
|
||||
* @deprecated Use FawePattern
|
||||
*/
|
||||
public interface Pattern {
|
||||
@Link(clazz = UtilityCommands.class, value = "patterns")
|
||||
@Deprecated
|
||||
public interface Pattern extends com.sk89q.worldedit.patterns.Pattern{
|
||||
|
||||
@Override
|
||||
default BaseBlock next(Vector position) {
|
||||
return new BaseBlock(apply(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock next(int x, int y, int z) {
|
||||
return new BaseBlock(apply(new Vector(x, y, z)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link BlockStateHolder} for the given position.
|
||||
@ -33,6 +56,10 @@ public interface Pattern {
|
||||
* @param position the position
|
||||
* @return a block
|
||||
*/
|
||||
@Deprecated
|
||||
BlockStateHolder apply(Vector position);
|
||||
|
||||
}
|
||||
default boolean apply(Extent extent, Vector get, Vector set) throws WorldEditException {
|
||||
return extent.setBlock(set, apply(get));
|
||||
}
|
||||
}
|
@ -1,88 +1,79 @@
|
||||
/*
|
||||
* 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.pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.object.collection.RandomCollection;
|
||||
import com.boydti.fawe.object.random.SimpleRandom;
|
||||
import com.boydti.fawe.object.random.TrueRandom;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Uses a random pattern of a weighted list of patterns.
|
||||
*/
|
||||
public class RandomPattern extends AbstractPattern {
|
||||
|
||||
private final Random random = new Random();
|
||||
private List<Chance> patterns = new ArrayList<>();
|
||||
private double max = 0;
|
||||
private final SimpleRandom random;
|
||||
private Map<Pattern, Double> weights = new HashMap<>();
|
||||
private RandomCollection<Pattern> collection;
|
||||
private LinkedHashSet<Pattern> patterns = new LinkedHashSet<>();
|
||||
|
||||
public RandomPattern() {
|
||||
this(new TrueRandom());
|
||||
}
|
||||
|
||||
public RandomPattern(SimpleRandom random) {
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a pattern to the weight list of patterns.
|
||||
*
|
||||
* <p>
|
||||
* <p>The probability for the pattern added is chance / max where max is
|
||||
* the sum of the probabilities of all added patterns.</p>
|
||||
*
|
||||
* @param pattern the pattern
|
||||
* @param chance the chance, which can be any positive number
|
||||
* @param chance the chance, which can be any positive number
|
||||
*/
|
||||
public void add(Pattern pattern, double chance) {
|
||||
checkNotNull(pattern);
|
||||
patterns.add(new Chance(pattern, chance));
|
||||
max += chance;
|
||||
Double existingWeight = weights.get(pattern);
|
||||
if (existingWeight != null) chance += existingWeight;
|
||||
weights.put(pattern, chance);
|
||||
collection = RandomCollection.of(weights, random);
|
||||
this.patterns.add(pattern);
|
||||
}
|
||||
|
||||
public Set<Pattern> getPatterns() {
|
||||
return patterns;
|
||||
}
|
||||
|
||||
public RandomCollection<Pattern> getCollection() {
|
||||
return collection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockStateHolder apply(Vector position) {
|
||||
double r = random.nextDouble();
|
||||
double offset = 0;
|
||||
|
||||
for (Chance chance : patterns) {
|
||||
if (r <= (offset + chance.getChance()) / max) {
|
||||
return chance.getPattern().apply(position);
|
||||
}
|
||||
offset += chance.getChance();
|
||||
}
|
||||
|
||||
throw new RuntimeException("ProportionalFillPattern");
|
||||
public BlockStateHolder apply(Vector get) {
|
||||
return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(get);
|
||||
}
|
||||
|
||||
private static class Chance {
|
||||
private Pattern pattern;
|
||||
private double chance;
|
||||
|
||||
private Chance(Pattern pattern, double chance) {
|
||||
this.pattern = pattern;
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
public Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public double getChance() {
|
||||
return chance;
|
||||
}
|
||||
@Override
|
||||
public boolean apply(Extent extent, Vector set, Vector get) throws WorldEditException {
|
||||
return collection.next(get.getBlockX(), get.getBlockY(), get.getBlockZ()).apply(extent, set, get);
|
||||
}
|
||||
|
||||
}
|
||||
public static Class<?> inject() {
|
||||
return RandomPattern.class;
|
||||
}
|
||||
|
||||
}
|
@ -19,11 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Returns the blocks from {@link Extent}, repeating when out of bounds.
|
||||
@ -89,7 +90,6 @@ public class RepeatingExtentPattern extends AbstractPattern {
|
||||
int x = base.getBlockX() % size.getBlockX();
|
||||
int y = base.getBlockY() % size.getBlockY();
|
||||
int z = base.getBlockZ() % size.getBlockZ();
|
||||
return extent.getFullBlock(new Vector(x, y, z));
|
||||
return extent.getBlock(new Vector(x, y, z));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.FlatRegionFunction;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Offsets the position parameter by adding a given offset vector.
|
||||
*/
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Offsets the position parameter by adding a given offset vector.
|
||||
*/
|
||||
|
@ -1,190 +1,221 @@
|
||||
/*
|
||||
* 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.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.example.MappedFaweQueue;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.boydti.fawe.object.IntegerTrio;
|
||||
import com.boydti.fawe.object.collection.BlockVectorSet;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Performs a breadth-first search starting from points added with
|
||||
* {@link #visit(com.sk89q.worldedit.Vector)}. The search continues
|
||||
* to a certain adjacent point provided that the method
|
||||
* {@link #isVisitable(com.sk89q.worldedit.Vector, com.sk89q.worldedit.Vector)}
|
||||
* returns true for that point.
|
||||
*
|
||||
* <p>As an abstract implementation, this class can be used to implement
|
||||
* functionality that starts at certain points and extends outward from
|
||||
* those points.</p>
|
||||
*/
|
||||
public abstract class BreadthFirstSearch implements Operation {
|
||||
|
||||
private final RegionFunction function;
|
||||
private final Queue<BlockVector> queue = new ArrayDeque<>();
|
||||
private final Set<BlockVector> visited = new HashSet<>();
|
||||
private final List<Vector> directions = new ArrayList<>();
|
||||
private int affected = 0;
|
||||
public static final Vector[] DEFAULT_DIRECTIONS = new Vector[6];
|
||||
public static final Vector[] DIAGONAL_DIRECTIONS;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param function the function to apply to visited blocks
|
||||
*/
|
||||
protected BreadthFirstSearch(RegionFunction function) {
|
||||
checkNotNull(function);
|
||||
this.function = function;
|
||||
addAxes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of directions will be visited.
|
||||
*
|
||||
* <p>Directions are {@link com.sk89q.worldedit.Vector}s that determine
|
||||
* what adjacent points area available. Vectors should not be
|
||||
* unit vectors. An example of a valid direction is
|
||||
* {@code new Vector(1, 0, 1)}.</p>
|
||||
*
|
||||
* <p>The list of directions can be cleared.</p>
|
||||
*
|
||||
* @return the list of directions
|
||||
*/
|
||||
protected Collection<Vector> getDirections() {
|
||||
return directions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the directions along the axes as directions to visit.
|
||||
*/
|
||||
protected void addAxes() {
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
directions.add(new Vector(0, 1, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(0, 0, -1));
|
||||
directions.add(new Vector(0, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the diagonal directions as directions to visit.
|
||||
*/
|
||||
protected void addDiagonal() {
|
||||
directions.add(new Vector(1, 0, 1));
|
||||
directions.add(new Vector(-1, 0, -1));
|
||||
directions.add(new Vector(1, 0, -1));
|
||||
directions.add(new Vector(-1, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given location to the list of locations to visit, provided
|
||||
* that it has not been visited. The position passed to this method
|
||||
* will still be visited even if it fails
|
||||
* {@link #isVisitable(com.sk89q.worldedit.Vector, com.sk89q.worldedit.Vector)}.
|
||||
*
|
||||
* <p>This method should be used before the search begins, because if
|
||||
* the position <em>does</em> fail the test, and the search has already
|
||||
* visited it (because it is connected to another root point),
|
||||
* the search will mark the position as "visited" and a call to this
|
||||
* method will do nothing.</p>
|
||||
*
|
||||
* @param position the position
|
||||
*/
|
||||
public void visit(Vector position) {
|
||||
BlockVector blockVector = position.toBlockVector();
|
||||
if (!visited.contains(blockVector)) {
|
||||
queue.add(blockVector);
|
||||
visited.add(blockVector);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to visit the given 'to' location.
|
||||
*
|
||||
* @param from the origin block
|
||||
* @param to the block under question
|
||||
*/
|
||||
private void visit(Vector from, Vector to) {
|
||||
BlockVector blockVector = to.toBlockVector();
|
||||
if (!visited.contains(blockVector)) {
|
||||
visited.add(blockVector);
|
||||
if (isVisitable(from, to)) {
|
||||
queue.add(blockVector);
|
||||
static {
|
||||
DEFAULT_DIRECTIONS[0] = (new MutableBlockVector(0, -1, 0));
|
||||
DEFAULT_DIRECTIONS[1] = (new MutableBlockVector(0, 1, 0));
|
||||
DEFAULT_DIRECTIONS[2] = (new MutableBlockVector(-1, 0, 0));
|
||||
DEFAULT_DIRECTIONS[3] = (new MutableBlockVector(1, 0, 0));
|
||||
DEFAULT_DIRECTIONS[4] = (new MutableBlockVector(0, 0, -1));
|
||||
DEFAULT_DIRECTIONS[5] = (new MutableBlockVector(0, 0, 1));
|
||||
List<MutableBlockVector> list = new ArrayList<>();
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
if (x != 0 || y != 0 || z != 0) {
|
||||
MutableBlockVector pos = new MutableBlockVector(x, y, z);
|
||||
if (!list.contains(pos)) {
|
||||
list.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(list, new Comparator<Vector>() {
|
||||
@Override
|
||||
public int compare(Vector o1, Vector o2) {
|
||||
return (int) Math.signum(o1.lengthSq() - o2.lengthSq());
|
||||
}
|
||||
});
|
||||
DIAGONAL_DIRECTIONS = list.toArray(new Vector[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given 'to' block should be visited, starting from the
|
||||
* 'from' block.
|
||||
*
|
||||
* @param from the origin block
|
||||
* @param to the block under question
|
||||
* @return true if the 'to' block should be visited
|
||||
*/
|
||||
protected abstract boolean isVisitable(Vector from, Vector to);
|
||||
private final RegionFunction function;
|
||||
private List<Vector> directions = new ArrayList<>();
|
||||
private BlockVectorSet visited;
|
||||
private final MappedFaweQueue mFaweQueue;
|
||||
private BlockVectorSet queue;
|
||||
private int currentDepth = 0;
|
||||
private final int maxDepth;
|
||||
private int affected = 0;
|
||||
private int maxBranch = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
*
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
public BreadthFirstSearch(final RegionFunction function) {
|
||||
this(function, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public BreadthFirstSearch(final RegionFunction function, int maxDepth) {
|
||||
this(function, maxDepth, null);
|
||||
}
|
||||
|
||||
public BreadthFirstSearch(final RegionFunction function, int maxDepth, HasFaweQueue faweQueue) {
|
||||
FaweQueue fq = faweQueue != null ? faweQueue.getQueue() : null;
|
||||
this.mFaweQueue = fq instanceof MappedFaweQueue ? (MappedFaweQueue) fq : null;
|
||||
this.queue = new BlockVectorSet();
|
||||
this.visited = new BlockVectorSet();
|
||||
this.function = function;
|
||||
this.directions.addAll(Arrays.asList(DEFAULT_DIRECTIONS));
|
||||
this.maxDepth = maxDepth;
|
||||
}
|
||||
|
||||
public abstract boolean isVisitable(Vector from, Vector to);
|
||||
|
||||
public Collection<Vector> getDirections() {
|
||||
return this.directions;
|
||||
}
|
||||
|
||||
public void setDirections(List<Vector> directions) {
|
||||
this.directions = directions;
|
||||
}
|
||||
|
||||
private IntegerTrio[] getIntDirections() {
|
||||
IntegerTrio[] array = new IntegerTrio[directions.size()];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
Vector dir = directions.get(i);
|
||||
array[i] = new IntegerTrio(dir.getBlockX(), dir.getBlockY(), dir.getBlockZ());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public void visit(final Vector pos) {
|
||||
if (!isVisited(pos)) {
|
||||
isVisitable(pos, pos); // Ignore this, just to initialize mask on this point
|
||||
queue.add(pos);
|
||||
visited.add(pos);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetVisited() {
|
||||
queue.clear();
|
||||
visited.clear();
|
||||
affected = 0;
|
||||
}
|
||||
|
||||
public void setVisited(BlockVectorSet set) {
|
||||
this.visited = set;
|
||||
}
|
||||
|
||||
public BlockVectorSet getVisited() {
|
||||
return visited;
|
||||
}
|
||||
|
||||
public boolean isVisited(Vector pos) {
|
||||
return visited.contains(pos);
|
||||
}
|
||||
|
||||
public void setMaxBranch(int maxBranch) {
|
||||
this.maxBranch = maxBranch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
Vector position;
|
||||
|
||||
while ((position = queue.poll()) != null) {
|
||||
if (function.apply(position)) {
|
||||
affected++;
|
||||
MutableBlockVector mutable = new MutableBlockVector();
|
||||
MutableBlockVector mutable2 = new MutableBlockVector();
|
||||
boolean shouldTrim = false;
|
||||
IntegerTrio[] dirs = getIntDirections();
|
||||
BlockVectorSet tempQueue = new BlockVectorSet();
|
||||
BlockVectorSet chunkLoadSet = new BlockVectorSet();
|
||||
for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) {
|
||||
if (mFaweQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) {
|
||||
int cx = Integer.MIN_VALUE;
|
||||
int cz = Integer.MIN_VALUE;
|
||||
for (Vector from : queue) {
|
||||
for (IntegerTrio direction : dirs) {
|
||||
int x = from.getBlockX() + direction.x;
|
||||
int z = from.getBlockZ() + direction.z;
|
||||
if (cx != (cx = x >> 4) || cz != (cz = z >> 4)) {
|
||||
int y = from.getBlockY() + direction.y;
|
||||
if (y < 0 || y >= 256) {
|
||||
continue;
|
||||
}
|
||||
if (!visited.contains(x, y, z)) {
|
||||
chunkLoadSet.add(cx, 0, cz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Vector chunk : chunkLoadSet) {
|
||||
mFaweQueue.queueChunkLoad(chunk.getBlockX(), chunk.getBlockZ());
|
||||
}
|
||||
}
|
||||
for (Vector from : queue) {
|
||||
if (function.apply(from)) affected++;
|
||||
for (int i = 0, j = 0; i < dirs.length && j < maxBranch; i++) {
|
||||
IntegerTrio direction = dirs[i];
|
||||
int y = from.getBlockY() + direction.y;
|
||||
if (y < 0 || y >= 256) {
|
||||
continue;
|
||||
}
|
||||
int x = from.getBlockX() + direction.x;
|
||||
int z = from.getBlockZ() + direction.z;
|
||||
if (!visited.contains(x, y, z)) {
|
||||
mutable2.mutX(x);
|
||||
mutable2.mutY(y);
|
||||
mutable2.mutZ(z);
|
||||
if (isVisitable(from, mutable2)) {
|
||||
j++;
|
||||
visited.add(x, y, z);
|
||||
tempQueue.add(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentDepth == maxDepth) {
|
||||
break;
|
||||
}
|
||||
int size = queue.size();
|
||||
BlockVectorSet tmp = queue;
|
||||
queue = tempQueue;
|
||||
tmp.clear();
|
||||
chunkLoadSet.clear();
|
||||
tempQueue = tmp;
|
||||
|
||||
for (Vector dir : directions) {
|
||||
visit(position, position.add(dir));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getDepth() {
|
||||
return currentDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
messages.add(BBC.VISITOR_BLOCK.format(getAffected()));
|
||||
}
|
||||
|
||||
public int getAffected() {
|
||||
return this.affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
messages.add(getAffected() + " blocks affected");
|
||||
public static Class<?> inject() {
|
||||
return BreadthFirstSearch.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.visitor;
|
||||
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.sk89q.worldedit.MutableBlockVector;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Visits adjacent points on the same X-Z plane as long as the points
|
||||
* pass the given mask, and then executes the provided region
|
||||
* function on the entire column.
|
||||
* <p>
|
||||
* <p>This is used by {@code //fill}.</p>
|
||||
*/
|
||||
public class DirectionalVisitor extends RecursiveVisitor {
|
||||
|
||||
private final Vector origin;
|
||||
private final Vector dirVec;
|
||||
|
||||
public DirectionalVisitor(Mask mask, RegionFunction function, Vector origin, Vector direction) {
|
||||
this(mask, function, origin, direction, Integer.MAX_VALUE, null);
|
||||
}
|
||||
|
||||
public DirectionalVisitor(Mask mask, RegionFunction function, Vector origin, Vector direction, int distance, HasFaweQueue hasFaweQueue) {
|
||||
super(mask, function, distance, hasFaweQueue);
|
||||
checkNotNull(mask);
|
||||
this.origin = origin;
|
||||
this.dirVec = new MutableBlockVector(direction);
|
||||
final Collection<Vector> directions = this.getDirections();
|
||||
directions.clear();
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
directions.add(new Vector(0, 0, 1));
|
||||
directions.add(new Vector(0, 0, -1));
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
directions.add(new Vector(0, 1, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisitable(final Vector from, final Vector to) {
|
||||
int dx = to.getBlockX() - from.getBlockX();
|
||||
int dz = to.getBlockZ() - from.getBlockZ();
|
||||
int dy = to.getBlockY() - from.getBlockY();
|
||||
|
||||
if (dx != 0) {
|
||||
if (dirVec.getBlockX() != 0 && dirVec.getBlockX() != dx) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (dy != 0) {
|
||||
if (dirVec.getBlockY() != 0 && dirVec.getBlockY() != dy) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (dz != 0) {
|
||||
if (dirVec.getBlockZ() != 0 && dirVec.getBlockZ() != dz) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.isVisitable(from, to);
|
||||
}
|
||||
}
|
@ -19,39 +19,42 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Visits adjacent points on the same X-Z plane as long as the points
|
||||
* pass the given mask, and then executes the provided region
|
||||
* function on the entire column.
|
||||
*
|
||||
* <p>
|
||||
* <p>This is used by {@code //fill}.</p>
|
||||
*/
|
||||
public class DownwardVisitor extends RecursiveVisitor {
|
||||
|
||||
private int baseY;
|
||||
private final int baseY;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param baseY the base Y
|
||||
* @param baseY the base Y
|
||||
*/
|
||||
public DownwardVisitor(Mask mask, RegionFunction function, int baseY) {
|
||||
super(mask, function);
|
||||
this(mask, function, baseY, Integer.MAX_VALUE, null);
|
||||
}
|
||||
|
||||
public DownwardVisitor(Mask mask, RegionFunction function, int baseY, int depth, HasFaweQueue hasFaweQueue) {
|
||||
super(mask, function, depth, hasFaweQueue);
|
||||
checkNotNull(mask);
|
||||
|
||||
this.baseY = baseY;
|
||||
|
||||
Collection<Vector> directions = getDirections();
|
||||
final Collection<Vector> directions = this.getDirections();
|
||||
directions.clear();
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
@ -61,8 +64,12 @@ public class DownwardVisitor extends RecursiveVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(Vector from, Vector to) {
|
||||
int fromY = from.getBlockY();
|
||||
return (fromY == baseY || to.subtract(from).getBlockY() < 0) && super.isVisitable(from, to);
|
||||
public boolean isVisitable(final Vector from, final Vector to) {
|
||||
final int fromY = from.getBlockY();
|
||||
return ((fromY == this.baseY) || (to.getBlockY() - from.getBlockY() < 0)) && super.isVisitable(from, to);
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return DownwardVisitor.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,25 +19,27 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.function.EntityFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Visits entities as provided by an {@code Iterator}.
|
||||
*/
|
||||
public class EntityVisitor implements Operation {
|
||||
|
||||
private final Iterator<? extends Entity> iterator;
|
||||
private final EntityFunction function;
|
||||
private int affected = 0;
|
||||
private final Iterator<? extends Entity> iterator;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -45,11 +47,12 @@ public class EntityVisitor implements Operation {
|
||||
* @param iterator the iterator
|
||||
* @param function the function
|
||||
*/
|
||||
public EntityVisitor(Iterator<? extends Entity> iterator, EntityFunction function) {
|
||||
public EntityVisitor(final Iterator<? extends Entity> iterator, final EntityFunction function) {
|
||||
checkNotNull(iterator);
|
||||
checkNotNull(function);
|
||||
this.iterator = iterator;
|
||||
|
||||
this.function = function;
|
||||
this.iterator = iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,17 +61,16 @@ public class EntityVisitor implements Operation {
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
return this.affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
while (iterator.hasNext()) {
|
||||
if (function.apply(iterator.next())) {
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
while (this.iterator.hasNext()) {
|
||||
if (this.function.apply(this.iterator.next())) {
|
||||
affected++;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -77,8 +79,11 @@ public class EntityVisitor implements Operation {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
messages.add(getAffected() + " entities affected");
|
||||
public void addStatusMessages(final List<String> messages) {
|
||||
messages.add(BBC.VISITOR_ENTITY.format(getAffected()));
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,38 +19,53 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
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;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.regions.FlatRegion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Applies region functions to columns in a {@link FlatRegion}.
|
||||
*/
|
||||
public class FlatRegionVisitor implements Operation {
|
||||
|
||||
private final FlatRegion flatRegion;
|
||||
private final FlatRegionFunction function;
|
||||
private MappedFaweQueue queue;
|
||||
private int affected = 0;
|
||||
private final Iterable<Vector2D> iterator;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion a flat region
|
||||
* @param function a function to apply to columns
|
||||
* @param function a function to apply to columns
|
||||
*/
|
||||
public FlatRegionVisitor(FlatRegion flatRegion, FlatRegionFunction function) {
|
||||
public FlatRegionVisitor(final FlatRegion flatRegion, final FlatRegionFunction function) {
|
||||
checkNotNull(flatRegion);
|
||||
checkNotNull(function);
|
||||
|
||||
this.flatRegion = flatRegion;
|
||||
this.function = function;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,17 +74,20 @@ public class FlatRegionVisitor implements Operation {
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
return this.affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
for (Vector2D pt : flatRegion.asFlatRegion()) {
|
||||
if (function.apply(pt)) {
|
||||
affected++;
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -78,9 +96,12 @@ public class FlatRegionVisitor implements Operation {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
messages.add(getAffected() + " columns affected");
|
||||
public void addStatusMessages(final List<String> messages) {
|
||||
messages.add(BBC.VISITOR_FLAT.format(getAffected()));
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
|
||||
public class IntersectRegionFunction implements RegionFunction {
|
||||
private final RegionFunction[] functions;
|
||||
|
||||
public IntersectRegionFunction(RegionFunction... functions) {
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
boolean ret = false;
|
||||
for (RegionFunction function : functions) {
|
||||
if (!function.apply(position)) {
|
||||
return ret;
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -19,9 +19,6 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
@ -29,44 +26,48 @@ import com.sk89q.worldedit.function.LayerFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.regions.FlatRegion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Visits the layers within a region.
|
||||
*
|
||||
* <p>
|
||||
* <p>This class works by iterating over all the columns in a {@link FlatRegion},
|
||||
* finding the first ground block in each column (searching from a given
|
||||
* 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 FlatRegion flatRegion;
|
||||
private final LayerFunction function;
|
||||
private Mask2D mask = Masks.alwaysTrue2D();
|
||||
private int minY;
|
||||
private int maxY;
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
private final Iterable<Vector2D> iterator;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion the flat region to visit
|
||||
* @param minY the minimum Y to stop the search at
|
||||
* @param maxY the maximum Y to begin the search at
|
||||
* @param function the layer function to apply t blocks
|
||||
* @param minY the minimum Y to stop the search at
|
||||
* @param maxY the maximum Y to begin the search at
|
||||
* @param function the layer function to apply t blocks
|
||||
*/
|
||||
public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function) {
|
||||
public LayerVisitor(final FlatRegion flatRegion, final int minY, final int maxY, final LayerFunction function) {
|
||||
checkNotNull(flatRegion);
|
||||
checkArgument(minY <= maxY, "minY <= maxY required");
|
||||
checkNotNull(function);
|
||||
|
||||
this.flatRegion = flatRegion;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.function = function;
|
||||
this.iterator = flatRegion.asFlatRegion();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,7 +77,7 @@ public class LayerVisitor implements Operation {
|
||||
* @return a 2D mask
|
||||
*/
|
||||
public Mask2D getMask() {
|
||||
return mask;
|
||||
return this.mask;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,42 +86,41 @@ public class LayerVisitor implements Operation {
|
||||
*
|
||||
* @param mask a 2D mask
|
||||
*/
|
||||
public void setMask(Mask2D mask) {
|
||||
public void setMask(final Mask2D mask) {
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
for (Vector2D column : flatRegion.asFlatRegion()) {
|
||||
if (!mask.test(column)) {
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
for (final Vector2D column : this.iterator) {
|
||||
if (!this.mask.test(column)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Abort if we are underground
|
||||
if (function.isGround(column.toVector(maxY + 1))) {
|
||||
if (this.function.isGround(column.toVector(this.maxY + 1))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
int groundY = 0;
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
Vector test = column.toVector(y);
|
||||
for (int y = this.maxY; y >= this.minY; --y) {
|
||||
final Vector test = column.toVector(y);
|
||||
if (!found) {
|
||||
if (function.isGround(test)) {
|
||||
if (this.function.isGround(test)) {
|
||||
found = true;
|
||||
groundY = y;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if (!function.apply(test, groundY - y)) {
|
||||
if (!this.function.apply(test, groundY - y)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -129,7 +129,10 @@ public class LayerVisitor implements Operation {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
public void addStatusMessages(final List<String> messages) {
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
@ -33,12 +33,17 @@ public class NonRisingVisitor extends RecursiveVisitor {
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
*/
|
||||
|
||||
public NonRisingVisitor(Mask mask, RegionFunction function) {
|
||||
super(mask, function);
|
||||
Collection<Vector> directions = getDirections();
|
||||
this(mask, function, Integer.MAX_VALUE, null);
|
||||
}
|
||||
|
||||
public NonRisingVisitor(Mask mask, RegionFunction function, int depth, HasFaweQueue hasFaweQueue) {
|
||||
super(mask, function, depth, hasFaweQueue);
|
||||
final Collection<Vector> directions = this.getDirections();
|
||||
directions.clear();
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
@ -47,4 +52,8 @@ public class NonRisingVisitor extends RecursiveVisitor {
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return NonRisingVisitor.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,12 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An implementation of an {@link BreadthFirstSearch} that uses a mask to
|
||||
* determine where a block should be visited.
|
||||
@ -33,20 +35,32 @@ public class RecursiveVisitor extends BreadthFirstSearch {
|
||||
|
||||
private final Mask mask;
|
||||
|
||||
public RecursiveVisitor(final Mask mask, final RegionFunction function) {
|
||||
this(mask, function, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
*/
|
||||
public RecursiveVisitor(Mask mask, RegionFunction function) {
|
||||
super(function);
|
||||
public RecursiveVisitor(final Mask mask, final RegionFunction function, int maxDepth) {
|
||||
this(mask, function, maxDepth, null);
|
||||
}
|
||||
|
||||
public RecursiveVisitor(final Mask mask, final RegionFunction function, int maxDepth, HasFaweQueue faweQueue) {
|
||||
super(function, maxDepth, faweQueue);
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(Vector from, Vector to) {
|
||||
return mask.test(to);
|
||||
public boolean isVisitable(final Vector from, final Vector to) {
|
||||
return this.mask.test(to);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return RecursiveVisitor.class;
|
||||
}
|
||||
}
|
@ -19,13 +19,22 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.example.MappedFaweQueue;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.HasFaweQueue;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -33,13 +42,37 @@ import java.util.List;
|
||||
*/
|
||||
public class RegionVisitor implements Operation {
|
||||
|
||||
private final Region region;
|
||||
private final RegionFunction function;
|
||||
private int affected = 0;
|
||||
public final Region region;
|
||||
public final Iterable<? extends Vector> iterable;
|
||||
public final RegionFunction function;
|
||||
private final MappedFaweQueue queue;
|
||||
private boolean useCuboidIterator = false;
|
||||
public int affected = 0;
|
||||
|
||||
/**
|
||||
* Deprecated in favor of the other constructors which will preload chunks during iteration
|
||||
*
|
||||
* @param region
|
||||
* @param function
|
||||
*/
|
||||
@Deprecated
|
||||
public RegionVisitor(Region region, RegionFunction function) {
|
||||
this.region = region;
|
||||
this(region, function, (FaweQueue) null);
|
||||
}
|
||||
|
||||
public RegionVisitor(Region region, RegionFunction function, EditSession editSession) {
|
||||
this(region, function, editSession != null ? editSession.getQueue() : null);
|
||||
}
|
||||
|
||||
public RegionVisitor(Region region, RegionFunction function, FaweQueue queue) {
|
||||
this((Iterable<BlockVector>) region, function, queue);
|
||||
}
|
||||
|
||||
public RegionVisitor(Iterable<? extends Vector> iterable, RegionFunction function, HasFaweQueue hasQueue) {
|
||||
region = (iterable instanceof Region) ? (Region) iterable : null;
|
||||
this.iterable = iterable;
|
||||
this.function = function;
|
||||
this.queue = hasQueue != null && hasQueue.getQueue() instanceof MappedFaweQueue ? (MappedFaweQueue) hasQueue.getQueue() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,28 +81,124 @@ public class RegionVisitor implements Operation {
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
return this.affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
for (Vector pt : region) {
|
||||
if (function.apply(pt)) {
|
||||
affected++;
|
||||
public Operation resume(final RunContext run) throws WorldEditException {
|
||||
if (queue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) {
|
||||
/*
|
||||
* The following is done to reduce iteration cost
|
||||
* - Preload chunks just in time
|
||||
* - Only check every 16th block for potential chunk loads
|
||||
* - Stop iteration on exception instead of hasNext
|
||||
* - Do not calculate the stacktrace as it is expensive
|
||||
*/
|
||||
Iterator<? extends Vector> trailIter = iterable.iterator();
|
||||
Iterator<? extends Vector> leadIter = iterable.iterator();
|
||||
int lastTrailChunkX = Integer.MIN_VALUE;
|
||||
int lastTrailChunkZ = Integer.MIN_VALUE;
|
||||
int lastLeadChunkX = Integer.MIN_VALUE;
|
||||
int lastLeadChunkZ = Integer.MIN_VALUE;
|
||||
int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNKS;
|
||||
try {
|
||||
for (; ; ) {
|
||||
Vector pt = trailIter.next();
|
||||
apply(pt);
|
||||
int cx = pt.getBlockX() >> 4;
|
||||
int cz = pt.getBlockZ() >> 4;
|
||||
if (cx != lastTrailChunkX || cz != lastTrailChunkZ) {
|
||||
lastTrailChunkX = cx;
|
||||
lastTrailChunkZ = cz;
|
||||
int amount;
|
||||
if (lastLeadChunkX == Integer.MIN_VALUE) {
|
||||
lastLeadChunkX = cx;
|
||||
lastLeadChunkZ = cz;
|
||||
amount = loadingTarget;
|
||||
} else {
|
||||
amount = 1;
|
||||
}
|
||||
for (int count = 0; count < amount; ) {
|
||||
Vector v = leadIter.next();
|
||||
int vcx = v.getBlockX() >> 4;
|
||||
int vcz = v.getBlockZ() >> 4;
|
||||
if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) {
|
||||
lastLeadChunkX = vcx;
|
||||
lastLeadChunkZ = vcz;
|
||||
queue.queueChunkLoad(vcx, vcz);
|
||||
count++;
|
||||
}
|
||||
// Skip the next 15 blocks
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
leadIter.next();
|
||||
}
|
||||
}
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
}
|
||||
} catch (FaweException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
try {
|
||||
for (; ; ) {
|
||||
apply(trailIter.next());
|
||||
apply(trailIter.next());
|
||||
}
|
||||
} catch (FaweException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
} else {
|
||||
for (Vector pt : iterable) {
|
||||
apply(pt);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void apply(Vector pt) throws WorldEditException {
|
||||
if (function.apply(pt)) {
|
||||
affected++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
messages.add(getAffected() + " blocks affected");
|
||||
public void addStatusMessages(final List<String> messages) {
|
||||
messages.add(BBC.VISITOR_BLOCK.format(getAffected()));
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Operations.class;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user