diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index c82c6455..ca0d51cd 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -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; diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java index a2f01864..24300e38 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java @@ -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 fc) { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java index 5ca2211e..ee4eee4f 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java @@ -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; diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 3c45b953..28c6ea95 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -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) { diff --git a/core/src/main/java/com/boydti/fawe/FaweAPI.java b/core/src/main/java/com/boydti/fawe/FaweAPI.java index 9bb325dc..591ddb56 100644 --- a/core/src/main/java/com/boydti/fawe/FaweAPI.java +++ b/core/src/main/java/com/boydti/fawe/FaweAPI.java @@ -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.
@@ -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.
-// * - The FaweChunk object can be reused if you want identical changes across chunks
-// * - This is additive modification.
-// * - First use {@link FaweChunk#fill(int, byte)} (e.g. with air) for absolute modification
-// * 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; } diff --git a/core/src/main/java/com/boydti/fawe/object/FaweLocation.java b/core/src/main/java/com/boydti/fawe/object/FaweLocation.java index 1d8e67e8..f2774229 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweLocation.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweLocation.java @@ -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); - } } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java index 91533276..d26a07f4 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java @@ -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 diff --git a/core/src/main/java/com/boydti/fawe/util/FaweQueue.java b/core/src/main/java/com/boydti/fawe/util/FaweQueue.java index 831c98c7..42affefa 100644 --- a/core/src/main/java/com/boydti/fawe/util/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/FaweQueue.java @@ -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); + } } diff --git a/core/src/main/java/com/boydti/fawe/util/SetQueue.java b/core/src/main/java/com/boydti/fawe/util/SetQueue.java index e1b4cb48..392caf37 100644 --- a/core/src/main/java/com/boydti/fawe/util/SetQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/SetQueue.java @@ -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 queues; + public final ArrayDeque 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 getQueues() { - List list = new ArrayList<>(queues.size()); - try { - for (Map.Entry 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 getQueues() { + return new ArrayList<>(queues); + } + + public FaweQueue getNewQueue(String world) { + return Fawe.imp().getNewQueue(world); } public FaweChunk next() { - for (Map.Entry 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
- * @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); - } } diff --git a/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java b/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java new file mode 100644 index 00000000..50e06d01 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java @@ -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 getFacet(Class 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); + } +} diff --git a/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java b/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java new file mode 100644 index 00000000..71019531 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java @@ -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 chunks) { + parent.fixAfterFastMode(chunks); + } + + @Override + public void fixLighting(Iterable 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 chunks = region.getChunks(); + TaskManager.IMP.objectTask(chunks, new RunnableVal() { + @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 getEntities(Region region) { + return parent.getEntities(region); + } + + @Override + public List 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); + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index e7a2b1a5..cbdab74b 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -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; } diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index d3f190c7..3904f908 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -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; diff --git a/core/src/main/java/com/sk89q/worldedit/Vector.java b/core/src/main/java/com/sk89q/worldedit/Vector.java new file mode 100644 index 00000000..7a679226 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/Vector.java @@ -0,0 +1,853 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 { + + 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. + * + *

One can also refer to a static {@link #ZERO}.

+ */ + 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. + * + *

Components < 0.5 are rounded down, otherwise up.

+ * + * @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; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index cd54321e..4327fa4d 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -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(); diff --git a/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index ce9b146c..aeca510b 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java +++ b/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -58,7 +58,6 @@ public class RegionVisitor implements Operation { affected++; } } - return null; } diff --git a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java new file mode 100644 index 00000000..125b0b98 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -0,0 +1,470 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * 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 . + */ + +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 getChunks() { + Set chunks = new HashSet(); + + 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 getChunkCubes() { + Set chunks = new HashSet(); + + 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 iterator() { + final BlockVector v = new BlockVector(0,0,0); + return new Iterator() { + 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 asFlatRegion() { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + 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; + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5a95e1a0..0ff1aa36 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 \ No newline at end of file