mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-16 03:14:04 +00:00
Update BukkitImplLoader
This commit is contained in:
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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] + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user