Update BukkitImplLoader

This commit is contained in:
MattBDev
2020-08-24 21:20:18 -04:00
parent fd8cf1ebba
commit 75a18b9d5b
45 changed files with 5618 additions and 5626 deletions

View File

@@ -1,52 +1,52 @@
/*
* 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;
/**
* Raised when an item is used when a block was expected.
*/
public class NotABlockException extends WorldEditException {
/**
* Create a new instance.
*/
public NotABlockException() {
super("This item is not a block.");
}
/**
* Create a new instance.
*
* @param input the input that was used
*/
public NotABlockException(String input) {
super("The item '" + input + "' is not a block.");
}
/**
* Create a new instance.
*
* @param input the input that was used
*/
public NotABlockException(int input) {
super("The item with the ID " + input + " is not a block.");
}
}
/*
* 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;
/**
* Raised when an item is used when a block was expected.
*/
public class NotABlockException extends WorldEditException {
/**
* Create a new instance.
*/
public NotABlockException() {
super("This item is not a block.");
}
/**
* Create a new instance.
*
* @param input the input that was used
*/
public NotABlockException(String input) {
super("The item '" + input + "' is not a block.");
}
/**
* Create a new instance.
*
* @param input the input that was used
*/
public NotABlockException(int input) {
super("The item with the ID " + input + " is not a block.");
}
}

View File

@@ -1,83 +1,83 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.blocks;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.item.ItemType;
/**
* Represents a stack of BaseItems.
*
* <p>This class may be removed in the future.</p>
*/
public class BaseItemStack extends BaseItem {
private int amount = 1;
/**
* Construct the object with default stack size of one, with damage value of 0.
*
* @param itemType The item type
*/
public BaseItemStack(ItemType itemType) {
super(itemType);
}
/**
* Construct the object.
*
* @param itemType The item type
* @param amount amount in the stack
*/
public BaseItemStack(ItemType itemType, int amount) {
super(itemType);
this.amount = amount;
}
/**
* Construct the object.
*
* @param id The item type
* @param tag Tag value
* @param amount amount in the stack
*/
public BaseItemStack(ItemType id, CompoundTag tag, int amount) {
super(id, tag);
this.amount = amount;
}
/**
* Get the number of items in the stack.
*
* @return the amount
*/
public int getAmount() {
return amount;
}
/**
* Set the amount of items in the stack.
*
* @param amount the amount to set
*/
public void setAmount(int amount) {
this.amount = amount;
}
}
/*
* 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.blocks;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.item.ItemType;
/**
* Represents a stack of BaseItems.
*
* <p>This class may be removed in the future.</p>
*/
public class BaseItemStack extends BaseItem {
private int amount = 1;
/**
* Construct the object with default stack size of one, with damage value of 0.
*
* @param itemType The item type
*/
public BaseItemStack(ItemType itemType) {
super(itemType);
}
/**
* Construct the object.
*
* @param itemType The item type
* @param amount amount in the stack
*/
public BaseItemStack(ItemType itemType, int amount) {
super(itemType);
this.amount = amount;
}
/**
* Construct the object.
*
* @param id The item type
* @param tag Tag value
* @param amount amount in the stack
*/
public BaseItemStack(ItemType id, CompoundTag tag, int amount) {
super(id, tag);
this.amount = amount;
}
/**
* Get the number of items in the stack.
*
* @return the amount
*/
public int getAmount() {
return amount;
}
/**
* Set the amount of items in the stack.
*
* @param amount the amount to set
*/
public void setAmount(int amount) {
this.amount = amount;
}
}

View File

@@ -1,250 +1,250 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.boydti.fawe.object.collection.BlockVectorSet;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.iterator.RegionIterator;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.ChunkStore;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public abstract class AbstractRegion extends AbstractSet<BlockVector3> implements Region {
protected World world;
public AbstractRegion(World world) {
this.world = world;
}
@Override
public int size() {
return com.google.common.primitives.Ints.saturatedCast(getVolume());
}
@Override
public Vector3 getCenter() {
return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2);
}
/**
* Get the iterator.
*
* @return iterator of points inside the region
*/
@Override
public Iterator<BlockVector3> iterator() {
return new RegionIterator(this);
}
@Override
public World getWorld() {
return world;
}
@Override
public void setWorld(World world) {
this.world = world;
}
@Override
public void shift(BlockVector3 change) throws RegionOperationException {
expand(change);
contract(change);
}
@Override
public AbstractRegion clone() {
try {
return (AbstractRegion) super.clone();
} catch (CloneNotSupportedException exc) {
return null;
}
}
@Override
public List<BlockVector2> polygonize(int maxPoints) {
if (maxPoints >= 0 && maxPoints < 4) {
throw new IllegalArgumentException("Cannot polygonize an AbstractRegion with no overridden polygonize method into less than 4 points.");
}
final BlockVector3 min = getMinimumPoint();
final BlockVector3 max = getMaximumPoint();
final List<BlockVector2> points = new ArrayList<>(4);
points.add(BlockVector2.at(min.getX(), min.getZ()));
points.add(BlockVector2.at(min.getX(), max.getZ()));
points.add(BlockVector2.at(max.getX(), max.getZ()));
points.add(BlockVector2.at(max.getX(), min.getZ()));
return points;
}
@Override
public long getVolume() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return (max.getX() - min.getX() + 1L)
* (max.getY() - min.getY() + 1L)
* (max.getZ() - min.getZ() + 1L);
}
/**
* Get X-size.
*
* @return width
*/
@Override
public int getWidth() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return max.getX() - min.getX() + 1;
}
/**
* Get Y-size.
*
* @return height
*/
@Override
public int getHeight() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return max.getY() - min.getY() + 1;
}
/**
* Get Z-size.
*
* @return length
*/
@Override
public int getLength() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return max.getZ() - min.getZ() + 1;
}
/**
* Get a list of chunks.
*
* @return a set of chunks
*/
@Override
public Set<BlockVector2> getChunks() {
final Set<BlockVector2> chunks = new HashSet<>();
final BlockVector3 minBlock = getMinimumPoint();
final BlockVector3 maxBlock = getMaximumPoint();
final BlockVector2 min = BlockVector2.at(minBlock.getX() >> 4, minBlock.getZ() >> 4);
final BlockVector2 max = BlockVector2.at(maxBlock.getX() >> 4, maxBlock.getZ() >> 4);
for (int X = min.getBlockX(); X <= max.getBlockX(); ++X) {
for (int Z = min.getBlockZ(); Z <= max.getBlockZ(); ++Z) {
if (containsChunk(X, Z)) {
chunks.add(BlockVector2.at(X, Z));
}
}
}
return chunks;
}
@Override
public Set<BlockVector3> getChunkCubes() {
final Set<BlockVector3> chunks = new BlockVectorSet();
final BlockVector3 min = getMinimumPoint();
final BlockVector3 max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
if (!contains(BlockVector3.at(x, y, z))) {
continue;
}
chunks.add(BlockVector3.at(
x >> ChunkStore.CHUNK_SHIFTS,
y >> ChunkStore.CHUNK_SHIFTS,
z >> ChunkStore.CHUNK_SHIFTS
));
}
}
}
return chunks;
}
// Sub-class utilities
protected final int getWorldMinY() {
return world == null ? 0 : world.getMinY();
}
protected final int getWorldMaxY() {
return world == null ? 255 : world.getMaxY();
}
@Override
public int hashCode() {
int worldHash = this.world == null ? 7 : this.world.hashCode();
int result = worldHash ^ (worldHash >>> 32);
result = 31 * result + this.getMinimumPoint().hashCode();
result = 31 * result + this.getMaximumPoint().hashCode();
result = (int) (31 * result + this.getVolume());
return result;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Region)) {
return false;
}
Region region = ((Region) o);
if (Objects.equals(this.getWorld(), region.getWorld())
&& this.getMinimumPoint().equals(region.getMinimumPoint())
&& this.getMaximumPoint().equals(region.getMaximumPoint())
&& this.getVolume() == region.getVolume()) {
return true;
}
return false;
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.boydti.fawe.object.collection.BlockVectorSet;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.iterator.RegionIterator;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.ChunkStore;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public abstract class AbstractRegion extends AbstractSet<BlockVector3> implements Region {
protected World world;
public AbstractRegion(World world) {
this.world = world;
}
@Override
public int size() {
return com.google.common.primitives.Ints.saturatedCast(getVolume());
}
@Override
public Vector3 getCenter() {
return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2);
}
/**
* Get the iterator.
*
* @return iterator of points inside the region
*/
@Override
public Iterator<BlockVector3> iterator() {
return new RegionIterator(this);
}
@Override
public World getWorld() {
return world;
}
@Override
public void setWorld(World world) {
this.world = world;
}
@Override
public void shift(BlockVector3 change) throws RegionOperationException {
expand(change);
contract(change);
}
@Override
public AbstractRegion clone() {
try {
return (AbstractRegion) super.clone();
} catch (CloneNotSupportedException exc) {
return null;
}
}
@Override
public List<BlockVector2> polygonize(int maxPoints) {
if (maxPoints >= 0 && maxPoints < 4) {
throw new IllegalArgumentException("Cannot polygonize an AbstractRegion with no overridden polygonize method into less than 4 points.");
}
final BlockVector3 min = getMinimumPoint();
final BlockVector3 max = getMaximumPoint();
final List<BlockVector2> points = new ArrayList<>(4);
points.add(BlockVector2.at(min.getX(), min.getZ()));
points.add(BlockVector2.at(min.getX(), max.getZ()));
points.add(BlockVector2.at(max.getX(), max.getZ()));
points.add(BlockVector2.at(max.getX(), min.getZ()));
return points;
}
@Override
public long getVolume() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return (max.getX() - min.getX() + 1L)
* (max.getY() - min.getY() + 1L)
* (max.getZ() - min.getZ() + 1L);
}
/**
* Get X-size.
*
* @return width
*/
@Override
public int getWidth() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return max.getX() - min.getX() + 1;
}
/**
* Get Y-size.
*
* @return height
*/
@Override
public int getHeight() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return max.getY() - min.getY() + 1;
}
/**
* Get Z-size.
*
* @return length
*/
@Override
public int getLength() {
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return max.getZ() - min.getZ() + 1;
}
/**
* Get a list of chunks.
*
* @return a set of chunks
*/
@Override
public Set<BlockVector2> getChunks() {
final Set<BlockVector2> chunks = new HashSet<>();
final BlockVector3 minBlock = getMinimumPoint();
final BlockVector3 maxBlock = getMaximumPoint();
final BlockVector2 min = BlockVector2.at(minBlock.getX() >> 4, minBlock.getZ() >> 4);
final BlockVector2 max = BlockVector2.at(maxBlock.getX() >> 4, maxBlock.getZ() >> 4);
for (int X = min.getBlockX(); X <= max.getBlockX(); ++X) {
for (int Z = min.getBlockZ(); Z <= max.getBlockZ(); ++Z) {
if (containsChunk(X, Z)) {
chunks.add(BlockVector2.at(X, Z));
}
}
}
return chunks;
}
@Override
public Set<BlockVector3> getChunkCubes() {
final Set<BlockVector3> chunks = new BlockVectorSet();
final BlockVector3 min = getMinimumPoint();
final BlockVector3 max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
if (!contains(BlockVector3.at(x, y, z))) {
continue;
}
chunks.add(BlockVector3.at(
x >> ChunkStore.CHUNK_SHIFTS,
y >> ChunkStore.CHUNK_SHIFTS,
z >> ChunkStore.CHUNK_SHIFTS
));
}
}
}
return chunks;
}
// Sub-class utilities
protected final int getWorldMinY() {
return world == null ? 0 : world.getMinY();
}
protected final int getWorldMaxY() {
return world == null ? 255 : world.getMaxY();
}
@Override
public int hashCode() {
int worldHash = this.world == null ? 7 : this.world.hashCode();
int result = worldHash ^ (worldHash >>> 32);
result = 31 * result + this.getMinimumPoint().hashCode();
result = 31 * result + this.getMaximumPoint().hashCode();
result = (int) (31 * result + this.getVolume());
return result;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Region)) {
return false;
}
Region region = ((Region) o);
if (Objects.equals(this.getWorld(), region.getWorld())
&& this.getMinimumPoint().equals(region.getMinimumPoint())
&& this.getMaximumPoint().equals(region.getMaximumPoint())
&& this.getVolume() == region.getVolume()) {
return true;
}
return false;
}
}

View File

@@ -1,336 +1,336 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.polyhedron.Edge;
import com.sk89q.worldedit.regions.polyhedron.Triangle;
import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
public class ConvexPolyhedralRegion extends AbstractRegion {
/**
* Vertices that are contained in the convex hull.
*/
private final Set<BlockVector3> vertices = new LinkedHashSet<>();
/**
* Triangles that form the convex hull.
*/
private final List<Triangle> triangles = new ArrayList<>();
/**
* Vertices that are coplanar to the first 3 vertices.
*/
private final Set<BlockVector3> vertexBacklog = new LinkedHashSet<>();
/**
* Minimum point of the axis-aligned bounding box.
*/
private BlockVector3 minimumPoint;
/**
* Maximum point of the axis-aligned bounding box.
*/
private BlockVector3 maximumPoint;
/**
* Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center.
*/
private BlockVector3 centerAccum = BlockVector3.ZERO;
/**
* The last triangle that caused a {@link #contains(BlockVector3)}} to classify a point as "outside". Used for optimization.
*/
private Triangle lastTriangle;
/**
* Constructs an empty mesh, containing no vertices or triangles.
*
* @param world the world
*/
public ConvexPolyhedralRegion(@Nullable World world) {
super(world);
}
/**
* Constructs an independent copy of the given region.
*
* @param region the region to copy
*/
public ConvexPolyhedralRegion(ConvexPolyhedralRegion region) {
this(region.world);
vertices.addAll(region.vertices);
triangles.addAll(region.triangles);
vertexBacklog.addAll(region.vertexBacklog);
minimumPoint = region.minimumPoint;
maximumPoint = region.maximumPoint;
centerAccum = region.centerAccum;
lastTriangle = region.lastTriangle;
}
/**
* Clears the region, removing all vertices and triangles.
*/
public void clear() {
vertices.clear();
triangles.clear();
vertexBacklog.clear();
minimumPoint = null;
maximumPoint = null;
centerAccum = BlockVector3.ZERO;
lastTriangle = null;
}
/**
* Add a vertex to the region.
*
* @param vertex the vertex
* @return true, if something changed.
*/
public boolean addVertex(BlockVector3 vertex) {
checkNotNull(vertex);
lastTriangle = null; // Probably not necessary
if (vertices.contains(vertex)) {
return false;
}
Vector3 vertexD = vertex.toVector3();
if (vertices.size() == 3) {
if (vertexBacklog.contains(vertex)) {
return false;
}
if (containsRaw(vertexD)) {
return vertexBacklog.add(vertex);
}
}
vertices.add(vertex);
centerAccum = centerAccum.add(vertex);
if (minimumPoint == null) {
minimumPoint = maximumPoint = vertex;
} else {
minimumPoint = minimumPoint.getMinimum(vertex);
maximumPoint = maximumPoint.getMaximum(vertex);
}
switch (vertices.size()) {
case 0:
case 1:
case 2:
// Incomplete, can't make a mesh yet
return true;
case 3:
// Generate minimal mesh to start from
final BlockVector3[] v = vertices.toArray(new BlockVector3[0]);
triangles.add((new Triangle(v[0].toVector3(), v[1].toVector3(), v[2].toVector3())));
triangles.add((new Triangle(v[0].toVector3(), v[2].toVector3(), v[1].toVector3())));
return true;
default:
break;
}
// Look for triangles that face the vertex and remove them
final Set<Edge> borderEdges = new LinkedHashSet<>();
for (Iterator<Triangle> it = triangles.iterator(); it.hasNext(); ) {
final Triangle triangle = it.next();
// If the triangle can't be seen, it's not relevant
if (!triangle.above(vertexD)) {
continue;
}
// Remove the triangle from the mesh
it.remove();
// ...and remember its edges
for (int i = 0; i < 3; ++i) {
final Edge edge = triangle.getEdge(i);
if (borderEdges.remove(edge)) {
continue;
}
borderEdges.add(edge);
}
}
// Add triangles between the remembered edges and the new vertex.
for (Edge edge : borderEdges) {
triangles.add(edge.createTriangle(vertexD));
}
if (!vertexBacklog.isEmpty()) {
// Remove the new vertex
vertices.remove(vertex);
// Clone, clear and work through the backlog
final List<BlockVector3> vertexBacklog2 = new ArrayList<>(vertexBacklog);
vertexBacklog.clear();
for (BlockVector3 vertex2 : vertexBacklog2) {
addVertex(vertex2);
}
// Re-add the new vertex after the backlog.
vertices.add(vertex);
}
return true;
}
public boolean isDefined() {
return !triangles.isEmpty();
}
@Override
public BlockVector3 getMinimumPoint() {
return minimumPoint;
}
@Override
public BlockVector3 getMaximumPoint() {
return maximumPoint;
}
@Override
public Vector3 getCenter() {
return centerAccum.toVector3().divide(vertices.size());
}
@Override
public void expand(BlockVector3... changes) throws RegionOperationException {
}
@Override
public void contract(BlockVector3... changes) throws RegionOperationException {
}
@Override
public void shift(BlockVector3 change) throws RegionOperationException {
Vector3 vec = change.toVector3();
shiftCollection(vertices, change);
shiftCollection(vertexBacklog, change);
for (int i = 0; i < triangles.size(); ++i) {
final Triangle triangle = triangles.get(i);
final Vector3 v0 = vec.add(triangle.getVertex(0));
final Vector3 v1 = vec.add(triangle.getVertex(1));
final Vector3 v2 = vec.add(triangle.getVertex(2));
triangles.set(i, new Triangle(v0, v1, v2));
}
minimumPoint = change.add(minimumPoint);
maximumPoint = change.add(maximumPoint);
centerAccum = change.multiply(vertices.size()).add(centerAccum);
lastTriangle = null;
}
private static void shiftCollection(Collection<BlockVector3> collection, BlockVector3 change) {
final List<BlockVector3> tmp = new ArrayList<>(collection);
collection.clear();
for (BlockVector3 vertex : tmp) {
collection.add(change.add(vertex));
}
}
@Override
public boolean contains(BlockVector3 position) {
if (!isDefined()) {
return false;
}
final BlockVector3 min = getMinimumPoint();
final BlockVector3 max = getMaximumPoint();
if (!position.containedWithin(min, max)) {
return false;
}
return containsRaw(position.toVector3());
}
private boolean containsRaw(Vector3 pt) {
if (lastTriangle != null && lastTriangle.above(pt)) {
return false;
}
for (Triangle triangle : triangles) {
if (lastTriangle == triangle) {
continue;
}
if (triangle.above(pt)) {
lastTriangle = triangle;
return false;
}
}
return true;
}
public Collection<BlockVector3> getVertices() {
if (vertexBacklog.isEmpty()) {
return vertices;
}
final List<BlockVector3> ret = new ArrayList<>(vertices);
ret.addAll(vertexBacklog);
return ret;
}
public Collection<Triangle> getTriangles() {
return triangles;
}
@Override
public AbstractRegion clone() {
return new ConvexPolyhedralRegion(this);
}
@Override
public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) {
return false;
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.polyhedron.Edge;
import com.sk89q.worldedit.regions.polyhedron.Triangle;
import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
public class ConvexPolyhedralRegion extends AbstractRegion {
/**
* Vertices that are contained in the convex hull.
*/
private final Set<BlockVector3> vertices = new LinkedHashSet<>();
/**
* Triangles that form the convex hull.
*/
private final List<Triangle> triangles = new ArrayList<>();
/**
* Vertices that are coplanar to the first 3 vertices.
*/
private final Set<BlockVector3> vertexBacklog = new LinkedHashSet<>();
/**
* Minimum point of the axis-aligned bounding box.
*/
private BlockVector3 minimumPoint;
/**
* Maximum point of the axis-aligned bounding box.
*/
private BlockVector3 maximumPoint;
/**
* Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center.
*/
private BlockVector3 centerAccum = BlockVector3.ZERO;
/**
* The last triangle that caused a {@link #contains(BlockVector3)}} to classify a point as "outside". Used for optimization.
*/
private Triangle lastTriangle;
/**
* Constructs an empty mesh, containing no vertices or triangles.
*
* @param world the world
*/
public ConvexPolyhedralRegion(@Nullable World world) {
super(world);
}
/**
* Constructs an independent copy of the given region.
*
* @param region the region to copy
*/
public ConvexPolyhedralRegion(ConvexPolyhedralRegion region) {
this(region.world);
vertices.addAll(region.vertices);
triangles.addAll(region.triangles);
vertexBacklog.addAll(region.vertexBacklog);
minimumPoint = region.minimumPoint;
maximumPoint = region.maximumPoint;
centerAccum = region.centerAccum;
lastTriangle = region.lastTriangle;
}
/**
* Clears the region, removing all vertices and triangles.
*/
public void clear() {
vertices.clear();
triangles.clear();
vertexBacklog.clear();
minimumPoint = null;
maximumPoint = null;
centerAccum = BlockVector3.ZERO;
lastTriangle = null;
}
/**
* Add a vertex to the region.
*
* @param vertex the vertex
* @return true, if something changed.
*/
public boolean addVertex(BlockVector3 vertex) {
checkNotNull(vertex);
lastTriangle = null; // Probably not necessary
if (vertices.contains(vertex)) {
return false;
}
Vector3 vertexD = vertex.toVector3();
if (vertices.size() == 3) {
if (vertexBacklog.contains(vertex)) {
return false;
}
if (containsRaw(vertexD)) {
return vertexBacklog.add(vertex);
}
}
vertices.add(vertex);
centerAccum = centerAccum.add(vertex);
if (minimumPoint == null) {
minimumPoint = maximumPoint = vertex;
} else {
minimumPoint = minimumPoint.getMinimum(vertex);
maximumPoint = maximumPoint.getMaximum(vertex);
}
switch (vertices.size()) {
case 0:
case 1:
case 2:
// Incomplete, can't make a mesh yet
return true;
case 3:
// Generate minimal mesh to start from
final BlockVector3[] v = vertices.toArray(new BlockVector3[0]);
triangles.add((new Triangle(v[0].toVector3(), v[1].toVector3(), v[2].toVector3())));
triangles.add((new Triangle(v[0].toVector3(), v[2].toVector3(), v[1].toVector3())));
return true;
default:
break;
}
// Look for triangles that face the vertex and remove them
final Set<Edge> borderEdges = new LinkedHashSet<>();
for (Iterator<Triangle> it = triangles.iterator(); it.hasNext(); ) {
final Triangle triangle = it.next();
// If the triangle can't be seen, it's not relevant
if (!triangle.above(vertexD)) {
continue;
}
// Remove the triangle from the mesh
it.remove();
// ...and remember its edges
for (int i = 0; i < 3; ++i) {
final Edge edge = triangle.getEdge(i);
if (borderEdges.remove(edge)) {
continue;
}
borderEdges.add(edge);
}
}
// Add triangles between the remembered edges and the new vertex.
for (Edge edge : borderEdges) {
triangles.add(edge.createTriangle(vertexD));
}
if (!vertexBacklog.isEmpty()) {
// Remove the new vertex
vertices.remove(vertex);
// Clone, clear and work through the backlog
final List<BlockVector3> vertexBacklog2 = new ArrayList<>(vertexBacklog);
vertexBacklog.clear();
for (BlockVector3 vertex2 : vertexBacklog2) {
addVertex(vertex2);
}
// Re-add the new vertex after the backlog.
vertices.add(vertex);
}
return true;
}
public boolean isDefined() {
return !triangles.isEmpty();
}
@Override
public BlockVector3 getMinimumPoint() {
return minimumPoint;
}
@Override
public BlockVector3 getMaximumPoint() {
return maximumPoint;
}
@Override
public Vector3 getCenter() {
return centerAccum.toVector3().divide(vertices.size());
}
@Override
public void expand(BlockVector3... changes) throws RegionOperationException {
}
@Override
public void contract(BlockVector3... changes) throws RegionOperationException {
}
@Override
public void shift(BlockVector3 change) throws RegionOperationException {
Vector3 vec = change.toVector3();
shiftCollection(vertices, change);
shiftCollection(vertexBacklog, change);
for (int i = 0; i < triangles.size(); ++i) {
final Triangle triangle = triangles.get(i);
final Vector3 v0 = vec.add(triangle.getVertex(0));
final Vector3 v1 = vec.add(triangle.getVertex(1));
final Vector3 v2 = vec.add(triangle.getVertex(2));
triangles.set(i, new Triangle(v0, v1, v2));
}
minimumPoint = change.add(minimumPoint);
maximumPoint = change.add(maximumPoint);
centerAccum = change.multiply(vertices.size()).add(centerAccum);
lastTriangle = null;
}
private static void shiftCollection(Collection<BlockVector3> collection, BlockVector3 change) {
final List<BlockVector3> tmp = new ArrayList<>(collection);
collection.clear();
for (BlockVector3 vertex : tmp) {
collection.add(change.add(vertex));
}
}
@Override
public boolean contains(BlockVector3 position) {
if (!isDefined()) {
return false;
}
final BlockVector3 min = getMinimumPoint();
final BlockVector3 max = getMaximumPoint();
if (!position.containedWithin(min, max)) {
return false;
}
return containsRaw(position.toVector3());
}
private boolean containsRaw(Vector3 pt) {
if (lastTriangle != null && lastTriangle.above(pt)) {
return false;
}
for (Triangle triangle : triangles) {
if (lastTriangle == triangle) {
continue;
}
if (triangle.above(pt)) {
lastTriangle = triangle;
return false;
}
}
return true;
}
public Collection<BlockVector3> getVertices() {
if (vertexBacklog.isEmpty()) {
return vertices;
}
final List<BlockVector3> ret = new ArrayList<>(vertices);
ret.addAll(vertexBacklog);
return ret;
}
public Collection<Triangle> getTriangles() {
return triangles;
}
@Override
public AbstractRegion clone() {
return new ConvexPolyhedralRegion(this);
}
@Override
public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) {
return false;
}
}

View File

@@ -1,430 +1,430 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector2;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.geom.Polygons;
import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator;
import com.sk89q.worldedit.regions.iterator.FlatRegionIterator;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.World;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a cylindrical region.
*/
public class CylinderRegion extends AbstractRegion implements FlatRegion {
private BlockVector2 center;
private Vector2 radius;
private Vector2 radiusInverse;
private int minY;
private int maxY;
private boolean hasY = false;
/**
* Construct the region.
*/
public CylinderRegion() {
this((World) null);
}
/**
* Construct the region.
*
* @param world the world
*/
public CylinderRegion(World world) {
this(world, BlockVector3.ZERO, Vector2.ZERO, 0, 0);
hasY = false;
}
/**
* Construct the region.
*
* @param world the world
* @param center the center position
* @param radius the radius along the X and Z axes
* @param minY the minimum Y, inclusive
* @param maxY the maximum Y, inclusive
*/
public CylinderRegion(World world, BlockVector3 center, Vector2 radius, int minY, int maxY) {
super(world);
setCenter(center.toBlockVector2());
setRadius(radius);
this.minY = minY;
this.maxY = maxY;
hasY = true;
}
/**
* Construct the region.
*
* @param center the center position
* @param radius the radius along the X and Z axes
* @param minY the minimum Y, inclusive
* @param maxY the maximum Y, inclusive
*/
public CylinderRegion(BlockVector3 center, Vector2 radius, int minY, int maxY) {
super(null);
setCenter(center.toBlockVector2());
setRadius(radius);
this.minY = minY;
this.maxY = maxY;
hasY = true;
}
public CylinderRegion(CylinderRegion region) {
this(region.world, region.getCenter().toBlockPoint(), region.getRadius(), region.minY, region.maxY);
hasY = region.hasY;
}
@Override
public Vector3 getCenter() {
return center.toVector3((maxY + minY) / 2);
}
/**
* Sets the main center point of the region.
*
* @param center the center point
*/
public void setCenter(BlockVector2 center) {
this.center = center;
}
/**
* Returns the radius of the cylinder.
*
* @return the radius along the X and Z axes
*/
public Vector2 getRadius() {
return radius.subtract(0.5, 0.5);
}
/**
* Sets the radius of the cylinder.
*
* @param radius the radius along the X and Z axes
*/
public void setRadius(Vector2 radius) {
this.radius = radius.add(0.5, 0.5);
this.radiusInverse = Vector2.ONE.divide(radius);
}
/**
* Extends the radius to be at least the given radius.
*
* @param minRadius the minimum radius
*/
public void extendRadius(Vector2 minRadius) {
setRadius(minRadius.getMaximum(getRadius()));
}
/**
* Set the minimum Y.
*
* @param y the y
*/
public void setMinimumY(int y) {
hasY = true;
minY = y;
}
/**
* Se the maximum Y.
*
* @param y the y
*/
public void setMaximumY(int y) {
hasY = true;
maxY = y;
}
@Override
public BlockVector3 getMinimumPoint() {
return center.toVector2().subtract(getRadius()).toVector3(minY).toBlockPoint();
}
@Override
public BlockVector3 getMaximumPoint() {
return center.toVector2().add(getRadius()).toVector3(maxY).toBlockPoint();
}
@Override
public int getMaximumY() {
int worldMax = world != null ? world.getMaxY() - 1 : 255;
if (maxY > worldMax) {
return maxY = worldMax;
}
return maxY;
}
@Override
public int getMinimumY() {
if (minY < 0) {
return minY = 0;
}
return minY;
}
private static final BigDecimal PI = BigDecimal.valueOf(Math.PI);
@Override
public long getVolume() {
return BigDecimal.valueOf(radius.getX())
.multiply(BigDecimal.valueOf(radius.getZ()))
.multiply(PI)
.multiply(BigDecimal.valueOf(getHeight()))
.setScale(0, RoundingMode.FLOOR)
.longValue();
}
@Override
public int getWidth() {
return (int) (2 * radius.getX());
}
@Override
public int getHeight() {
return maxY - minY + 1;
}
@Override
public int getLength() {
return (int) (2 * radius.getZ());
}
private BlockVector2 calculateDiff2D(BlockVector3... changes) throws RegionOperationException {
BlockVector2 diff = BlockVector2.ZERO;
for (BlockVector3 change : changes) {
diff = diff.add(change.toBlockVector2());
}
if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) {
throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.cylinder.error.even-horizontal"));
}
return diff.divide(2).floor();
}
private BlockVector2 calculateChanges2D(BlockVector3... changes) {
BlockVector2 total = BlockVector2.ZERO;
for (BlockVector3 change : changes) {
total = total.add(change.toBlockVector2().abs());
}
return total.divide(2).floor();
}
/**
* Expand the region.
* Expand the region.
*
* @param changes array/arguments with multiple related changes
*/
@Override
public void expand(BlockVector3... changes) throws RegionOperationException {
center = center.add(calculateDiff2D(changes));
radius = radius.add(calculateChanges2D(changes).toVector2());
this.radiusInverse = Vector2.ONE.divide(radius);
for (BlockVector3 change : changes) {
int changeY = change.getBlockY();
if (changeY > 0) {
maxY += changeY;
} else {
minY += changeY;
}
}
}
/**
* Contract the region.
*
* @param changes array/arguments with multiple related changes
* @throws RegionOperationException
*/
@Override
public void contract(BlockVector3... changes) throws RegionOperationException {
center = center.subtract(calculateDiff2D(changes));
Vector2 newRadius = radius.subtract(calculateChanges2D(changes).toVector2());
radius = Vector2.at(1.5, 1.5).getMaximum(newRadius);
this.radiusInverse = Vector2.ONE.divide(radius);
for (BlockVector3 change : changes) {
int height = maxY - minY;
int changeY = change.getBlockY();
if (changeY > 0) {
minY += Math.min(height, changeY);
} else {
maxY += Math.max(-height, changeY);
}
}
}
@Override
public void shift(BlockVector3 change) throws RegionOperationException {
center = center.add(change.toBlockVector2());
int changeY = change.getBlockY();
maxY += changeY;
minY += changeY;
}
/**
* Checks to see if a point is inside this region.
*/
/* Slow and unnecessary
@Override
public boolean contains(BlockVector3 position) {
final int blockY = position.getBlockY();
if (blockY < minY || blockY > maxY) {
return false;
}
return position.toBlockVector2().subtract(center).toVector2().divide(radius).lengthSq() <= 1;
}
*/
/**
* Checks to see if a point is inside this region.
*/
@Override
public boolean contains(int x, int y, int z) {
if (y < minY || y > maxY) {
return false;
}
return contains(x, z);
}
@Override
public boolean contains(int x, int z) {
double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX();
double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ();
return dx * dx + dz * dz <= 1;
}
@Override
public boolean contains(BlockVector3 position) {
return contains(position.getX(), position.getY(), position.getZ());
}
/**
* Sets the height of the cylinder to fit the specified Y.
*
* @param y the y value
* @return true if the area was expanded
*/
public boolean setY(int y) {
if (!hasY) {
minY = y;
maxY = y;
hasY = true;
return true;
} else if (y < minY) {
minY = y;
return true;
} else if (y > maxY) {
maxY = y;
return true;
}
return false;
}
@Override
public Iterator<BlockVector3> iterator() {
return new FlatRegion3DIterator(this);
}
@Override
public Iterable<BlockVector2> asFlatRegion() {
return () -> new FlatRegionIterator(CylinderRegion.this);
}
/**
* Returns string representation in the format.
* "(centerX, centerZ) - (radiusX, radiusZ) - (minY, maxY)"
*
* @return string
*/
@Override
public String toString() {
return center + " - " + radius + "(" + minY + ", " + maxY + ")";
}
@Override
public CylinderRegion clone() {
return (CylinderRegion) super.clone();
}
@Override
public List<BlockVector2> polygonize(int maxPoints) {
return Polygons.polygonizeCylinder(center, radius, maxPoints);
}
/**
* Return a new instance with the given center and radius in the X and Z
* axes with a Y that extends from the bottom of the extent to the top
* of the extent.
*
* @param extent the extent
* @param center the center position
* @param radius the radius in the X and Z axes
* @return a region
*/
public static CylinderRegion createRadius(Extent extent, BlockVector3 center, double radius) {
checkNotNull(extent);
checkNotNull(center);
Vector2 radiusVec = Vector2.at(radius, radius);
int minY = extent.getMinimumPoint().getBlockY();
int maxY = extent.getMaximumPoint().getBlockY();
return new CylinderRegion(center, radiusVec, minY, maxY);
}
@Override
public void filter(final IChunk chunk, final Filter filter, final ChunkFilterBlock block,
final IChunkGet get, final IChunkSet set, boolean full) {
int bcx = chunk.getX() >> 4;
int bcz = chunk.getZ() >> 4;
int tcx = bcx + 15;
int tcz = bcz + 15;
if (contains(bcx, bcz) && contains(tcx, tcz)) {
filter(chunk, filter, block, get, set, minY, maxY, full);
return;
}
super.filter(chunk, filter, block, get, set, full);
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector2;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.geom.Polygons;
import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator;
import com.sk89q.worldedit.regions.iterator.FlatRegionIterator;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.World;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a cylindrical region.
*/
public class CylinderRegion extends AbstractRegion implements FlatRegion {
private BlockVector2 center;
private Vector2 radius;
private Vector2 radiusInverse;
private int minY;
private int maxY;
private boolean hasY = false;
/**
* Construct the region.
*/
public CylinderRegion() {
this((World) null);
}
/**
* Construct the region.
*
* @param world the world
*/
public CylinderRegion(World world) {
this(world, BlockVector3.ZERO, Vector2.ZERO, 0, 0);
hasY = false;
}
/**
* Construct the region.
*
* @param world the world
* @param center the center position
* @param radius the radius along the X and Z axes
* @param minY the minimum Y, inclusive
* @param maxY the maximum Y, inclusive
*/
public CylinderRegion(World world, BlockVector3 center, Vector2 radius, int minY, int maxY) {
super(world);
setCenter(center.toBlockVector2());
setRadius(radius);
this.minY = minY;
this.maxY = maxY;
hasY = true;
}
/**
* Construct the region.
*
* @param center the center position
* @param radius the radius along the X and Z axes
* @param minY the minimum Y, inclusive
* @param maxY the maximum Y, inclusive
*/
public CylinderRegion(BlockVector3 center, Vector2 radius, int minY, int maxY) {
super(null);
setCenter(center.toBlockVector2());
setRadius(radius);
this.minY = minY;
this.maxY = maxY;
hasY = true;
}
public CylinderRegion(CylinderRegion region) {
this(region.world, region.getCenter().toBlockPoint(), region.getRadius(), region.minY, region.maxY);
hasY = region.hasY;
}
@Override
public Vector3 getCenter() {
return center.toVector3((maxY + minY) / 2);
}
/**
* Sets the main center point of the region.
*
* @param center the center point
*/
public void setCenter(BlockVector2 center) {
this.center = center;
}
/**
* Returns the radius of the cylinder.
*
* @return the radius along the X and Z axes
*/
public Vector2 getRadius() {
return radius.subtract(0.5, 0.5);
}
/**
* Sets the radius of the cylinder.
*
* @param radius the radius along the X and Z axes
*/
public void setRadius(Vector2 radius) {
this.radius = radius.add(0.5, 0.5);
this.radiusInverse = Vector2.ONE.divide(radius);
}
/**
* Extends the radius to be at least the given radius.
*
* @param minRadius the minimum radius
*/
public void extendRadius(Vector2 minRadius) {
setRadius(minRadius.getMaximum(getRadius()));
}
/**
* Set the minimum Y.
*
* @param y the y
*/
public void setMinimumY(int y) {
hasY = true;
minY = y;
}
/**
* Se the maximum Y.
*
* @param y the y
*/
public void setMaximumY(int y) {
hasY = true;
maxY = y;
}
@Override
public BlockVector3 getMinimumPoint() {
return center.toVector2().subtract(getRadius()).toVector3(minY).toBlockPoint();
}
@Override
public BlockVector3 getMaximumPoint() {
return center.toVector2().add(getRadius()).toVector3(maxY).toBlockPoint();
}
@Override
public int getMaximumY() {
int worldMax = world != null ? world.getMaxY() - 1 : 255;
if (maxY > worldMax) {
return maxY = worldMax;
}
return maxY;
}
@Override
public int getMinimumY() {
if (minY < 0) {
return minY = 0;
}
return minY;
}
private static final BigDecimal PI = BigDecimal.valueOf(Math.PI);
@Override
public long getVolume() {
return BigDecimal.valueOf(radius.getX())
.multiply(BigDecimal.valueOf(radius.getZ()))
.multiply(PI)
.multiply(BigDecimal.valueOf(getHeight()))
.setScale(0, RoundingMode.FLOOR)
.longValue();
}
@Override
public int getWidth() {
return (int) (2 * radius.getX());
}
@Override
public int getHeight() {
return maxY - minY + 1;
}
@Override
public int getLength() {
return (int) (2 * radius.getZ());
}
private BlockVector2 calculateDiff2D(BlockVector3... changes) throws RegionOperationException {
BlockVector2 diff = BlockVector2.ZERO;
for (BlockVector3 change : changes) {
diff = diff.add(change.toBlockVector2());
}
if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) {
throw new RegionOperationException(TranslatableComponent.of("worldedit.selection.cylinder.error.even-horizontal"));
}
return diff.divide(2).floor();
}
private BlockVector2 calculateChanges2D(BlockVector3... changes) {
BlockVector2 total = BlockVector2.ZERO;
for (BlockVector3 change : changes) {
total = total.add(change.toBlockVector2().abs());
}
return total.divide(2).floor();
}
/**
* Expand the region.
* Expand the region.
*
* @param changes array/arguments with multiple related changes
*/
@Override
public void expand(BlockVector3... changes) throws RegionOperationException {
center = center.add(calculateDiff2D(changes));
radius = radius.add(calculateChanges2D(changes).toVector2());
this.radiusInverse = Vector2.ONE.divide(radius);
for (BlockVector3 change : changes) {
int changeY = change.getBlockY();
if (changeY > 0) {
maxY += changeY;
} else {
minY += changeY;
}
}
}
/**
* Contract the region.
*
* @param changes array/arguments with multiple related changes
* @throws RegionOperationException
*/
@Override
public void contract(BlockVector3... changes) throws RegionOperationException {
center = center.subtract(calculateDiff2D(changes));
Vector2 newRadius = radius.subtract(calculateChanges2D(changes).toVector2());
radius = Vector2.at(1.5, 1.5).getMaximum(newRadius);
this.radiusInverse = Vector2.ONE.divide(radius);
for (BlockVector3 change : changes) {
int height = maxY - minY;
int changeY = change.getBlockY();
if (changeY > 0) {
minY += Math.min(height, changeY);
} else {
maxY += Math.max(-height, changeY);
}
}
}
@Override
public void shift(BlockVector3 change) throws RegionOperationException {
center = center.add(change.toBlockVector2());
int changeY = change.getBlockY();
maxY += changeY;
minY += changeY;
}
/**
* Checks to see if a point is inside this region.
*/
/* Slow and unnecessary
@Override
public boolean contains(BlockVector3 position) {
final int blockY = position.getBlockY();
if (blockY < minY || blockY > maxY) {
return false;
}
return position.toBlockVector2().subtract(center).toVector2().divide(radius).lengthSq() <= 1;
}
*/
/**
* Checks to see if a point is inside this region.
*/
@Override
public boolean contains(int x, int y, int z) {
if (y < minY || y > maxY) {
return false;
}
return contains(x, z);
}
@Override
public boolean contains(int x, int z) {
double dx = Math.abs(x - center.getBlockX()) * radiusInverse.getX();
double dz = Math.abs(z - center.getBlockZ()) * radiusInverse.getZ();
return dx * dx + dz * dz <= 1;
}
@Override
public boolean contains(BlockVector3 position) {
return contains(position.getX(), position.getY(), position.getZ());
}
/**
* Sets the height of the cylinder to fit the specified Y.
*
* @param y the y value
* @return true if the area was expanded
*/
public boolean setY(int y) {
if (!hasY) {
minY = y;
maxY = y;
hasY = true;
return true;
} else if (y < minY) {
minY = y;
return true;
} else if (y > maxY) {
maxY = y;
return true;
}
return false;
}
@Override
public Iterator<BlockVector3> iterator() {
return new FlatRegion3DIterator(this);
}
@Override
public Iterable<BlockVector2> asFlatRegion() {
return () -> new FlatRegionIterator(CylinderRegion.this);
}
/**
* Returns string representation in the format.
* "(centerX, centerZ) - (radiusX, radiusZ) - (minY, maxY)"
*
* @return string
*/
@Override
public String toString() {
return center + " - " + radius + "(" + minY + ", " + maxY + ")";
}
@Override
public CylinderRegion clone() {
return (CylinderRegion) super.clone();
}
@Override
public List<BlockVector2> polygonize(int maxPoints) {
return Polygons.polygonizeCylinder(center, radius, maxPoints);
}
/**
* Return a new instance with the given center and radius in the X and Z
* axes with a Y that extends from the bottom of the extent to the top
* of the extent.
*
* @param extent the extent
* @param center the center position
* @param radius the radius in the X and Z axes
* @return a region
*/
public static CylinderRegion createRadius(Extent extent, BlockVector3 center, double radius) {
checkNotNull(extent);
checkNotNull(center);
Vector2 radiusVec = Vector2.at(radius, radius);
int minY = extent.getMinimumPoint().getBlockY();
int maxY = extent.getMaximumPoint().getBlockY();
return new CylinderRegion(center, radiusVec, minY, maxY);
}
@Override
public void filter(final IChunk chunk, final Filter filter, final ChunkFilterBlock block,
final IChunkGet get, final IChunkSet set, boolean full) {
int bcx = chunk.getX() >> 4;
int bcz = chunk.getZ() >> 4;
int tcx = bcx + 15;
int tcz = bcz + 15;
if (contains(bcx, bcz) && contains(tcx, tcz)) {
filter(chunk, filter, block, get, set, minY, maxY, full);
return;
}
super.filter(chunk, filter, block, get, set, full);
}
}

View File

@@ -1,36 +1,36 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.util.formatting.text.Component;
public class RegionOperationException extends WorldEditException {
@Deprecated
public RegionOperationException(String msg) {
super(msg);
}
public RegionOperationException(Component msg) {
super(msg);
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.util.formatting.text.Component;
public class RegionOperationException extends WorldEditException {
@Deprecated
public RegionOperationException(String msg) {
super(msg);
}
public RegionOperationException(Component msg) {
super(msg);
}
}

View File

@@ -1,90 +1,90 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.polyhedron;
import com.sk89q.worldedit.math.Vector3;
import static com.google.common.base.Preconditions.checkNotNull;
public class Edge {
private final Vector3 start;
private final Vector3 end;
public Edge(Vector3 start, Vector3 end) {
checkNotNull(start);
checkNotNull(end);
this.start = start;
this.end = end;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Edge)) {
return false;
}
Edge otherEdge = (Edge) other;
if ((this.start == otherEdge.end) && (this.end == otherEdge.start)) {
return true;
}
if ((this.end == otherEdge.end) && (this.start == otherEdge.start)) {
return true;
}
return false;
}
@Override
public int hashCode() {
return start.hashCode() ^ end.hashCode();
}
@Override
public String toString() {
return "(" + this.start + "," + this.end + ")";
}
/**
* Create a triangle from { this.start, this.end, vertex }
*
* @param vertex the 3rd vertex for the triangle
* @return a triangle
*/
public Triangle createTriangle(Vector3 vertex) {
checkNotNull(vertex);
return new Triangle(this.start, this.end, vertex);
}
/**
* Create a triangle from { this.start, vertex, this.end }.
*
* @param vertex the second vertex
* @return a new triangle
*/
public Triangle createTriangle2(Vector3 vertex) {
checkNotNull(vertex);
return new Triangle(this.start, vertex, this.end);
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.polyhedron;
import com.sk89q.worldedit.math.Vector3;
import static com.google.common.base.Preconditions.checkNotNull;
public class Edge {
private final Vector3 start;
private final Vector3 end;
public Edge(Vector3 start, Vector3 end) {
checkNotNull(start);
checkNotNull(end);
this.start = start;
this.end = end;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Edge)) {
return false;
}
Edge otherEdge = (Edge) other;
if ((this.start == otherEdge.end) && (this.end == otherEdge.start)) {
return true;
}
if ((this.end == otherEdge.end) && (this.start == otherEdge.start)) {
return true;
}
return false;
}
@Override
public int hashCode() {
return start.hashCode() ^ end.hashCode();
}
@Override
public String toString() {
return "(" + this.start + "," + this.end + ")";
}
/**
* Create a triangle from { this.start, this.end, vertex }
*
* @param vertex the 3rd vertex for the triangle
* @return a triangle
*/
public Triangle createTriangle(Vector3 vertex) {
checkNotNull(vertex);
return new Triangle(this.start, this.end, vertex);
}
/**
* Create a triangle from { this.start, vertex, this.end }.
*
* @param vertex the second vertex
* @return a new triangle
*/
public Triangle createTriangle2(Vector3 vertex) {
checkNotNull(vertex);
return new Triangle(this.start, vertex, this.end);
}
}

View File

@@ -1,113 +1,113 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.polyhedron;
import com.sk89q.worldedit.math.Vector3;
import static com.google.common.base.Preconditions.checkNotNull;
public class Triangle {
private String tag = "Triangle";
private final Vector3[] vertices;
private final Vector3 normal;
private final double maxDotProduct;
/**
* Constructs a triangle with the given vertices (counter-clockwise).
*
* @param v0 first vertex
* @param v1 second vertex
* @param v2 third vertex
*/
public Triangle(Vector3 v0, Vector3 v1, Vector3 v2) {
checkNotNull(v0);
checkNotNull(v1);
checkNotNull(v2);
vertices = new Vector3[] { v0, v1, v2 };
this.normal = v1.subtract(v0).cross(v2.subtract(v0)).normalize();
this.maxDotProduct = Math.max(Math.max(normal.dot(v0), normal.dot(v1)), normal.dot(v2));
}
/**
* Returns the triangle's vertex with the given index, counter-clockwise.
*
* @param index Vertex index. Valid input: 0..2
* @return a vertex
*/
public Vector3 getVertex(int index) {
return vertices[index];
}
/**
* Returns the triangle's edge with the given index, counter-clockwise.
*
* @param index Edge index. Valid input: 0..2
* @return an edge
*/
public Edge getEdge(int index) {
if (index == vertices.length - 1) {
return new Edge(vertices[index], vertices[0]);
}
return new Edge(vertices[index], vertices[index + 1]);
}
/**
* Returns whether the given point is above the plane the triangle is in.
*
* @param pt the point to test
* @return true if the point is below
*/
public boolean below(Vector3 pt) {
checkNotNull(pt);
return normal.dot(pt) < maxDotProduct;
}
/**
* Returns whether the given point is above the plane the triangle is in.
*
* @param pt the point to test
* @return true if the point is above
*/
public boolean above(Vector3 pt) {
checkNotNull(pt);
return normal.dot(pt) > maxDotProduct;
}
/**
* Set the triangle's tag.
*
* @param tag the tag
* @return this object
*/
public Triangle tag(String tag) {
checkNotNull(tag);
this.tag = tag;
return this;
}
@Override
public String toString() {
return tag + "(" + this.vertices[0] + "," + this.vertices[1] + "," + this.vertices[2] + ")";
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.polyhedron;
import com.sk89q.worldedit.math.Vector3;
import static com.google.common.base.Preconditions.checkNotNull;
public class Triangle {
private String tag = "Triangle";
private final Vector3[] vertices;
private final Vector3 normal;
private final double maxDotProduct;
/**
* Constructs a triangle with the given vertices (counter-clockwise).
*
* @param v0 first vertex
* @param v1 second vertex
* @param v2 third vertex
*/
public Triangle(Vector3 v0, Vector3 v1, Vector3 v2) {
checkNotNull(v0);
checkNotNull(v1);
checkNotNull(v2);
vertices = new Vector3[] { v0, v1, v2 };
this.normal = v1.subtract(v0).cross(v2.subtract(v0)).normalize();
this.maxDotProduct = Math.max(Math.max(normal.dot(v0), normal.dot(v1)), normal.dot(v2));
}
/**
* Returns the triangle's vertex with the given index, counter-clockwise.
*
* @param index Vertex index. Valid input: 0..2
* @return a vertex
*/
public Vector3 getVertex(int index) {
return vertices[index];
}
/**
* Returns the triangle's edge with the given index, counter-clockwise.
*
* @param index Edge index. Valid input: 0..2
* @return an edge
*/
public Edge getEdge(int index) {
if (index == vertices.length - 1) {
return new Edge(vertices[index], vertices[0]);
}
return new Edge(vertices[index], vertices[index + 1]);
}
/**
* Returns whether the given point is above the plane the triangle is in.
*
* @param pt the point to test
* @return true if the point is below
*/
public boolean below(Vector3 pt) {
checkNotNull(pt);
return normal.dot(pt) < maxDotProduct;
}
/**
* Returns whether the given point is above the plane the triangle is in.
*
* @param pt the point to test
* @return true if the point is above
*/
public boolean above(Vector3 pt) {
checkNotNull(pt);
return normal.dot(pt) > maxDotProduct;
}
/**
* Set the triangle's tag.
*
* @param tag the tag
* @return this object
*/
public Triangle tag(String tag) {
checkNotNull(tag);
this.tag = tag;
return this;
}
@Override
public String toString() {
return tag + "(" + this.vertices[0] + "," + this.vertices[1] + "," + this.vertices[2] + ")";
}
}

View File

@@ -1,274 +1,274 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.InsufficientArgumentsException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.invoke.ReturnException;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.FilenameException;
import com.sk89q.worldedit.world.block.BaseBlock;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* The context given to scripts.
*/
public class CraftScriptContext extends CraftScriptEnvironment {
private final List<EditSession> editSessions = new ArrayList<>();
private final String[] args;
public CraftScriptContext(WorldEdit controller,
Platform server, LocalConfiguration config,
LocalSession session, Player player, String[] args) {
super(controller, server, config, session, player);
this.args = args;
}
/**
* Get an edit session. Every subsequent call returns a new edit session.
* Usually you only need to use one edit session.
*
* @return an edit session
*/
public EditSession remember() {
EditSession editSession = controller.getEditSessionFactory()
.getEditSession(player.getWorld(),
session.getBlockChangeLimit(), session.getBlockBag(player), player);
Request.request().setEditSession(editSession);
editSession.enableStandardMode();
editSessions.add(editSession);
return editSession;
}
/**
* Get the player.
*
* @return the calling player
*/
public Player getPlayer() {
return player;
}
/**
* Get the player's session.
*
* @return a session
*/
public LocalSession getSession() {
return session;
}
/**
* Get the configuration for WorldEdit.
*
* @return the configuration
*/
public LocalConfiguration getConfiguration() {
return config;
}
/**
* Get a list of edit sessions that have been created.
*
* @return a list of created {@code EditSession}s
*/
public List<EditSession> getEditSessions() {
return Collections.unmodifiableList(editSessions);
}
/**
* Print a regular message to the user.
*
* @param message a message
*/
public void print(String message) {
player.printInfo(TextComponent.of(message));
}
/**
* Print an error message to the user.
*
* @param message a message
*/
public void error(String message) {
player.printError(TextComponent.of(message));
}
/**
* Print a raw message to the user.
*
* @param message a message
*/
public void printRaw(String message) {
player.print(TextComponent.of(message));
}
/**
* Checks to make sure that there are enough but not too many arguments.
*
* @param min a number of arguments
* @param max -1 for no maximum
* @param usage usage string
* @throws InsufficientArgumentsException if the arguments are not "sufficiently" good
*/
public void checkArgs(int min, int max, String usage)
throws InsufficientArgumentsException {
if (args.length <= min || (max != -1 && args.length - 1 > max)) {
throw new InsufficientArgumentsException(TranslatableComponent.of("worldedit.error.incorrect-usage", TextComponent.of(usage)));
}
}
/**
* Immediately terminate execution of the script, but without a failure message.
*
* @implNote This exits by throwing an exception, which if caught will prevent
* the script from exiting
*/
public void exit() {
throw new ReturnException(null);
}
/**
* Get an item from an item name or an item ID number.
*
* @param input input to parse
* @param allAllowed true to ignore blacklists
* @return a block
* @throws NoMatchException if no block was found
* @throws DisallowedUsageException if the block is disallowed
*/
public BaseBlock getBlock(String input, boolean allAllowed) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setWorld(player.getWorld());
context.setSession(session);
context.setRestricted(!allAllowed);
context.setPreferringWildcard(false);
return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null);
}
/**
* Get a block.
*
* @param id the type Id
* @return a block
* @throws NoMatchException if no block was found
* @throws DisallowedUsageException if the block is disallowed
*/
public BaseBlock getBlock(String id) throws WorldEditException {
return getBlock(id, false);
}
/**
* Get a list of blocks as a set. This returns a Pattern.
*
* @param list the input
* @return pattern
* @throws NoMatchException if the pattern was invalid
* @throws DisallowedUsageException if the block is disallowed
*/
public Pattern getBlockPattern(String list) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setWorld(player.getWorld());
context.setSession(session);
return controller.getPatternFactory().parseFromInput(list, context);
}
/**
* Get a list of blocks as a set.
*
* @param list a list
* @param allBlocksAllowed true if all blocks are allowed
* @return set
* @throws NoMatchException if the blocks couldn't be found
* @throws DisallowedUsageException if the block is disallowed
*/
public Set<BaseBlock> getBlocks(String list, boolean allBlocksAllowed) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setWorld(player.getWorld());
context.setSession(session);
context.setRestricted(!allBlocksAllowed);
return controller.getBlockFactory().parseFromListInput(list, context);
}
/**
* Gets the path to a file for opening. This method will check to see if the
* filename has valid characters and has an extension. It also prevents
* directory traversal exploits by checking the root directory and the file
* directory. On success, a {@code java.io.File} object will be
* returned.
*
* <p>Use this method if you need to read a file from a directory.</p>
*
* @param folder sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt default extension to append if there is none
* @param exts list of extensions for file open dialog, null for no filter
* @return a file
* @throws FilenameException if there is a problem with the name of the file
*/
public File getSafeOpenFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException {
File dir = controller.getWorkingDirectoryFile(folder);
return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts);
}
/**
* Gets the path to a file for saving. This method will check to see if the
* filename has valid characters and has an extension. It also prevents
* directory traversal exploits by checking the root directory and the file
* directory. On success, a {@code java.io.File} object will be
* returned.
*
* <p>Use this method if you need to read a file from a directory.</p>
*
* @param folder sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt default extension to append if there is none
* @param exts list of extensions for file save dialog, null for no filter
* @return a file
* @throws FilenameException if there is a problem with the name of the file
*/
public File getSafeSaveFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException {
File dir = controller.getWorkingDirectoryFile(folder);
return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts);
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.InsufficientArgumentsException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.invoke.ReturnException;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.FilenameException;
import com.sk89q.worldedit.world.block.BaseBlock;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* The context given to scripts.
*/
public class CraftScriptContext extends CraftScriptEnvironment {
private final List<EditSession> editSessions = new ArrayList<>();
private final String[] args;
public CraftScriptContext(WorldEdit controller,
Platform server, LocalConfiguration config,
LocalSession session, Player player, String[] args) {
super(controller, server, config, session, player);
this.args = args;
}
/**
* Get an edit session. Every subsequent call returns a new edit session.
* Usually you only need to use one edit session.
*
* @return an edit session
*/
public EditSession remember() {
EditSession editSession = controller.getEditSessionFactory()
.getEditSession(player.getWorld(),
session.getBlockChangeLimit(), session.getBlockBag(player), player);
Request.request().setEditSession(editSession);
editSession.enableStandardMode();
editSessions.add(editSession);
return editSession;
}
/**
* Get the player.
*
* @return the calling player
*/
public Player getPlayer() {
return player;
}
/**
* Get the player's session.
*
* @return a session
*/
public LocalSession getSession() {
return session;
}
/**
* Get the configuration for WorldEdit.
*
* @return the configuration
*/
public LocalConfiguration getConfiguration() {
return config;
}
/**
* Get a list of edit sessions that have been created.
*
* @return a list of created {@code EditSession}s
*/
public List<EditSession> getEditSessions() {
return Collections.unmodifiableList(editSessions);
}
/**
* Print a regular message to the user.
*
* @param message a message
*/
public void print(String message) {
player.printInfo(TextComponent.of(message));
}
/**
* Print an error message to the user.
*
* @param message a message
*/
public void error(String message) {
player.printError(TextComponent.of(message));
}
/**
* Print a raw message to the user.
*
* @param message a message
*/
public void printRaw(String message) {
player.print(TextComponent.of(message));
}
/**
* Checks to make sure that there are enough but not too many arguments.
*
* @param min a number of arguments
* @param max -1 for no maximum
* @param usage usage string
* @throws InsufficientArgumentsException if the arguments are not "sufficiently" good
*/
public void checkArgs(int min, int max, String usage)
throws InsufficientArgumentsException {
if (args.length <= min || (max != -1 && args.length - 1 > max)) {
throw new InsufficientArgumentsException(TranslatableComponent.of("worldedit.error.incorrect-usage", TextComponent.of(usage)));
}
}
/**
* Immediately terminate execution of the script, but without a failure message.
*
* @implNote This exits by throwing an exception, which if caught will prevent
* the script from exiting
*/
public void exit() {
throw new ReturnException(null);
}
/**
* Get an item from an item name or an item ID number.
*
* @param input input to parse
* @param allAllowed true to ignore blacklists
* @return a block
* @throws NoMatchException if no block was found
* @throws DisallowedUsageException if the block is disallowed
*/
public BaseBlock getBlock(String input, boolean allAllowed) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setWorld(player.getWorld());
context.setSession(session);
context.setRestricted(!allAllowed);
context.setPreferringWildcard(false);
return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null);
}
/**
* Get a block.
*
* @param id the type Id
* @return a block
* @throws NoMatchException if no block was found
* @throws DisallowedUsageException if the block is disallowed
*/
public BaseBlock getBlock(String id) throws WorldEditException {
return getBlock(id, false);
}
/**
* Get a list of blocks as a set. This returns a Pattern.
*
* @param list the input
* @return pattern
* @throws NoMatchException if the pattern was invalid
* @throws DisallowedUsageException if the block is disallowed
*/
public Pattern getBlockPattern(String list) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setWorld(player.getWorld());
context.setSession(session);
return controller.getPatternFactory().parseFromInput(list, context);
}
/**
* Get a list of blocks as a set.
*
* @param list a list
* @param allBlocksAllowed true if all blocks are allowed
* @return set
* @throws NoMatchException if the blocks couldn't be found
* @throws DisallowedUsageException if the block is disallowed
*/
public Set<BaseBlock> getBlocks(String list, boolean allBlocksAllowed) throws WorldEditException {
ParserContext context = new ParserContext();
context.setActor(player);
context.setWorld(player.getWorld());
context.setSession(session);
context.setRestricted(!allBlocksAllowed);
return controller.getBlockFactory().parseFromListInput(list, context);
}
/**
* Gets the path to a file for opening. This method will check to see if the
* filename has valid characters and has an extension. It also prevents
* directory traversal exploits by checking the root directory and the file
* directory. On success, a {@code java.io.File} object will be
* returned.
*
* <p>Use this method if you need to read a file from a directory.</p>
*
* @param folder sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt default extension to append if there is none
* @param exts list of extensions for file open dialog, null for no filter
* @return a file
* @throws FilenameException if there is a problem with the name of the file
*/
public File getSafeOpenFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException {
File dir = controller.getWorkingDirectoryFile(folder);
return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts);
}
/**
* Gets the path to a file for saving. This method will check to see if the
* filename has valid characters and has an extension. It also prevents
* directory traversal exploits by checking the root directory and the file
* directory. On success, a {@code java.io.File} object will be
* returned.
*
* <p>Use this method if you need to read a file from a directory.</p>
*
* @param folder sub-directory to look in
* @param filename filename (user-submitted)
* @param defaultExt default extension to append if there is none
* @param exts list of extensions for file save dialog, null for no filter
* @return a file
* @throws FilenameException if there is a problem with the name of the file
*/
public File getSafeSaveFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException {
File dir = controller.getWorkingDirectoryFile(folder);
return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts);
}
}

View File

@@ -1,32 +1,32 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import java.util.Map;
import javax.script.ScriptException;
public interface CraftScriptEngine {
void setTimeLimit(int milliseconds);
int getTimeLimit();
Object evaluate(String script, String filename, Map<String, Object> args)
throws ScriptException, Throwable;
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import java.util.Map;
import javax.script.ScriptException;
public interface CraftScriptEngine {
void setTimeLimit(int milliseconds);
int getTimeLimit();
Object evaluate(String script, String filename, Map<String, Object> args)
throws ScriptException, Throwable;
}

View File

@@ -1,44 +1,44 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Platform;
public abstract class CraftScriptEnvironment {
protected WorldEdit controller;
protected Player player;
protected LocalConfiguration config;
protected LocalSession session;
protected Platform server;
public CraftScriptEnvironment(WorldEdit controller, Platform server, LocalConfiguration config, LocalSession session, Player player) {
this.controller = controller;
this.player = player;
this.config = config;
this.server = server;
this.session = session;
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Platform;
public abstract class CraftScriptEnvironment {
protected WorldEdit controller;
protected Player player;
protected LocalConfiguration config;
protected LocalSession session;
protected Platform server;
public CraftScriptEnvironment(WorldEdit controller, Platform server, LocalConfiguration config, LocalSession session, Player player) {
this.controller = controller;
this.player = player;
this.config = config;
this.server = server;
this.session = session;
}
}

View File

@@ -1,77 +1,77 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.Scriptable;
public class RhinoContextFactory extends ContextFactory {
protected int timeLimit;
public RhinoContextFactory(int timeLimit) {
this.timeLimit = timeLimit;
}
@Override
protected Context makeContext() {
RhinoContext cx = new RhinoContext(this);
try {
// Try to set ES6 compat flag (since 1.7.7)
Context.class.getDeclaredField("VERSION_ES6");
cx.setLanguageVersion(RhinoContext.VERSION_ES6);
} catch (NoSuchFieldException e) {
// best we can do, compatible with 1.7R2 that many people probably use
cx.setLanguageVersion(Context.VERSION_1_7);
}
cx.setInstructionObserverThreshold(10000);
return cx;
}
@Override
protected void observeInstructionCount(Context cx, int instructionCount) {
RhinoContext mcx = (RhinoContext) cx;
long currentTime = System.currentTimeMillis();
if (currentTime - mcx.startTime > timeLimit) {
throw new Error("Script timed out (" + timeLimit + "ms)");
}
}
@Override
protected Object doTopCall(Callable callable, Context cx, Scriptable scope,
Scriptable thisObj, Object[] args) {
RhinoContext mcx = (RhinoContext) cx;
mcx.startTime = System.currentTimeMillis();
return super.doTopCall(callable, cx, scope, thisObj, args);
}
private static class RhinoContext extends Context {
long startTime;
private RhinoContext(ContextFactory factory) {
super(factory);
}
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.Scriptable;
public class RhinoContextFactory extends ContextFactory {
protected int timeLimit;
public RhinoContextFactory(int timeLimit) {
this.timeLimit = timeLimit;
}
@Override
protected Context makeContext() {
RhinoContext cx = new RhinoContext(this);
try {
// Try to set ES6 compat flag (since 1.7.7)
Context.class.getDeclaredField("VERSION_ES6");
cx.setLanguageVersion(RhinoContext.VERSION_ES6);
} catch (NoSuchFieldException e) {
// best we can do, compatible with 1.7R2 that many people probably use
cx.setLanguageVersion(Context.VERSION_1_7);
}
cx.setInstructionObserverThreshold(10000);
return cx;
}
@Override
protected void observeInstructionCount(Context cx, int instructionCount) {
RhinoContext mcx = (RhinoContext) cx;
long currentTime = System.currentTimeMillis();
if (currentTime - mcx.startTime > timeLimit) {
throw new Error("Script timed out (" + timeLimit + "ms)");
}
}
@Override
protected Object doTopCall(Callable callable, Context cx, Scriptable scope,
Scriptable thisObj, Object[] args) {
RhinoContext mcx = (RhinoContext) cx;
mcx.startTime = System.currentTimeMillis();
return super.doTopCall(callable, cx, scope, thisObj, args);
}
private static class RhinoContext extends Context {
long startTime;
private RhinoContext(ContextFactory factory) {
super(factory);
}
}
}

View File

@@ -1,98 +1,98 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.google.common.io.CharStreams;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.scripting.compat.BabelScriptTranspiler;
import com.sk89q.worldedit.scripting.compat.ScriptTranspiler;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrappedException;
import java.io.StringReader;
import java.util.Map;
import javax.script.ScriptException;
public class RhinoCraftScriptEngine implements CraftScriptEngine {
private static final ScriptTranspiler TRANSPILER = new BabelScriptTranspiler();
private int timeLimit;
@Override
public void setTimeLimit(int milliseconds) {
timeLimit = milliseconds;
}
@Override
public int getTimeLimit() {
return timeLimit;
}
@Override
public Object evaluate(String script, String filename, Map<String, Object> args)
throws ScriptException, Throwable {
String transpiled = CharStreams.toString(TRANSPILER.transpile(new StringReader(script)));
RhinoContextFactory factory = new RhinoContextFactory(timeLimit);
Context cx = factory.enterContext();
cx.setClassShutter(new MinecraftHidingClassShutter());
ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable);
for (Map.Entry<String, Object> entry : args.entrySet()) {
ScriptableObject.putProperty(scope, entry.getKey(),
Context.javaToJS(entry.getValue(), scope));
}
try {
return cx.evaluateString(scope, transpiled, filename, 1, null);
} catch (Error e) {
throw new ScriptException(e.getMessage());
} catch (RhinoException e) {
if (e instanceof WrappedException) {
Throwable cause = e.getCause();
if (cause instanceof WorldEditException) {
throw cause;
}
}
String msg;
int line = (line = e.lineNumber()) == 0 ? -1 : line;
if (e instanceof JavaScriptException) {
msg = String.valueOf(((JavaScriptException) e).getValue());
} else {
msg = e.getMessage();
}
ScriptException scriptException =
new ScriptException(msg, e.sourceName(), line);
scriptException.initCause(e);
throw scriptException;
} finally {
Context.exit();
}
}
}
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.scripting;
import com.google.common.io.CharStreams;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.scripting.compat.BabelScriptTranspiler;
import com.sk89q.worldedit.scripting.compat.ScriptTranspiler;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrappedException;
import java.io.StringReader;
import java.util.Map;
import javax.script.ScriptException;
public class RhinoCraftScriptEngine implements CraftScriptEngine {
private static final ScriptTranspiler TRANSPILER = new BabelScriptTranspiler();
private int timeLimit;
@Override
public void setTimeLimit(int milliseconds) {
timeLimit = milliseconds;
}
@Override
public int getTimeLimit() {
return timeLimit;
}
@Override
public Object evaluate(String script, String filename, Map<String, Object> args)
throws ScriptException, Throwable {
String transpiled = CharStreams.toString(TRANSPILER.transpile(new StringReader(script)));
RhinoContextFactory factory = new RhinoContextFactory(timeLimit);
Context cx = factory.enterContext();
cx.setClassShutter(new MinecraftHidingClassShutter());
ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable);
for (Map.Entry<String, Object> entry : args.entrySet()) {
ScriptableObject.putProperty(scope, entry.getKey(),
Context.javaToJS(entry.getValue(), scope));
}
try {
return cx.evaluateString(scope, transpiled, filename, 1, null);
} catch (Error e) {
throw new ScriptException(e.getMessage());
} catch (RhinoException e) {
if (e instanceof WrappedException) {
Throwable cause = e.getCause();
if (cause instanceof WorldEditException) {
throw cause;
}
}
String msg;
int line = (line = e.lineNumber()) == 0 ? -1 : line;
if (e instanceof JavaScriptException) {
msg = String.valueOf(((JavaScriptException) e).getValue());
} else {
msg = e.getMessage();
}
ScriptException scriptException =
new ScriptException(msg, e.sourceName(), line);
scriptException.initCause(e);
throw scriptException;
} finally {
Context.exit();
}
}
}

View File

@@ -1,96 +1,96 @@
/*
* 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.util;
import com.sk89q.util.StringUtil;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
public final class FileDialogUtil {
private FileDialogUtil() {
}
public static File showSaveDialog(String[] exts) {
JFileChooser dialog = new JFileChooser();
if (exts != null) {
dialog.setFileFilter(new ExtensionFilter(exts));
}
int returnVal = dialog.showSaveDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return dialog.getSelectedFile();
}
return null;
}
public static File showOpenDialog(String[] exts) {
JFileChooser dialog = new JFileChooser();
if (exts != null) {
dialog.setFileFilter(new ExtensionFilter(exts));
}
int returnVal = dialog.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return dialog.getSelectedFile();
}
return null;
}
private static class ExtensionFilter extends FileFilter {
private Set<String> exts;
private String desc;
private ExtensionFilter(String[] exts) {
this.exts = new HashSet<>(Arrays.asList(exts));
desc = StringUtil.joinString(exts, ",");
}
@Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String path = f.getPath();
int index = path.lastIndexOf('.');
if (index == -1 || index == path.length() - 1) {
return false;
} else {
return exts.contains(path.substring(index + 1));
}
}
@Override
public String getDescription() {
return desc;
}
}
}
/*
* 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.util;
import com.sk89q.util.StringUtil;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
public final class FileDialogUtil {
private FileDialogUtil() {
}
public static File showSaveDialog(String[] exts) {
JFileChooser dialog = new JFileChooser();
if (exts != null) {
dialog.setFileFilter(new ExtensionFilter(exts));
}
int returnVal = dialog.showSaveDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return dialog.getSelectedFile();
}
return null;
}
public static File showOpenDialog(String[] exts) {
JFileChooser dialog = new JFileChooser();
if (exts != null) {
dialog.setFileFilter(new ExtensionFilter(exts));
}
int returnVal = dialog.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return dialog.getSelectedFile();
}
return null;
}
private static class ExtensionFilter extends FileFilter {
private Set<String> exts;
private String desc;
private ExtensionFilter(String[] exts) {
this.exts = new HashSet<>(Arrays.asList(exts));
desc = StringUtil.joinString(exts, ",");
}
@Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String path = f.getPath();
int index = path.lastIndexOf('.');
if (index == -1 || index == path.length() - 1) {
return false;
} else {
return exts.contains(path.substring(index + 1));
}
}
@Override
public String getDescription() {
return desc;
}
}
}

View File

@@ -1,250 +1,250 @@
/*
* 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.util;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import javax.annotation.Nullable;
/**
* This class uses an inefficient method to figure out what block a player
* is looking towards.
*
* <p>Originally written by toi. It was ported to WorldEdit and trimmed down by
* sk89q. Thanks to Raphfrk for optimization of toi's original class.</p>
*/
public class TargetBlock {
private final Extent world;
private int maxDistance;
private double checkDistance, curDistance;
private BlockVector3 targetPos = BlockVector3.ZERO;
private Vector3 targetPosDouble = Vector3.ZERO;
private BlockVector3 prevPos = BlockVector3.ZERO;
private Vector3 offset = Vector3.ZERO;
// the mask which dictates when to stop a trace - defaults to stopping at non-air blocks
private Mask stopMask;
// the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker
private Mask solidMask;
/**
* Constructor requiring a player, uses default values
*
* @param player player to work with
*/
public TargetBlock(Player player) {
this(player, 300, 0.2);
}
/**
* Constructor requiring a player, max distance and a checking distance
*
* @param player Player to work with
* @param maxDistance how far it checks for blocks
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
public TargetBlock(Player player, int maxDistance, double checkDistance) {
this(player, player.getWorld(), maxDistance, checkDistance);
}
public TargetBlock(Player player, Extent extent, int maxDistance, double checkDistance) {
this.world = player.getWorld();
this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), maxDistance, 1.65, checkDistance);
this.stopMask = new ExistingBlockMask(world);
this.solidMask = new SolidBlockMask(world);
}
/**
* Set the mask used for determine where to stop traces.
* Setting to null will restore the default.
*
* @param stopMask the mask used to stop traces
*/
public void setStopMask(@Nullable Mask stopMask) {
if (stopMask == null) {
this.stopMask = new ExistingBlockMask(world);
} else {
this.stopMask = stopMask;
}
}
/**
* Set the mask used for determine where to stop solid block traces.
* Setting to null will restore the default.
*
* @param solidMask the mask used to stop solid block traces
*/
public void setSolidMask(@Nullable Mask solidMask) {
if (solidMask == null) {
this.solidMask = new SolidBlockMask(world);
} else {
this.solidMask = solidMask;
}
}
/**
* Set the values, all constructors uses this function
*
* @param loc location of the view
* @param xRotation the X rotation
* @param yRotation the Y rotation
* @param maxDistance how far it checks for blocks
* @param viewHeight where the view is positioned in y-axis
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
private void setValues(Vector3 loc, double xRotation, double yRotation, int maxDistance, double viewHeight, double checkDistance) {
this.maxDistance = maxDistance;
this.checkDistance = checkDistance;
this.curDistance = 0;
xRotation = (xRotation + 90) % 360;
yRotation *= -1;
double h = (checkDistance * Math.cos(Math.toRadians(yRotation)));
offset = Vector3.at((h * Math.cos(Math.toRadians(xRotation))),
(checkDistance * Math.sin(Math.toRadians(yRotation))),
(h * Math.sin(Math.toRadians(xRotation))));
targetPosDouble = loc.add(0, viewHeight, 0);
targetPos = targetPosDouble.toBlockPoint();
prevPos = targetPos;
}
/**
* Returns any block at the sight. Returns null if out of range or if no
* viable target was found. Will try to return the last valid air block it finds.
*
* @return Block
*/
public Location getAnyTargetBlock() {
boolean searchForLastBlock = true;
Location lastBlock = null;
while (getNextBlock() != null) {
if (stopMask.test(world, targetPos)) {
break;
} else {
if (searchForLastBlock) {
lastBlock = getCurrentBlock();
if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) {
searchForLastBlock = false;
}
}
}
}
Location currentBlock = getCurrentBlock();
return (currentBlock != null ? currentBlock : lastBlock);
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
* @return Block
*/
public Location getTargetBlock() {
//noinspection StatementWithEmptyBody
while (getNextBlock() != null && !stopMask.test(world, targetPos)) ;
return getCurrentBlock();
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
* @return Block
*/
public Location getSolidTargetBlock() {
//noinspection StatementWithEmptyBody
while (getNextBlock() != null && !solidMask.test(world, targetPos)) ;
return getCurrentBlock();
}
/**
* Get next block
*
* @return next block position
*/
public Location getNextBlock() {
prevPos = targetPos;
do {
curDistance += checkDistance;
targetPosDouble = offset.add(targetPosDouble.getX(),
targetPosDouble.getY(),
targetPosDouble.getZ());
targetPos = targetPosDouble.toBlockPoint();
} while (curDistance <= maxDistance
&& targetPos.getBlockX() == prevPos.getBlockX()
&& targetPos.getBlockY() == prevPos.getBlockY()
&& targetPos.getBlockZ() == prevPos.getBlockZ());
if (curDistance > maxDistance) {
return null;
}
return new Location(world, targetPos.toVector3());
}
/**
* Returns the current block along the line of vision
*
* @return block position
*/
public Location getCurrentBlock() {
if (curDistance > maxDistance) {
return null;
} else {
return new Location(world, targetPos.toVector3());
}
}
/**
* Returns the previous block in the aimed path
*
* @return block position
*/
public Location getPreviousBlock() {
return new Location(world, prevPos.toVector3());
}
public Location getAnyTargetBlockFace() {
getAnyTargetBlock();
Location current = getCurrentBlock();
if (current != null)
return current.setDirection(current.toVector().subtract(getPreviousBlock().toVector()));
else
return new Location(world, targetPos.toVector3(), Float.NaN, Float.NaN);
}
public Location getTargetBlockFace() {
getTargetBlock();
if (getCurrentBlock() == null) return null;
return getCurrentBlock().setDirection(getCurrentBlock().toVector().subtract(getPreviousBlock().toVector()));
}
}
/*
* 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.util;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import javax.annotation.Nullable;
/**
* This class uses an inefficient method to figure out what block a player
* is looking towards.
*
* <p>Originally written by toi. It was ported to WorldEdit and trimmed down by
* sk89q. Thanks to Raphfrk for optimization of toi's original class.</p>
*/
public class TargetBlock {
private final Extent world;
private int maxDistance;
private double checkDistance, curDistance;
private BlockVector3 targetPos = BlockVector3.ZERO;
private Vector3 targetPosDouble = Vector3.ZERO;
private BlockVector3 prevPos = BlockVector3.ZERO;
private Vector3 offset = Vector3.ZERO;
// the mask which dictates when to stop a trace - defaults to stopping at non-air blocks
private Mask stopMask;
// the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker
private Mask solidMask;
/**
* Constructor requiring a player, uses default values
*
* @param player player to work with
*/
public TargetBlock(Player player) {
this(player, 300, 0.2);
}
/**
* Constructor requiring a player, max distance and a checking distance
*
* @param player Player to work with
* @param maxDistance how far it checks for blocks
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
public TargetBlock(Player player, int maxDistance, double checkDistance) {
this(player, player.getWorld(), maxDistance, checkDistance);
}
public TargetBlock(Player player, Extent extent, int maxDistance, double checkDistance) {
this.world = player.getWorld();
this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), maxDistance, 1.65, checkDistance);
this.stopMask = new ExistingBlockMask(world);
this.solidMask = new SolidBlockMask(world);
}
/**
* Set the mask used for determine where to stop traces.
* Setting to null will restore the default.
*
* @param stopMask the mask used to stop traces
*/
public void setStopMask(@Nullable Mask stopMask) {
if (stopMask == null) {
this.stopMask = new ExistingBlockMask(world);
} else {
this.stopMask = stopMask;
}
}
/**
* Set the mask used for determine where to stop solid block traces.
* Setting to null will restore the default.
*
* @param solidMask the mask used to stop solid block traces
*/
public void setSolidMask(@Nullable Mask solidMask) {
if (solidMask == null) {
this.solidMask = new SolidBlockMask(world);
} else {
this.solidMask = solidMask;
}
}
/**
* Set the values, all constructors uses this function
*
* @param loc location of the view
* @param xRotation the X rotation
* @param yRotation the Y rotation
* @param maxDistance how far it checks for blocks
* @param viewHeight where the view is positioned in y-axis
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
private void setValues(Vector3 loc, double xRotation, double yRotation, int maxDistance, double viewHeight, double checkDistance) {
this.maxDistance = maxDistance;
this.checkDistance = checkDistance;
this.curDistance = 0;
xRotation = (xRotation + 90) % 360;
yRotation *= -1;
double h = (checkDistance * Math.cos(Math.toRadians(yRotation)));
offset = Vector3.at((h * Math.cos(Math.toRadians(xRotation))),
(checkDistance * Math.sin(Math.toRadians(yRotation))),
(h * Math.sin(Math.toRadians(xRotation))));
targetPosDouble = loc.add(0, viewHeight, 0);
targetPos = targetPosDouble.toBlockPoint();
prevPos = targetPos;
}
/**
* Returns any block at the sight. Returns null if out of range or if no
* viable target was found. Will try to return the last valid air block it finds.
*
* @return Block
*/
public Location getAnyTargetBlock() {
boolean searchForLastBlock = true;
Location lastBlock = null;
while (getNextBlock() != null) {
if (stopMask.test(world, targetPos)) {
break;
} else {
if (searchForLastBlock) {
lastBlock = getCurrentBlock();
if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) {
searchForLastBlock = false;
}
}
}
}
Location currentBlock = getCurrentBlock();
return (currentBlock != null ? currentBlock : lastBlock);
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
* @return Block
*/
public Location getTargetBlock() {
//noinspection StatementWithEmptyBody
while (getNextBlock() != null && !stopMask.test(world, targetPos)) ;
return getCurrentBlock();
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
* @return Block
*/
public Location getSolidTargetBlock() {
//noinspection StatementWithEmptyBody
while (getNextBlock() != null && !solidMask.test(world, targetPos)) ;
return getCurrentBlock();
}
/**
* Get next block
*
* @return next block position
*/
public Location getNextBlock() {
prevPos = targetPos;
do {
curDistance += checkDistance;
targetPosDouble = offset.add(targetPosDouble.getX(),
targetPosDouble.getY(),
targetPosDouble.getZ());
targetPos = targetPosDouble.toBlockPoint();
} while (curDistance <= maxDistance
&& targetPos.getBlockX() == prevPos.getBlockX()
&& targetPos.getBlockY() == prevPos.getBlockY()
&& targetPos.getBlockZ() == prevPos.getBlockZ());
if (curDistance > maxDistance) {
return null;
}
return new Location(world, targetPos.toVector3());
}
/**
* Returns the current block along the line of vision
*
* @return block position
*/
public Location getCurrentBlock() {
if (curDistance > maxDistance) {
return null;
} else {
return new Location(world, targetPos.toVector3());
}
}
/**
* Returns the previous block in the aimed path
*
* @return block position
*/
public Location getPreviousBlock() {
return new Location(world, prevPos.toVector3());
}
public Location getAnyTargetBlockFace() {
getAnyTargetBlock();
Location current = getCurrentBlock();
if (current != null)
return current.setDirection(current.toVector().subtract(getPreviousBlock().toVector()));
else
return new Location(world, targetPos.toVector3(), Float.NaN, Float.NaN);
}
public Location getTargetBlockFace() {
getTargetBlock();
if (getCurrentBlock() == null) return null;
return getCurrentBlock().setDirection(getCurrentBlock().toVector().subtract(getPreviousBlock().toVector()));
}
}

View File

@@ -1,270 +1,270 @@
/*
* 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.util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Tree generator.
*/
public class TreeGenerator {
public enum TreeType {
TREE("Oak tree", "oak", "tree", "regular"),
BIG_TREE("Large oak tree", "largeoak", "bigoak", "big", "bigtree"),
REDWOOD("Spruce tree", "spruce", "redwood", "sequoia", "sequoioideae"),
TALL_REDWOOD("Tall spruce tree", "tallspruce", "bigspruce", "tallredwood", "tallsequoia", "tallsequoioideae"),
MEGA_REDWOOD("Large spruce tree", "largespruce", "megaredwood"),
RANDOM_REDWOOD("Random spruce tree", "randspruce", "randredwood", "randomredwood", "anyredwood") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { REDWOOD, TALL_REDWOOD, MEGA_REDWOOD };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
BIRCH("Birch tree", "birch", "white", "whitebark"),
TALL_BIRCH("Tall birch tree", "tallbirch"),
RANDOM_BIRCH("Random birch tree", "randbirch", "randombirch") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { BIRCH, TALL_BIRCH };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
JUNGLE("Jungle tree", "jungle"),
SMALL_JUNGLE("Small jungle tree", "smalljungle"),
SHORT_JUNGLE("Short jungle tree", "shortjungle") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
return SMALL_JUNGLE.generate(editSession, pos);
}
},
RANDOM_JUNGLE("Random jungle tree", "randjungle", "randomjungle") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { JUNGLE, SMALL_JUNGLE };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
JUNGLE_BUSH("Jungle bush", "junglebush", "jungleshrub"),
RED_MUSHROOM("Red mushroom", "redmushroom", "redgiantmushroom"),
BROWN_MUSHROOM("Brown mushroom", "brownmushroom", "browngiantmushroom"),
RANDOM_MUSHROOM("Random mushroom", "randmushroom", "randommushroom") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { RED_MUSHROOM, BROWN_MUSHROOM };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
SWAMP("Swamp tree", "swamp", "swamptree"),
ACACIA("Acacia tree", "acacia"),
DARK_OAK("Dark oak tree", "darkoak"),
PINE("Pine tree", "pine") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
makePineTree(editSession, pos);
return true;
}
},
RANDOM("Random tree", "rand", "random") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = TreeType.values();
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
};
/**
* Stores a map of the names for fast access.
*/
private static final Map<String, TreeType> lookup = new HashMap<>();
private static final Set<String> primaryAliases = Sets.newHashSet();
private final String name;
public final ImmutableList<String> lookupKeys;
static {
for (TreeType type : EnumSet.allOf(TreeType.class)) {
for (String key : type.lookupKeys) {
lookup.put(key, type);
}
if (type.lookupKeys.size() > 0) {
primaryAliases.add(type.lookupKeys.get(0));
}
}
}
TreeType(String name, String... lookupKeys) {
this.name = name;
this.lookupKeys = ImmutableList.copyOf(lookupKeys);
}
public static Set<String> getAliases() {
return Collections.unmodifiableSet(lookup.keySet());
}
public static Set<String> getPrimaryAliases() {
return Collections.unmodifiableSet(primaryAliases);
}
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
return editSession.getWorld().generateTree(this, editSession, pos);
}
/**
* Get user-friendly tree type name.
*
* @return a name
*/
public String getName() {
return name;
}
/**
* Return type from name. May return null.
*
* @param name name to search
* @return a tree type or null
*/
@Nullable
public static TreeType lookup(String name) {
return lookup.get(name.replace("_", "").toLowerCase(Locale.ROOT));
}
}
private TreeGenerator() {
}
private static final Random RANDOM = new Random();
/**
* Makes a terrible looking pine tree.
*
* @param basePosition the base position
*/
private static void makePineTree(EditSession editSession, BlockVector3 basePosition)
throws MaxChangedBlocksException {
int trunkHeight = (int) Math.floor(Math.random() * 2) + 3;
int height = (int) Math.floor(Math.random() * 5) + 8;
BlockState logBlock = BlockTypes.OAK_LOG.getDefaultState();
BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState();
// Create trunk
for (int i = 0; i < trunkHeight; ++i) {
if (!setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock)) {
return;
}
}
// Move up
basePosition = basePosition.add(0, trunkHeight, 0);
// Create tree + leaves
for (int i = 0; i < height; ++i) {
setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock);
// Less leaves at these levels
double chance = ((i == 0 || i == height - 1) ? 0.6 : 1);
// Inner leaves
setChanceBlockIfAir(editSession, basePosition.add(-1, i, 0), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(1, i, 0), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(0, i, -1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(0, i, 1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(1, i, 1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(-1, i, 1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(1, i, -1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(-1, i, -1), leavesBlock, chance);
if (!(i == 0 || i == height - 1)) {
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(-2, i, j), leavesBlock, 0.6);
}
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(2, i, j), leavesBlock, 0.6);
}
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(j, i, -2), leavesBlock, 0.6);
}
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(j, i, 2), leavesBlock, 0.6);
}
}
}
setBlockIfAir(editSession, basePosition.add(0, height, 0), leavesBlock);
}
/**
* Looks up a tree type. May return null if a tree type by that
* name is not found.
*
* @param type the tree type
* @return a tree type or null
*/
@Nullable
public static TreeType lookup(String type) {
return TreeType.lookup(type);
}
/**
* Set a block (only if a previous block was not there) if {@link Math#random()}
* returns a number less than the given probability.
*
* @param position the position
* @param block the block
* @param probability a probability between 0 and 1, inclusive
* @return whether a block was changed
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
private static <B extends BlockStateHolder<B>> boolean setChanceBlockIfAir(EditSession session, BlockVector3 position, B block, double probability)
throws MaxChangedBlocksException {
return Math.random() <= probability && setBlockIfAir(session, position, block);
}
/**
* Set a block only if there's no block already there.
*
* @param position the position
* @param block the block to set
* @return if block was changed
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
private static <B extends BlockStateHolder<B>> boolean setBlockIfAir(EditSession session, BlockVector3 position, B block) throws MaxChangedBlocksException {
return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, block);
}
}
/*
* 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.util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Tree generator.
*/
public class TreeGenerator {
public enum TreeType {
TREE("Oak tree", "oak", "tree", "regular"),
BIG_TREE("Large oak tree", "largeoak", "bigoak", "big", "bigtree"),
REDWOOD("Spruce tree", "spruce", "redwood", "sequoia", "sequoioideae"),
TALL_REDWOOD("Tall spruce tree", "tallspruce", "bigspruce", "tallredwood", "tallsequoia", "tallsequoioideae"),
MEGA_REDWOOD("Large spruce tree", "largespruce", "megaredwood"),
RANDOM_REDWOOD("Random spruce tree", "randspruce", "randredwood", "randomredwood", "anyredwood") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { REDWOOD, TALL_REDWOOD, MEGA_REDWOOD };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
BIRCH("Birch tree", "birch", "white", "whitebark"),
TALL_BIRCH("Tall birch tree", "tallbirch"),
RANDOM_BIRCH("Random birch tree", "randbirch", "randombirch") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { BIRCH, TALL_BIRCH };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
JUNGLE("Jungle tree", "jungle"),
SMALL_JUNGLE("Small jungle tree", "smalljungle"),
SHORT_JUNGLE("Short jungle tree", "shortjungle") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
return SMALL_JUNGLE.generate(editSession, pos);
}
},
RANDOM_JUNGLE("Random jungle tree", "randjungle", "randomjungle") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { JUNGLE, SMALL_JUNGLE };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
JUNGLE_BUSH("Jungle bush", "junglebush", "jungleshrub"),
RED_MUSHROOM("Red mushroom", "redmushroom", "redgiantmushroom"),
BROWN_MUSHROOM("Brown mushroom", "brownmushroom", "browngiantmushroom"),
RANDOM_MUSHROOM("Random mushroom", "randmushroom", "randommushroom") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = { RED_MUSHROOM, BROWN_MUSHROOM };
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
},
SWAMP("Swamp tree", "swamp", "swamptree"),
ACACIA("Acacia tree", "acacia"),
DARK_OAK("Dark oak tree", "darkoak"),
PINE("Pine tree", "pine") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
makePineTree(editSession, pos);
return true;
}
},
RANDOM("Random tree", "rand", "random") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
TreeType[] choices = TreeType.values();
return choices[TreeGenerator.RANDOM.nextInt(choices.length)].generate(editSession, pos);
}
};
/**
* Stores a map of the names for fast access.
*/
private static final Map<String, TreeType> lookup = new HashMap<>();
private static final Set<String> primaryAliases = Sets.newHashSet();
private final String name;
public final ImmutableList<String> lookupKeys;
static {
for (TreeType type : EnumSet.allOf(TreeType.class)) {
for (String key : type.lookupKeys) {
lookup.put(key, type);
}
if (type.lookupKeys.size() > 0) {
primaryAliases.add(type.lookupKeys.get(0));
}
}
}
TreeType(String name, String... lookupKeys) {
this.name = name;
this.lookupKeys = ImmutableList.copyOf(lookupKeys);
}
public static Set<String> getAliases() {
return Collections.unmodifiableSet(lookup.keySet());
}
public static Set<String> getPrimaryAliases() {
return Collections.unmodifiableSet(primaryAliases);
}
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {
return editSession.getWorld().generateTree(this, editSession, pos);
}
/**
* Get user-friendly tree type name.
*
* @return a name
*/
public String getName() {
return name;
}
/**
* Return type from name. May return null.
*
* @param name name to search
* @return a tree type or null
*/
@Nullable
public static TreeType lookup(String name) {
return lookup.get(name.replace("_", "").toLowerCase(Locale.ROOT));
}
}
private TreeGenerator() {
}
private static final Random RANDOM = new Random();
/**
* Makes a terrible looking pine tree.
*
* @param basePosition the base position
*/
private static void makePineTree(EditSession editSession, BlockVector3 basePosition)
throws MaxChangedBlocksException {
int trunkHeight = (int) Math.floor(Math.random() * 2) + 3;
int height = (int) Math.floor(Math.random() * 5) + 8;
BlockState logBlock = BlockTypes.OAK_LOG.getDefaultState();
BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState();
// Create trunk
for (int i = 0; i < trunkHeight; ++i) {
if (!setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock)) {
return;
}
}
// Move up
basePosition = basePosition.add(0, trunkHeight, 0);
// Create tree + leaves
for (int i = 0; i < height; ++i) {
setBlockIfAir(editSession, basePosition.add(0, i, 0), logBlock);
// Less leaves at these levels
double chance = ((i == 0 || i == height - 1) ? 0.6 : 1);
// Inner leaves
setChanceBlockIfAir(editSession, basePosition.add(-1, i, 0), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(1, i, 0), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(0, i, -1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(0, i, 1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(1, i, 1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(-1, i, 1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(1, i, -1), leavesBlock, chance);
setChanceBlockIfAir(editSession, basePosition.add(-1, i, -1), leavesBlock, chance);
if (!(i == 0 || i == height - 1)) {
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(-2, i, j), leavesBlock, 0.6);
}
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(2, i, j), leavesBlock, 0.6);
}
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(j, i, -2), leavesBlock, 0.6);
}
for (int j = -2; j <= 2; ++j) {
setChanceBlockIfAir(editSession, basePosition.add(j, i, 2), leavesBlock, 0.6);
}
}
}
setBlockIfAir(editSession, basePosition.add(0, height, 0), leavesBlock);
}
/**
* Looks up a tree type. May return null if a tree type by that
* name is not found.
*
* @param type the tree type
* @return a tree type or null
*/
@Nullable
public static TreeType lookup(String type) {
return TreeType.lookup(type);
}
/**
* Set a block (only if a previous block was not there) if {@link Math#random()}
* returns a number less than the given probability.
*
* @param position the position
* @param block the block
* @param probability a probability between 0 and 1, inclusive
* @return whether a block was changed
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
private static <B extends BlockStateHolder<B>> boolean setChanceBlockIfAir(EditSession session, BlockVector3 position, B block, double probability)
throws MaxChangedBlocksException {
return Math.random() <= probability && setBlockIfAir(session, position, block);
}
/**
* Set a block only if there's no block already there.
*
* @param position the position
* @param block the block to set
* @return if block was changed
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
private static <B extends BlockStateHolder<B>> boolean setBlockIfAir(EditSession session, BlockVector3 position, B block) throws MaxChangedBlocksException {
return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, block);
}
}

View File

@@ -1,23 +1,23 @@
/*
* 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.util.io.file;
/*
* 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.util.io.file;
import java.io.Closeable;
import java.nio.file.Path;

View File

@@ -1,23 +1,23 @@
/*
* 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.util.io.file;
/*
* 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.util.io.file;
import java.io.IOException;
import java.nio.file.Files;