mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-24 19:46:34 +01:00
Fixes #23
This commit is contained in:
parent
5b3e0973f2
commit
fff311a99f
@ -13,6 +13,7 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
@ -21,6 +22,8 @@ import org.bukkit.plugin.Plugin;
|
||||
*/
|
||||
public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
|
||||
protected World bukkitWorld;
|
||||
|
||||
/**
|
||||
* Map of chunks in the queue
|
||||
*/
|
||||
@ -47,6 +50,14 @@ public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
|
||||
// return false;
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(int x, int z) {
|
||||
if (bukkitWorld == null) {
|
||||
bukkitWorld = Bukkit.getServer().getWorld(world);
|
||||
}
|
||||
return bukkitWorld.regenerateChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTask(int x, int z, Runnable runnable) {
|
||||
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
|
||||
|
@ -132,16 +132,20 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
|
||||
lcz = cz;
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
if (Settings.CHUNK_WAIT > 0) {
|
||||
synchronized (loadQueue) {
|
||||
loadQueue.add(new IntegerPair(cx, cz));
|
||||
try {
|
||||
loadQueue.wait(Settings.CHUNK_WAIT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
if (Thread.currentThread() != Fawe.get().getMainThread()) {
|
||||
synchronized (loadQueue) {
|
||||
loadQueue.add(new IntegerPair(cx, cz));
|
||||
try {
|
||||
loadQueue.wait(Settings.CHUNK_WAIT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
return 0;
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
bukkitWorld.loadChunk(cx, cz, true);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
@ -316,7 +320,6 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
|
||||
private int lcy = Integer.MIN_VALUE;
|
||||
private Object lc;
|
||||
private char[] ls;
|
||||
private World bukkitWorld;
|
||||
|
||||
@Override
|
||||
public boolean setComponents(final FaweChunk<Chunk> fc) {
|
||||
|
@ -128,16 +128,20 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 {
|
||||
lcz = cz;
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
if (Settings.CHUNK_WAIT > 0) {
|
||||
synchronized (loadQueue) {
|
||||
loadQueue.add(new IntegerPair(cx, cz));
|
||||
try {
|
||||
loadQueue.wait(Settings.CHUNK_WAIT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
if (Thread.currentThread() != Fawe.get().getMainThread()) {
|
||||
synchronized (loadQueue) {
|
||||
loadQueue.add(new IntegerPair(cx, cz));
|
||||
try {
|
||||
loadQueue.wait(Settings.CHUNK_WAIT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
return 0;
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
bukkitWorld.loadChunk(cx, cz, true);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -16,6 +16,7 @@ import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.util.WESubscriber;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.SchematicCommands;
|
||||
import com.sk89q.worldedit.command.ScriptingCommands;
|
||||
@ -32,6 +33,7 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.history.change.EntityCreate;
|
||||
import com.sk89q.worldedit.history.change.EntityRemove;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
@ -154,9 +156,6 @@ public class Fawe {
|
||||
this.IMP.startMetrics();
|
||||
}
|
||||
|
||||
// // Delete old history
|
||||
// MainUtil.deleteDirectory(new File(IMP.getDirectory(), "history"));
|
||||
|
||||
// Delayed setup
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
@ -229,6 +228,8 @@ public class Fawe {
|
||||
EntityRemove.inject();
|
||||
LocalSession.inject();
|
||||
BlockArrayClipboard.inject();
|
||||
CuboidRegion.inject();
|
||||
Vector.inject();
|
||||
try {
|
||||
CommandManager.inject();
|
||||
} catch (Throwable e) {
|
||||
|
@ -20,7 +20,6 @@ import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
||||
/**
|
||||
* The FaweAPI class offers a few useful functions.<br>
|
||||
@ -42,90 +41,14 @@ public class FaweAPI {
|
||||
return (version[0] > major) || ((version[0] == major) && (version[1] > minor)) || ((version[0] == major) && (version[1] == minor) && (version[2] >= minor2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block at a location asynchronously
|
||||
* @param loc
|
||||
* @param m
|
||||
*/
|
||||
public static void setBlockAsync(final Location loc, final Material m) {
|
||||
SetQueue.IMP.setBlock(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), (short) m.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a block at a location asynchronously
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @param data
|
||||
*/
|
||||
public static void setBlockAsync(final String world, final int x, final int y, final int z, final short id, final byte data) {
|
||||
SetQueue.IMP.setBlock(world, x, y, z, id, data);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Set a biome at a location asynchronously
|
||||
// * @param world
|
||||
// * @param x
|
||||
// * @param z
|
||||
// * @param id
|
||||
// * @param data
|
||||
// */
|
||||
// public static void setBiomeAsync(final String world, final int x, final int z, final BaseBiome biome) {
|
||||
// SetQueue.IMP.setBiome(world, x, z, biome);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Set a biome at a location asynchronously
|
||||
// * @param loc
|
||||
// * @param biome
|
||||
// */
|
||||
// public static void setBiomeAsync(final Location loc, final BaseBiome biome) {
|
||||
// SetQueue.IMP.setBiome(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockZ(), biome);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * This will return a FaweChunk object that can be modified.<br>
|
||||
// * - The FaweChunk object can be reused if you want identical changes across chunks<br>
|
||||
// * - This is additive modification.<br>
|
||||
// * - First use {@link FaweChunk#fill(int, byte)} (e.g. with air) for absolute modification<br>
|
||||
// * When ready, use {@link #setChunk(FaweChunk, ChunkLoc)}
|
||||
// * @return
|
||||
// */
|
||||
// public static FaweChunk<?> createChunk() {
|
||||
// return SetQueue.IMP.queue.getChunk(new ChunkLoc(null, 0, 0));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @see #createChunk()
|
||||
// * @param data
|
||||
// * @param location
|
||||
// */
|
||||
// public static void setChunkAsync(final FaweChunk<?> data, final ChunkLoc location) {
|
||||
// data.setChunkLoc(location);
|
||||
// data.addToQueue();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @see #createChunk()
|
||||
// * @param data
|
||||
// * @param chunk
|
||||
// */
|
||||
// public static void setChunkAsync(final FaweChunk<?> data, final Chunk chunk) {
|
||||
// final ChunkLoc loc = new ChunkLoc(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
|
||||
// data.setChunkLoc(loc);
|
||||
// data.addToQueue();
|
||||
// }
|
||||
//
|
||||
public static void fixLighting(String world, int x, int z, final boolean fixAll) {
|
||||
FaweQueue queue = SetQueue.IMP.getQueue(world);
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(world);
|
||||
queue.fixLighting(queue.getChunk(x, z), fixAll);
|
||||
}
|
||||
|
||||
|
||||
public static void fixLighting(final Chunk chunk, final boolean fixAll) {
|
||||
FaweQueue queue = SetQueue.IMP.getQueue(chunk.getWorld().getName());
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(chunk.getWorld().getName());
|
||||
queue.fixLighting(queue.getChunk(chunk.getX(), chunk.getZ()), fixAll);
|
||||
}
|
||||
|
||||
@ -218,6 +141,8 @@ public class FaweAPI {
|
||||
tagMap = null;
|
||||
tag = null;
|
||||
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
final int yy = y_offset + y;
|
||||
if (yy > 255) {
|
||||
@ -298,10 +223,10 @@ public class FaweAPI {
|
||||
case 190:
|
||||
case 191:
|
||||
case 192:
|
||||
setBlockAsync(world, xx, yy, zz, id, (byte) 0);
|
||||
queue.setBlock(xx, yy, zz, id, (byte) 0);
|
||||
break;
|
||||
default: {
|
||||
setBlockAsync(world, xx, yy, zz, id, datas[i]);
|
||||
queue.setBlock(xx, yy, zz, id, datas[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -309,6 +234,8 @@ public class FaweAPI {
|
||||
}
|
||||
}
|
||||
|
||||
queue.enqueue();
|
||||
|
||||
ids = null;
|
||||
datas = null;
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
/**
|
||||
|
||||
/**
|
||||
*/
|
||||
public class FaweLocation {
|
||||
|
||||
@ -37,8 +36,4 @@ public class FaweLocation {
|
||||
public int hashCode() {
|
||||
return this.x << (8 + this.z) << (4 + this.y);
|
||||
}
|
||||
|
||||
public void setBlockAsync(final short id, final byte data) {
|
||||
SetQueue.IMP.setBlock(this.world, this.x, this.y, this.z, id, data);
|
||||
}
|
||||
}
|
||||
|
@ -224,9 +224,8 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
|
||||
}
|
||||
BlockVector position = new BlockVector(x, y, z);
|
||||
return dir ? new BlockChange(position, to, from) : new BlockChange(position, from, to);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,6 +25,8 @@ public abstract class FaweQueue {
|
||||
|
||||
public abstract boolean isChunkLoaded(final int x, final int z);
|
||||
|
||||
public abstract boolean regenerateChunk(int x, int z);
|
||||
|
||||
/**
|
||||
* Gets the FaweChunk and sets the requested blocks
|
||||
* @return
|
||||
@ -52,4 +54,8 @@ public abstract class FaweQueue {
|
||||
public abstract void addTask(int x, int z, Runnable runnable);
|
||||
|
||||
public abstract int getCombinedId4Data(int x, int y, int z);
|
||||
|
||||
public void enqueue() {
|
||||
SetQueue.IMP.enqueue(this);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,9 @@ package com.boydti.fawe.util;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class SetQueue {
|
||||
@ -18,7 +15,7 @@ public class SetQueue {
|
||||
*/
|
||||
public static final SetQueue IMP = new SetQueue();
|
||||
|
||||
public final Map<String, FaweQueue> queues;
|
||||
public final ArrayDeque<FaweQueue> queues;
|
||||
|
||||
/**
|
||||
* Track the time in ticks
|
||||
@ -39,7 +36,7 @@ public class SetQueue {
|
||||
|
||||
|
||||
public SetQueue() {
|
||||
queues = new ConcurrentHashMap<>();
|
||||
queues = new ArrayDeque();
|
||||
TaskManager.IMP.repeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -79,34 +76,24 @@ public class SetQueue {
|
||||
}, 1);
|
||||
}
|
||||
|
||||
public List<FaweQueue> getQueues() {
|
||||
List<FaweQueue> list = new ArrayList<>(queues.size());
|
||||
try {
|
||||
for (Map.Entry<String, FaweQueue> entry : queues.entrySet()) {
|
||||
list.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return list;
|
||||
public void enqueue(FaweQueue queue) {
|
||||
queues.add(queue);
|
||||
}
|
||||
|
||||
public FaweQueue getQueue(String world) {
|
||||
FaweQueue queue = queues.get(world);
|
||||
if (queue != null) {
|
||||
return queue;
|
||||
}
|
||||
queue = Fawe.imp().getNewQueue(world);
|
||||
queues.put(world, queue);
|
||||
return queue;
|
||||
public List<FaweQueue> getQueues() {
|
||||
return new ArrayList<>(queues);
|
||||
}
|
||||
|
||||
public FaweQueue getNewQueue(String world) {
|
||||
return Fawe.imp().getNewQueue(world);
|
||||
}
|
||||
|
||||
public FaweChunk<?> next() {
|
||||
for (Map.Entry<String, FaweQueue> entry : queues.entrySet()) {
|
||||
FaweQueue queue = entry.getValue();
|
||||
while (queues.size() > 0) {
|
||||
FaweQueue queue = queues.poll();
|
||||
final FaweChunk<?> set = queue.next();
|
||||
if (set != null ) {
|
||||
if (set != null) {
|
||||
queues.add(queue);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
@ -155,65 +142,4 @@ public class SetQueue {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean setBlock(final String world, final int x, final int y, final int z, final short id, final byte data) {
|
||||
SetQueue.IMP.setWaiting();
|
||||
return getQueue(world).setBlock(x, y, z, id, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean setBlock(final String world, final int x, final int y, final int z, final short id) {
|
||||
SetQueue.IMP.setWaiting();
|
||||
return getQueue(world).setBlock(x, y, z, id, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param world
|
||||
* @param x
|
||||
* @param z
|
||||
* @param biome
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean setBiome(final String world, final int x, final int z, final BaseBiome biome) {
|
||||
SetQueue.IMP.setWaiting();
|
||||
return getQueue(world).setBiome(x, z, biome);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isChunkLoaded(final String world, final int x, final int z) {
|
||||
return getQueue(world).isChunkLoaded(x, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task to run when the chunk is set<br>
|
||||
* @throws IllegalArgumentException if the chunk is not in the queue
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param runnable
|
||||
*/
|
||||
@Deprecated
|
||||
public void addTask(String world, int x, int y, int z, Runnable runnable) {
|
||||
getQueue(world).addTask(x >> 4, z >> 4, runnable);
|
||||
}
|
||||
}
|
||||
|
289
core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java
Normal file
289
core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java
Normal file
@ -0,0 +1,289 @@
|
||||
package com.boydti.fawe.wrappers;
|
||||
|
||||
import com.sk89q.worldedit.PlayerDirection;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.WorldVector;
|
||||
import com.sk89q.worldedit.WorldVectorFace;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||
import com.sk89q.worldedit.session.SessionKey;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.auth.AuthorizationException;
|
||||
import com.sk89q.worldedit.world.AbstractWorld;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlayerWrapper implements Player {
|
||||
private final Player parent;
|
||||
|
||||
public PlayerWrapper(Player parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return new WorldWrapper((AbstractWorld) parent.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHoldingPickAxe() {
|
||||
return parent.isHoldingPickAxe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerDirection getCardinalDirection(int yawOffset) {
|
||||
return parent.getCardinalDirection(yawOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemInHand() {
|
||||
return parent.getItemInHand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlockInHand() throws WorldEditException {
|
||||
return parent.getBlockInHand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void giveItem(int type, int amount) {
|
||||
parent.giveItem(type, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockBag getInventoryBlockBag() {
|
||||
return parent.getInventoryBlockBag();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCreativeMode() {
|
||||
return parent.hasCreativeMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findFreePosition(WorldVector searchPos) {
|
||||
parent.findFreePosition(searchPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnGround(WorldVector searchPos) {
|
||||
parent.setOnGround(searchPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findFreePosition() {
|
||||
parent.findFreePosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ascendLevel() {
|
||||
return parent.ascendLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean descendLevel() {
|
||||
return parent.descendLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ascendToCeiling(int clearance) {
|
||||
return parent.ascendToCeiling(clearance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ascendToCeiling(int clearance, boolean alwaysGlass) {
|
||||
return parent.ascendToCeiling(clearance, alwaysGlass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ascendUpwards(int distance) {
|
||||
return parent.ascendUpwards(distance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ascendUpwards(int distance, boolean alwaysGlass) {
|
||||
return parent.ascendUpwards(distance, alwaysGlass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
|
||||
parent.floatAt(x, y, z, alwaysGlass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldVector getBlockIn() {
|
||||
return parent.getBlockIn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldVector getBlockOn() {
|
||||
return parent.getBlockOn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldVector getBlockTrace(int range, boolean useLastBlock) {
|
||||
return parent.getBlockTrace(range, useLastBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldVectorFace getBlockTraceFace(int range, boolean useLastBlock) {
|
||||
return parent.getBlockTraceFace(range, useLastBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldVector getBlockTrace(int range) {
|
||||
return parent.getBlockTrace(range);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldVector getSolidBlockTrace(int range) {
|
||||
return parent.getSolidBlockTrace(range);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerDirection getCardinalDirection() {
|
||||
return parent.getCardinalDirection();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public WorldVector getPosition() {
|
||||
return parent.getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public double getPitch() {
|
||||
return parent.getPitch();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public double getYaw() {
|
||||
return parent.getYaw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passThroughForwardWall(int range) {
|
||||
return parent.passThroughForwardWall(range);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(Vector pos, float pitch, float yaw) {
|
||||
parent.setPosition(pos, pitch, yaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(Vector pos) {
|
||||
parent.setPosition(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BaseEntity getState() {
|
||||
return parent.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return parent.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getExtent() {
|
||||
return parent.getExtent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove() {
|
||||
return parent.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T getFacet(Class<? extends T> cls) {
|
||||
return parent.getFacet(cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return parent.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printRaw(String msg) {
|
||||
parent.printRaw(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printDebug(String msg) {
|
||||
parent.printDebug(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String msg) {
|
||||
parent.print(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printError(String msg) {
|
||||
parent.printError(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDestroyBedrock() {
|
||||
return parent.canDestroyBedrock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayer() {
|
||||
return parent.isPlayer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File openFileOpenDialog(String[] extensions) {
|
||||
return parent.openFileOpenDialog(extensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File openFileSaveDialog(String[] extensions) {
|
||||
return parent.openFileSaveDialog(extensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchCUIEvent(CUIEvent event) {
|
||||
parent.dispatchCUIEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return parent.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionKey getSessionKey() {
|
||||
return parent.getSessionKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getGroups() {
|
||||
return parent.getGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPermission(String permission) throws AuthorizationException {
|
||||
parent.checkPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return parent.hasPermission(permission);
|
||||
}
|
||||
}
|
336
core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java
Normal file
336
core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java
Normal file
@ -0,0 +1,336 @@
|
||||
package com.boydti.fawe.wrappers;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal;
|
||||
import com.sk89q.worldedit.BlockVector2D;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.world.AbstractWorld;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class WorldWrapper extends AbstractWorld {
|
||||
|
||||
private final AbstractWorld parent;
|
||||
|
||||
public WorldWrapper(AbstractWorld parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useItem(Vector position, BaseItem item, Direction face) {
|
||||
return parent.useItem(position, item, face);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return parent.getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidBlockType(int type) {
|
||||
return parent.isValidBlockType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesBlockData(int type) {
|
||||
return parent.usesBlockData(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask createLiquidMask() {
|
||||
return parent.createLiquidMask();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockType(Vector pt) {
|
||||
return parent.getBlockType(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockData(Vector pt) {
|
||||
return parent.getBlockData(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropItem(Vector pt, BaseItemStack item, int times) {
|
||||
parent.dropItem(pt, item, times);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulateBlockMine(Vector pt) {
|
||||
parent.simulateBlockMine(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException {
|
||||
return parent.generateTree(editSession, pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateBigTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException {
|
||||
return parent.generateBigTree(editSession, pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateBirchTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException {
|
||||
return parent.generateBirchTree(editSession, pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateRedwoodTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException {
|
||||
return parent.generateRedwoodTree(editSession, pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTallRedwoodTree(EditSession editSession, Vector pt) throws MaxChangedBlocksException {
|
||||
return parent.generateTallRedwoodTree(editSession, pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkLoadedChunk(Vector pt) {
|
||||
parent.checkLoadedChunk(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixAfterFastMode(Iterable<BlockVector2D> chunks) {
|
||||
parent.fixAfterFastMode(chunks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixLighting(Iterable<BlockVector2D> chunks) {
|
||||
parent.fixLighting(chunks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playEffect(Vector position, int type, int data) {
|
||||
return parent.playEffect(position, type, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean queueBlockBreakEffect(Platform server, Vector position, int blockId, double priority) {
|
||||
return parent.queueBlockBreakEffect(server, position, blockId, priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMinimumPoint() {
|
||||
return parent.getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMaximumPoint() {
|
||||
return parent.getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Operation commit() {
|
||||
return parent.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return parent.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException {
|
||||
return parent.setBlock(position, block, notifyAndLight);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getBlockLightLevel(Vector position) {
|
||||
return parent.getBlockLightLevel(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearContainerBlockContents(Vector position) {
|
||||
return parent.clearContainerBlockContents(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropItem(Vector position, BaseItemStack item) {
|
||||
parent.dropItem(position, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(final Region region, EditSession session) {
|
||||
final FaweQueue queue = session.getQueue();
|
||||
final FaweChangeSet fcs = (FaweChangeSet) session.getChangeSet();
|
||||
session.setChangeSet(fcs);
|
||||
final CuboidRegion cb = (CuboidRegion) region;
|
||||
final boolean cuboid = region instanceof CuboidRegion;
|
||||
Set<Vector2D> chunks = region.getChunks();
|
||||
TaskManager.IMP.objectTask(chunks, new RunnableVal<Vector2D>() {
|
||||
@Override
|
||||
public void run(Vector2D chunk) {
|
||||
int cx = chunk.getBlockX();
|
||||
int cz = chunk.getBlockZ();
|
||||
int bx = cx << 4;
|
||||
int bz = cz << 4;
|
||||
Vector cmin = new Vector(bx, 0, bz);
|
||||
Vector cmax = cmin.add(15, getMaxY(), 15);
|
||||
if (cuboid && region.contains(cmin) && region.contains(cmax)) {
|
||||
if (fcs != null) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int xx = x + bx;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = z + bz;
|
||||
for (int y = 0; y < getMaxY() + 1; y++) {
|
||||
int from = queue.getCombinedId4Data(xx, y, zz);
|
||||
if (!FaweCache.hasNBT(from >> 4)) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
} else {
|
||||
try {
|
||||
Vector loc = new Vector(xx, y, zz);
|
||||
BaseBlock block = getLazyBlock(loc);
|
||||
fcs.add(loc, block, FaweCache.CACHE_BLOCK[0]);
|
||||
} catch (Throwable e) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int xx = x + bx;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = z + bz;
|
||||
for (int y = 0; y < getMaxY() + 1; y++) {
|
||||
final Vector loc = new Vector(xx, y, zz);
|
||||
int from = queue.getCombinedId4Data(xx, y, zz);
|
||||
if (region.contains(loc)) {
|
||||
if (fcs != null) {
|
||||
if (!FaweCache.hasNBT(from >> 4)) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
} else {
|
||||
try {
|
||||
|
||||
BaseBlock block = getLazyBlock(loc);
|
||||
fcs.add(loc, block, FaweCache.CACHE_BLOCK[0]);
|
||||
} catch (Throwable e) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
short id = (short) (from >> 4);
|
||||
byte data = (byte) (from & 0xf);
|
||||
if (!FaweCache.hasNBT(id)) {
|
||||
queue.setBlock(xx, y, zz, id, data);
|
||||
} else {
|
||||
try {
|
||||
final BaseBlock block = getLazyBlock(loc);
|
||||
queue.addTask(cx, cz, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
setBlock(loc, block, false);
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
queue.setBlock(xx, y, zz, id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
queue.regenerateChunk(cx, cz);
|
||||
}
|
||||
}, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
queue.enqueue();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return parent.generateTree(type, editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldData getWorldData() {
|
||||
return parent.getWorldData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return parent.equals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return parent.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(Region region) {
|
||||
return parent.getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return parent.getEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entity createEntity(Location location, BaseEntity entity) {
|
||||
return parent.createEntity(location, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return parent.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
return parent.getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
return parent.getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
return parent.setBiome(position, biome);
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BlockID;
|
||||
@ -113,6 +114,7 @@ import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.util.collection.DoubleArrayList;
|
||||
import com.sk89q.worldedit.util.eventbus.EventBus;
|
||||
import com.sk89q.worldedit.world.AbstractWorld;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayDeque;
|
||||
@ -155,7 +157,7 @@ public class EditSession implements Extent {
|
||||
BEFORE_HISTORY, BEFORE_REORDER, BEFORE_CHANGE
|
||||
}
|
||||
|
||||
protected final World world;
|
||||
private World world;
|
||||
private FaweChangeSet changeSet;
|
||||
private final EditSessionWrapper wrapper;
|
||||
private MaskingExtent maskingExtent;
|
||||
@ -208,17 +210,13 @@ public class EditSession implements Extent {
|
||||
* @param blockBag an optional {@link BlockBag} to use, otherwise null
|
||||
* @param event the event to call with the extent
|
||||
*/
|
||||
public EditSession(final EventBus eventBus, final World world, final int maxBlocks, @Nullable final BlockBag blockBag, final EditSessionEvent event) {
|
||||
public EditSession(final EventBus eventBus, World world, final int maxBlocks, @Nullable final BlockBag blockBag, final EditSessionEvent event) {
|
||||
checkNotNull(eventBus);
|
||||
checkArgument(maxBlocks >= -1, "maxBlocks >= -1 required");
|
||||
checkNotNull(event);
|
||||
|
||||
// Wrap world
|
||||
this.blockBag = blockBag;
|
||||
this.maxBlocks = maxBlocks;
|
||||
this.world = world;
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
// this.changeSet = new BlockOptimizedHistory();
|
||||
|
||||
// Invalid; return null extent
|
||||
if (world == null) {
|
||||
final Extent extent = new NullExtent();
|
||||
@ -226,10 +224,13 @@ public class EditSession implements Extent {
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
this.changeSet = new NullChangeSet();
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
return;
|
||||
}
|
||||
final Actor actor = event.getActor();
|
||||
this.queue = SetQueue.IMP.getQueue(world.getName());
|
||||
this.queue = SetQueue.IMP.getNewQueue(world.getName());
|
||||
this.world = (world = new WorldWrapper((AbstractWorld) world));
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
// Not a player; bypass history
|
||||
if ((actor == null) || !actor.isPlayer()) {
|
||||
Extent extent = new FastWorldEditExtent(world, queue);
|
||||
@ -339,6 +340,10 @@ public class EditSession implements Extent {
|
||||
return;
|
||||
}
|
||||
|
||||
public FaweQueue getQueue() {
|
||||
return queue;
|
||||
}
|
||||
|
||||
private Extent wrapExtent(final Extent extent, final EventBus eventBus, EditSessionEvent event, final Stage stage) {
|
||||
event = event.clone(stage);
|
||||
event.setExtent(extent);
|
||||
@ -853,6 +858,9 @@ public class EditSession implements Extent {
|
||||
@Override
|
||||
public void run() {
|
||||
Operations.completeBlindly(EditSession.this.commit());
|
||||
if (queue != null) {
|
||||
queue.enqueue();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -2069,10 +2077,15 @@ public class EditSession implements Extent {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (MaxChangedBlocksException ignore) {
|
||||
}
|
||||
catch (MaxChangedBlocksException ignore) {}
|
||||
}
|
||||
}, null);
|
||||
}, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
queue.enqueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.changes = -1;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
package com.sk89q.worldedit;
|
||||
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.sk89q.jchronic.Chronic;
|
||||
import com.sk89q.jchronic.Options;
|
||||
import com.sk89q.jchronic.utils.Span;
|
||||
@ -191,6 +192,10 @@ public class LocalSession {
|
||||
public void remember(EditSession editSession) {
|
||||
checkNotNull(editSession);
|
||||
|
||||
if (editSession.getQueue() != null) {
|
||||
SetQueue.IMP.enqueue(editSession.getQueue());
|
||||
}
|
||||
|
||||
// Don't store anything if no changes were made
|
||||
if (editSession.size() == 0) return;
|
||||
|
||||
|
853
core/src/main/java/com/sk89q/worldedit/Vector.java
Normal file
853
core/src/main/java/com/sk89q/worldedit/Vector.java
Normal file
@ -0,0 +1,853 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An immutable 3-dimensional vector.
|
||||
*/
|
||||
public class Vector implements Comparable<Vector> {
|
||||
|
||||
public static final Vector ZERO = new Vector(0, 0, 0);
|
||||
public static final Vector UNIT_X = new Vector(1, 0, 0);
|
||||
public static final Vector UNIT_Y = new Vector(0, 1, 0);
|
||||
public static final Vector UNIT_Z = new Vector(0, 0, 1);
|
||||
public static final Vector ONE = new Vector(1, 1, 1);
|
||||
|
||||
public double x, y, z;
|
||||
|
||||
/**
|
||||
* Construct an instance.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @param z the Z coordinate
|
||||
*/
|
||||
public Vector(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @param z the Z coordinate
|
||||
*/
|
||||
public Vector(int x, int y, int z) {
|
||||
this.x = (double) x;
|
||||
this.y = (double) y;
|
||||
this.z = (double) z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @param z the Z coordinate
|
||||
*/
|
||||
public Vector(float x, float y, float z) {
|
||||
this.x = (double) x;
|
||||
this.y = (double) y;
|
||||
this.z = (double) z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy another vector.
|
||||
*
|
||||
* @param other another vector to make a copy of
|
||||
*/
|
||||
public Vector(Vector other) {
|
||||
this.x = other.x;
|
||||
this.y = other.y;
|
||||
this.z = other.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance with X, Y, and Z coordinates set to 0.
|
||||
*
|
||||
* <p>One can also refer to a static {@link #ZERO}.</p>
|
||||
*/
|
||||
public Vector() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X coordinate.
|
||||
*
|
||||
* @return the x coordinate
|
||||
*/
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X coordinate rounded.
|
||||
*
|
||||
* @return the x coordinate
|
||||
*/
|
||||
public int getBlockX() {
|
||||
return (int) Math.round(x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the X coordinate.
|
||||
*
|
||||
* @param x the new X
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector setX(double x) {
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the X coordinate.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @return new vector
|
||||
*/
|
||||
public Vector setX(int x) {
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y coordinate.
|
||||
*
|
||||
* @return the y coordinate
|
||||
*/
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y coordinate rounded.
|
||||
*
|
||||
* @return the y coordinate
|
||||
*/
|
||||
public int getBlockY() {
|
||||
return (int) Math.round(y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Y coordinate.
|
||||
*
|
||||
* @param y the new Y
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector setY(double y) {
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Y coordinate.
|
||||
*
|
||||
* @param y the new Y
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector setY(int y) {
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Z coordinate.
|
||||
*
|
||||
* @return the z coordinate
|
||||
*/
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Z coordinate rounded.
|
||||
*
|
||||
* @return the z coordinate
|
||||
*/
|
||||
public int getBlockZ() {
|
||||
return (int) Math.round(z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Z coordinate.
|
||||
*
|
||||
* @param z the new Z
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector setZ(double z) {
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Z coordinate.
|
||||
*
|
||||
* @param z the new Z
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector setZ(int z) {
|
||||
return new Vector(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another vector to this vector and return the result as a new vector.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector add(Vector other) {
|
||||
return new Vector(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another vector to this vector and return the result as a new vector.
|
||||
*
|
||||
* @param x the value to add
|
||||
* @param y the value to add
|
||||
* @param z the value to add
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector add(double x, double y, double z) {
|
||||
return new Vector(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another vector to this vector and return the result as a new vector.
|
||||
*
|
||||
* @param x the value to add
|
||||
* @param y the value to add
|
||||
* @param z the value to add
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector add(int x, int y, int z) {
|
||||
return new Vector(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of vectors to this vector and return the
|
||||
* result as a new vector.
|
||||
*
|
||||
* @param others an array of vectors
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector add(Vector... others) {
|
||||
double newX = x, newY = y, newZ = z;
|
||||
|
||||
for (Vector other : others) {
|
||||
newX += other.x;
|
||||
newY += other.y;
|
||||
newZ += other.z;
|
||||
}
|
||||
|
||||
return new Vector(newX, newY, newZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract another vector from this vector and return the result
|
||||
* as a new vector.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector subtract(Vector other) {
|
||||
return new Vector(x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract another vector from this vector and return the result
|
||||
* as a new vector.
|
||||
*
|
||||
* @param x the value to subtract
|
||||
* @param y the value to subtract
|
||||
* @param z the value to subtract
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector subtract(double x, double y, double z) {
|
||||
return new Vector(this.x - x, this.y - y, this.z - z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract another vector from this vector and return the result
|
||||
* as a new vector.
|
||||
*
|
||||
* @param x the value to subtract
|
||||
* @param y the value to subtract
|
||||
* @param z the value to subtract
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector subtract(int x, int y, int z) {
|
||||
return new Vector(this.x - x, this.y - y, this.z - z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract a list of vectors from this vector and return the result
|
||||
* as a new vector.
|
||||
*
|
||||
* @param others an array of vectors
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector subtract(Vector... others) {
|
||||
double newX = x, newY = y, newZ = z;
|
||||
|
||||
for (Vector other : others) {
|
||||
newX -= other.x;
|
||||
newY -= other.y;
|
||||
newZ -= other.z;
|
||||
}
|
||||
|
||||
return new Vector(newX, newY, newZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply this vector by another vector on each component.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(Vector other) {
|
||||
return new Vector(x * other.x, y * other.y, z * other.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply this vector by another vector on each component.
|
||||
*
|
||||
* @param x the value to multiply
|
||||
* @param y the value to multiply
|
||||
* @param z the value to multiply
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(double x, double y, double z) {
|
||||
return new Vector(this.x * x, this.y * y, this.z * z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply this vector by another vector on each component.
|
||||
*
|
||||
* @param x the value to multiply
|
||||
* @param y the value to multiply
|
||||
* @param z the value to multiply
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(int x, int y, int z) {
|
||||
return new Vector(this.x * x, this.y * y, this.z * z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply this vector by zero or more vectors on each component.
|
||||
*
|
||||
* @param others an array of vectors
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(Vector... others) {
|
||||
double newX = x, newY = y, newZ = z;
|
||||
|
||||
for (Vector other : others) {
|
||||
newX *= other.x;
|
||||
newY *= other.y;
|
||||
newZ *= other.z;
|
||||
}
|
||||
|
||||
return new Vector(newX, newY, newZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scalar multiplication and return a new vector.
|
||||
*
|
||||
* @param n the value to multiply
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(double n) {
|
||||
return new Vector(this.x * n, this.y * n, this.z * n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scalar multiplication and return a new vector.
|
||||
*
|
||||
* @param n the value to multiply
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(float n) {
|
||||
return new Vector(this.x * n, this.y * n, this.z * n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scalar multiplication and return a new vector.
|
||||
*
|
||||
* @param n the value to multiply
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector multiply(int n) {
|
||||
return new Vector(this.x * n, this.y * n, this.z * n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide this vector by another vector on each component.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector divide(Vector other) {
|
||||
return new Vector(x / other.x, y / other.y, z / other.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide this vector by another vector on each component.
|
||||
*
|
||||
* @param x the value to divide by
|
||||
* @param y the value to divide by
|
||||
* @param z the value to divide by
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector divide(double x, double y, double z) {
|
||||
return new Vector(this.x / x, this.y / y, this.z / z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide this vector by another vector on each component.
|
||||
*
|
||||
* @param x the value to divide by
|
||||
* @param y the value to divide by
|
||||
* @param z the value to divide by
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector divide(int x, int y, int z) {
|
||||
return new Vector(this.x / x, this.y / y, this.z / z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scalar division and return a new vector.
|
||||
*
|
||||
* @param n the value to divide by
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector divide(int n) {
|
||||
return new Vector(x / n, y / n, z / n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scalar division and return a new vector.
|
||||
*
|
||||
* @param n the value to divide by
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector divide(double n) {
|
||||
return new Vector(x / n, y / n, z / n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scalar division and return a new vector.
|
||||
*
|
||||
* @param n the value to divide by
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector divide(float n) {
|
||||
return new Vector(x / n, y / n, z / n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of the vector.
|
||||
*
|
||||
* @return length
|
||||
*/
|
||||
public double length() {
|
||||
return Math.sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length, squared, of the vector.
|
||||
*
|
||||
* @return length, squared
|
||||
*/
|
||||
public double lengthSq() {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance between this vector and another vector.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return distance
|
||||
*/
|
||||
public double distance(Vector other) {
|
||||
return Math.sqrt(Math.pow(other.x - x, 2) +
|
||||
Math.pow(other.y - y, 2) +
|
||||
Math.pow(other.z - z, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance between this vector and another vector, squared.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return distance
|
||||
*/
|
||||
public double distanceSq(Vector other) {
|
||||
return Math.pow(other.x - x, 2) +
|
||||
Math.pow(other.y - y, 2) +
|
||||
Math.pow(other.z - z, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the normalized vector, which is the vector divided by its
|
||||
* length, as a new vector.
|
||||
*
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector normalize() {
|
||||
return divide(length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dot product of this and another vector.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return the dot product of this and the other vector
|
||||
*/
|
||||
public double dot(Vector other) {
|
||||
return x * other.x + y * other.y + z * other.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cross product of this and another vector.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return the cross product of this and the other vector
|
||||
*/
|
||||
public Vector cross(Vector other) {
|
||||
return new Vector(
|
||||
y * other.z - z * other.y,
|
||||
z * other.x - x * other.z,
|
||||
x * other.y - y * other.x
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a vector is contained with another.
|
||||
*
|
||||
* @param min the minimum point (X, Y, and Z are the lowest)
|
||||
* @param max the maximum point (X, Y, and Z are the lowest)
|
||||
* @return true if the vector is contained
|
||||
*/
|
||||
public boolean containedWithin(Vector min, Vector max) {
|
||||
return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a vector is contained with another, comparing
|
||||
* using discrete comparisons, inclusively.
|
||||
*
|
||||
* @param min the minimum point (X, Y, and Z are the lowest)
|
||||
* @param max the maximum point (X, Y, and Z are the lowest)
|
||||
* @return true if the vector is contained
|
||||
*/
|
||||
public boolean containedWithinBlock(Vector min, Vector max) {
|
||||
return getBlockX() >= min.getBlockX() && getBlockX() <= max.getBlockX()
|
||||
&& getBlockY() >= min.getBlockY() && getBlockY() <= max.getBlockY()
|
||||
&& getBlockZ() >= min.getBlockZ() && getBlockZ() <= max.getBlockZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamp the Y component.
|
||||
*
|
||||
* @param min the minimum value
|
||||
* @param max the maximum value
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector clampY(int min, int max) {
|
||||
return new Vector(x, Math.max(min, Math.min(max, y)), z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Floors the values of all components.
|
||||
*
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector floor() {
|
||||
return new Vector(Math.floor(x), Math.floor(y), Math.floor(z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds all components up.
|
||||
*
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector ceil() {
|
||||
return new Vector(Math.ceil(x), Math.ceil(y), Math.ceil(z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds all components to the closest integer.
|
||||
*
|
||||
* <p>Components < 0.5 are rounded down, otherwise up.</p>
|
||||
*
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector round() {
|
||||
return new Vector(Math.floor(x + 0.5), Math.floor(y + 0.5), Math.floor(z + 0.5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a vector with the absolute values of the components of
|
||||
* this vector.
|
||||
*
|
||||
* @return a new vector
|
||||
*/
|
||||
public Vector positive() {
|
||||
return new Vector(Math.abs(x), Math.abs(y), Math.abs(z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a 2D transformation on this vector and return a new one.
|
||||
*
|
||||
* @param angle in degrees
|
||||
* @param aboutX about which x coordinate to rotate
|
||||
* @param aboutZ about which z coordinate to rotate
|
||||
* @param translateX what to add after rotation
|
||||
* @param translateZ what to add after rotation
|
||||
* @return a new vector
|
||||
* @see AffineTransform another method to transform vectors
|
||||
*/
|
||||
public Vector transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) {
|
||||
angle = Math.toRadians(angle);
|
||||
double x = this.x - aboutX;
|
||||
double z = this.z - aboutZ;
|
||||
double x2 = x * Math.cos(angle) - z * Math.sin(angle);
|
||||
double z2 = x * Math.sin(angle) + z * Math.cos(angle);
|
||||
|
||||
return new Vector(
|
||||
x2 + aboutX + translateX,
|
||||
y,
|
||||
z2 + aboutZ + translateZ
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vector is collinear with another vector.
|
||||
*
|
||||
* @param other the other vector
|
||||
* @return true if collinear
|
||||
*/
|
||||
public boolean isCollinearWith(Vector other) {
|
||||
if (x == 0 && y == 0 && z == 0) {
|
||||
// this is a zero vector
|
||||
return true;
|
||||
}
|
||||
|
||||
final double otherX = other.x;
|
||||
final double otherY = other.y;
|
||||
final double otherZ = other.z;
|
||||
|
||||
if (otherX == 0 && otherY == 0 && otherZ == 0) {
|
||||
// other is a zero vector
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((x == 0) != (otherX == 0)) return false;
|
||||
if ((y == 0) != (otherY == 0)) return false;
|
||||
if ((z == 0) != (otherZ == 0)) return false;
|
||||
|
||||
final double quotientX = otherX / x;
|
||||
if (!Double.isNaN(quotientX)) {
|
||||
return other.equals(multiply(quotientX));
|
||||
}
|
||||
|
||||
final double quotientY = otherY / y;
|
||||
if (!Double.isNaN(quotientY)) {
|
||||
return other.equals(multiply(quotientY));
|
||||
}
|
||||
|
||||
final double quotientZ = otherZ / z;
|
||||
if (!Double.isNaN(quotientZ)) {
|
||||
return other.equals(multiply(quotientZ));
|
||||
}
|
||||
|
||||
throw new RuntimeException("This should not happen");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this vector's pitch as used within the game.
|
||||
*
|
||||
* @return pitch in radians
|
||||
*/
|
||||
public float toPitch() {
|
||||
double x = getX();
|
||||
double z = getZ();
|
||||
|
||||
if (x == 0 && z == 0) {
|
||||
return getY() > 0 ? -90 : 90;
|
||||
} else {
|
||||
double x2 = x * x;
|
||||
double z2 = z * z;
|
||||
double xz = Math.sqrt(x2 + z2);
|
||||
return (float) Math.toDegrees(Math.atan(-getY() / xz));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this vector's yaw as used within the game.
|
||||
*
|
||||
* @return yaw in radians
|
||||
*/
|
||||
public float toYaw() {
|
||||
double x = getX();
|
||||
double z = getZ();
|
||||
|
||||
double t = Math.atan2(-x, z);
|
||||
double _2pi = 2 * Math.PI;
|
||||
|
||||
return (float) Math.toDegrees(((t + _2pi) % _2pi));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code BlockVector} using the given components.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @param z the Z coordinate
|
||||
* @return a new {@code BlockVector}
|
||||
*/
|
||||
public static BlockVector toBlockPoint(double x, double y, double z) {
|
||||
return new BlockVector(
|
||||
Math.floor(x),
|
||||
Math.floor(y),
|
||||
Math.floor(z)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code BlockVector} from this vector.
|
||||
*
|
||||
* @return a new {@code BlockVector}
|
||||
*/
|
||||
public BlockVector toBlockPoint() {
|
||||
return new BlockVector(
|
||||
Math.floor(x),
|
||||
Math.floor(y),
|
||||
Math.floor(z)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code BlockVector} from this vector.
|
||||
*
|
||||
* @return a new {@code BlockVector}
|
||||
*/
|
||||
public BlockVector toBlockVector() {
|
||||
return new BlockVector(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a 2D vector by dropping the Y component from this vector.
|
||||
*
|
||||
* @return a new {@code Vector2D}
|
||||
*/
|
||||
public Vector2D toVector2D() {
|
||||
return new Vector2D(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Vector)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector other = (Vector) obj;
|
||||
return other.x == this.x && other.y == this.y && other.z == this.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nullable Vector other) {
|
||||
if (other == null) {
|
||||
throw new IllegalArgumentException("null not supported");
|
||||
}
|
||||
if (y != other.y) return Double.compare(y, other.y);
|
||||
if (z != other.z) return Double.compare(z, other.z);
|
||||
if (x != other.x) return Double.compare(x, other.x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + x + ", " + y + ", " + z + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum components of two vectors.
|
||||
*
|
||||
* @param v1 the first vector
|
||||
* @param v2 the second vector
|
||||
* @return minimum
|
||||
*/
|
||||
public static Vector getMinimum(Vector v1, Vector v2) {
|
||||
return new Vector(
|
||||
Math.min(v1.x, v2.x),
|
||||
Math.min(v1.y, v2.y),
|
||||
Math.min(v1.z, v2.z)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum components of two vectors.
|
||||
*
|
||||
* @param v1 the first vector
|
||||
* @param v2 the second vector
|
||||
* @return maximum
|
||||
*/
|
||||
public static Vector getMaximum(Vector v1, Vector v2) {
|
||||
return new Vector(
|
||||
Math.max(v1.x, v2.x),
|
||||
Math.max(v1.y, v2.y),
|
||||
Math.max(v1.z, v2.z)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the midpoint of two vectors.
|
||||
*
|
||||
* @param v1 the first vector
|
||||
* @param v2 the second vector
|
||||
* @return maximum
|
||||
*/
|
||||
public static Vector getMidpoint(Vector v1, Vector v2) {
|
||||
return new Vector(
|
||||
(v1.x + v2.x) / 2,
|
||||
(v1.y + v2.y) / 2,
|
||||
(v1.z + v2.z) / 2
|
||||
);
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return Vector.class;
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.PlayerWrapper;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
@ -59,6 +60,7 @@ import com.sk89q.worldedit.command.composition.DeformCommand;
|
||||
import com.sk89q.worldedit.command.composition.PaintCommand;
|
||||
import com.sk89q.worldedit.command.composition.SelectionCommand;
|
||||
import com.sk89q.worldedit.command.composition.ShapedBrushCommand;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||
import com.sk89q.worldedit.function.factory.Deform;
|
||||
@ -234,7 +236,11 @@ public final class CommandManager {
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
|
||||
CommandLocals locals = new CommandLocals();
|
||||
locals.put(Actor.class, actor);
|
||||
if (actor != null && actor.isPlayer()) {
|
||||
locals.put(Actor.class, new PlayerWrapper((Player) actor));
|
||||
} else {
|
||||
locals.put(Actor.class, actor);
|
||||
}
|
||||
locals.put("arguments", event.getArguments());
|
||||
|
||||
final long start = System.currentTimeMillis();
|
||||
|
@ -58,7 +58,6 @@ public class RegionVisitor implements Operation {
|
||||
affected++;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
470
core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java
Normal file
470
core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java
Normal file
@ -0,0 +1,470 @@
|
||||
/*
|
||||
* 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.regions;
|
||||
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.storage.ChunkStore;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An axis-aligned cuboid. It can be defined using two corners of the cuboid.
|
||||
*/
|
||||
public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
||||
|
||||
private Vector pos1;
|
||||
private Vector pos2;
|
||||
|
||||
/**
|
||||
* Construct a new instance of this cuboid using two corners of the cuboid.
|
||||
*
|
||||
* @param pos1 the first position
|
||||
* @param pos2 the second position
|
||||
*/
|
||||
public CuboidRegion(Vector pos1, Vector pos2) {
|
||||
this(null, pos1, pos2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated cast {@code world} to {@link World}
|
||||
*/
|
||||
@Deprecated
|
||||
public CuboidRegion(LocalWorld world, Vector pos1, Vector pos2) {
|
||||
this((World) world, pos1, pos2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance of this cuboid using two corners of the cuboid.
|
||||
*
|
||||
* @param world the world
|
||||
* @param pos1 the first position
|
||||
* @param pos2 the second position
|
||||
*/
|
||||
public CuboidRegion(World world, Vector pos1, Vector pos2) {
|
||||
super(world);
|
||||
checkNotNull(pos1);
|
||||
checkNotNull(pos2);
|
||||
this.pos1 = pos1;
|
||||
this.pos2 = pos2;
|
||||
recalculate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first cuboid-defining corner.
|
||||
*
|
||||
* @return a position
|
||||
*/
|
||||
public Vector getPos1() {
|
||||
return pos1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the first cuboid-defining corner.
|
||||
*
|
||||
* @param pos1 a position
|
||||
*/
|
||||
public void setPos1(Vector pos1) {
|
||||
this.pos1 = pos1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the second cuboid-defining corner.
|
||||
*
|
||||
* @return a position
|
||||
*/
|
||||
public Vector getPos2() {
|
||||
return pos2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the second cuboid-defining corner.
|
||||
*
|
||||
* @param pos2 a position
|
||||
*/
|
||||
public void setPos2(Vector pos2) {
|
||||
this.pos2 = pos2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the cuboid according to boundaries of the world.
|
||||
*/
|
||||
private void recalculate() {
|
||||
pos1 = pos1.clampY(0, world == null ? 255 : world.getMaxY());
|
||||
pos2 = pos2.clampY(0, world == null ? 255 : world.getMaxY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a region that contains the faces of this cuboid.
|
||||
*
|
||||
* @return a new complex region
|
||||
*/
|
||||
public Region getFaces() {
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
return new RegionIntersection(
|
||||
// Project to Z-Y plane
|
||||
new CuboidRegion(pos1.setX(min.getX()), pos2.setX(min.getX())),
|
||||
new CuboidRegion(pos1.setX(max.getX()), pos2.setX(max.getX())),
|
||||
|
||||
// Project to X-Y plane
|
||||
new CuboidRegion(pos1.setZ(min.getZ()), pos2.setZ(min.getZ())),
|
||||
new CuboidRegion(pos1.setZ(max.getZ()), pos2.setZ(max.getZ())),
|
||||
|
||||
// Project to the X-Z plane
|
||||
new CuboidRegion(pos1.setY(min.getY()), pos2.setY(min.getY())),
|
||||
new CuboidRegion(pos1.setY(max.getY()), pos2.setY(max.getY())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a region that contains the walls (all faces but the ones parallel to
|
||||
* the X-Z plane) of this cuboid.
|
||||
*
|
||||
* @return a new complex region
|
||||
*/
|
||||
public Region getWalls() {
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
return new RegionIntersection(
|
||||
// Project to Z-Y plane
|
||||
new CuboidRegion(pos1.setX(min.getX()), pos2.setX(min.getX())),
|
||||
new CuboidRegion(pos1.setX(max.getX()), pos2.setX(max.getX())),
|
||||
|
||||
// Project to X-Y plane
|
||||
new CuboidRegion(pos1.setZ(min.getZ()), pos2.setZ(min.getZ())),
|
||||
new CuboidRegion(pos1.setZ(max.getZ()), pos2.setZ(max.getZ())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMinimumPoint() {
|
||||
return new Vector(Math.min(pos1.getX(), pos2.getX()),
|
||||
Math.min(pos1.getY(), pos2.getY()),
|
||||
Math.min(pos1.getZ(), pos2.getZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMaximumPoint() {
|
||||
return new Vector(Math.max(pos1.getX(), pos2.getX()),
|
||||
Math.max(pos1.getY(), pos2.getY()),
|
||||
Math.max(pos1.getZ(), pos2.getZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumY() {
|
||||
return Math.min(pos1.getBlockY(), pos2.getBlockY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumY() {
|
||||
return Math.max(pos1.getBlockY(), pos2.getBlockY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expand(Vector... changes) {
|
||||
checkNotNull(changes);
|
||||
|
||||
for (Vector change : changes) {
|
||||
if (change.getX() > 0) {
|
||||
if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) {
|
||||
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
|
||||
}
|
||||
} else {
|
||||
if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) {
|
||||
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (change.getY() > 0) {
|
||||
if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) {
|
||||
pos1 = pos1.add(new Vector(0, change.getY(), 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, change.getY(), 0));
|
||||
}
|
||||
} else {
|
||||
if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) {
|
||||
pos1 = pos1.add(new Vector(0, change.getY(), 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, change.getY(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (change.getZ() > 0) {
|
||||
if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
|
||||
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
|
||||
}
|
||||
} else {
|
||||
if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
|
||||
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recalculate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contract(Vector... changes) {
|
||||
checkNotNull(changes);
|
||||
|
||||
for (Vector change : changes) {
|
||||
if (change.getX() < 0) {
|
||||
if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) {
|
||||
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
|
||||
}
|
||||
} else {
|
||||
if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) {
|
||||
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (change.getY() < 0) {
|
||||
if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) {
|
||||
pos1 = pos1.add(new Vector(0, change.getY(), 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, change.getY(), 0));
|
||||
}
|
||||
} else {
|
||||
if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) {
|
||||
pos1 = pos1.add(new Vector(0, change.getY(), 0));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, change.getY(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (change.getZ() < 0) {
|
||||
if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
|
||||
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
|
||||
}
|
||||
} else {
|
||||
if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
|
||||
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
|
||||
} else {
|
||||
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recalculate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shift(Vector change) throws RegionOperationException {
|
||||
pos1 = pos1.add(change);
|
||||
pos2 = pos2.add(change);
|
||||
|
||||
recalculate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Vector2D> getChunks() {
|
||||
Set<Vector2D> chunks = new HashSet<Vector2D>();
|
||||
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) {
|
||||
for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) {
|
||||
chunks.add(new BlockVector2D(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Vector> getChunkCubes() {
|
||||
Set<Vector> chunks = new HashSet<Vector>();
|
||||
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
for (int x = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x <= max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; ++x) {
|
||||
for (int z = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z <= max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; ++z) {
|
||||
for (int y = min.getBlockY() >> ChunkStore.CHUNK_SHIFTS; y <= max.getBlockY() >> ChunkStore.CHUNK_SHIFTS; ++y) {
|
||||
chunks.add(new BlockVector(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Vector position) {
|
||||
double x = position.getX();
|
||||
double y = position.getY();
|
||||
double z = position.getZ();
|
||||
|
||||
Vector min = getMinimumPoint();
|
||||
Vector max = getMaximumPoint();
|
||||
|
||||
return x >= min.getBlockX() && x <= max.getBlockX()
|
||||
&& y >= min.getBlockY() && y <= max.getBlockY()
|
||||
&& z >= min.getBlockZ() && z <= max.getBlockZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<BlockVector> iterator() {
|
||||
final BlockVector v = new BlockVector(0,0,0);
|
||||
return new Iterator<BlockVector>() {
|
||||
private Vector min = getMinimumPoint();
|
||||
private Vector max = getMaximumPoint();
|
||||
|
||||
int minX = min.getBlockX();
|
||||
int minY = min.getBlockY();
|
||||
int minZ = min.getBlockZ();
|
||||
|
||||
int maxX = max.getBlockX();
|
||||
int maxY = max.getBlockY();
|
||||
int maxZ = max.getBlockZ();
|
||||
|
||||
private int nextX = min.getBlockX();
|
||||
private int nextY = min.getBlockY();
|
||||
private int nextZ = min.getBlockZ();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (nextX != Integer.MIN_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector next() {
|
||||
if (!hasNext()) throw new java.util.NoSuchElementException();
|
||||
v.x = nextX;
|
||||
v.y = nextY;
|
||||
v.z = nextZ;
|
||||
if (++nextX > maxX) {
|
||||
nextX = minX;
|
||||
if (++nextY > maxY) {
|
||||
nextY = minY;
|
||||
if (++nextZ > maxZ) {
|
||||
nextX = Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Vector2D> asFlatRegion() {
|
||||
return new Iterable<Vector2D>() {
|
||||
@Override
|
||||
public Iterator<Vector2D> iterator() {
|
||||
return new Iterator<Vector2D>() {
|
||||
private Vector min = getMinimumPoint();
|
||||
private Vector max = getMaximumPoint();
|
||||
private int nextX = min.getBlockX();
|
||||
private int nextZ = min.getBlockZ();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (nextX != Integer.MIN_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2D next() {
|
||||
if (!hasNext()) throw new java.util.NoSuchElementException();
|
||||
Vector2D answer = new Vector2D(nextX, nextZ);
|
||||
if (++nextX > max.getBlockX()) {
|
||||
nextX = min.getBlockX();
|
||||
if (++nextZ > max.getBlockZ()) {
|
||||
nextX = Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getMinimumPoint() + " - " + getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CuboidRegion clone() {
|
||||
return (CuboidRegion) super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a cuboid region out of the given region using the minimum and maximum
|
||||
* bounds of the provided region.
|
||||
*
|
||||
* @param region the region
|
||||
* @return a new cuboid region
|
||||
*/
|
||||
public static CuboidRegion makeCuboid(Region region) {
|
||||
checkNotNull(region);
|
||||
return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a cuboid from the center.
|
||||
*
|
||||
* @param origin the origin
|
||||
* @param apothem the apothem, where 0 is the minimum value to make a 1x1 cuboid
|
||||
* @return a cuboid region
|
||||
*/
|
||||
public static CuboidRegion fromCenter(Vector origin, int apothem) {
|
||||
checkNotNull(origin);
|
||||
checkArgument(apothem >= 0, "apothem => 0 required");
|
||||
Vector size = new Vector(1, 1, 1).multiply(apothem);
|
||||
return new CuboidRegion(origin.subtract(size), origin.add(size));
|
||||
}
|
||||
|
||||
public static Class<?> inject() {
|
||||
return CuboidRegion.class;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
org.gradle.daemon=false
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.parallel=true
|
Loading…
Reference in New Issue
Block a user