diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_12/BukkitQueue_1_12.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_12/BukkitQueue_1_12.java index 79f1ec42..095ec676 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_12/BukkitQueue_1_12.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_12/BukkitQueue_1_12.java @@ -378,6 +378,7 @@ public class BukkitQueue_1_12 extends BukkitQueue_0 { } } } + if (!other.tiles.isEmpty()) { + for (Map.Entry entry : other.tiles.entrySet()) { + int key = entry.getKey(); + int x = MathMan.untripleBlockCoordX(key); + int y = MathMan.untripleBlockCoordY(key); + int z = MathMan.untripleBlockCoordZ(key); + if (x < minX || x > maxX) continue; + if (z < minZ || z > maxZ) continue; + if (y < minY || y > maxY) continue; + x += offsetX; + y += offsetY; + z += offsetZ; + short pair = MathMan.tripleBlockCoord(x, y, z); + CompoundTag tag = entry.getValue(); + Map map = ReflectionUtils.getMap(tag.getValue()); + map.put("x", new IntTag(x + (getX() << 4))); + map.put("y", new IntTag(y)); + map.put("z", new IntTag(z + (getZ() << 4))); + tiles.put(pair, tag); + } + } } public void copyFrom(MCAChunk other, int minY, int maxY, int offsetY) { @@ -746,6 +770,57 @@ public class MCAChunk extends FaweChunk { entities.remove(uuid); } + private final boolean idsEqual(byte[] a, byte[] b) { + // Assumes both are null, or none are (idsEqual - 2d array) + // Assumes length is 4096 + if (a == b) return true; + for (char i = 0; i < 4096; i++) { + if (a[i] != b[i]) return false; + } + return true; + } + + private final boolean idsEqual(byte[][] a, byte[][] b, boolean matchNullToAir) { + // Assumes length is 16 + for (byte i = 0; i < 16; i++) { + if ((a[i] == null) != (b[i] == null)) { + if (matchNullToAir) { + if (b[i] != null) { + for (byte c : b[i]) { + if (c != 0) return false; + } + } else if (a[i] != null) { + for (byte c : a[i]) { + if (c != 0) return false; + } + } + } + return false; + } + } + // Check the chunks close to the ground first + for (byte i = 4; i < 8; i++) { + if (!idsEqual(a[i], b[i])) return false; + } + for (byte i = 3; i >= 0; i--) { + if (!idsEqual(a[i], b[i])) return false; + } + for (byte i = 8; i < 16; i++) { + if (!idsEqual(a[i], b[i])) return false; + } + return true; + } + + /** + * Check if the ids match the ids in the other chunk + * @param other + * @param matchNullToAir + * @return + */ + public boolean idsEqual(MCAChunk other, boolean matchNullToAir) { + return idsEqual(other.ids, this.ids, matchNullToAir); + } + @Override public Void getChunk() { throw new UnsupportedOperationException("Not applicable for this"); diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java index ffba0bcc..74613816 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java @@ -5,6 +5,7 @@ import com.boydti.fawe.jnbt.NBTStreamer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.RunnableVal4; +import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.io.BufferedRandomAccessFile; import com.boydti.fawe.object.io.FastByteArrayInputStream; @@ -97,6 +98,14 @@ public class MCAFile { locations = null; } + @Override + protected void finalize() throws Throwable { + IterableThreadLocal.clean(byteStore1); + IterableThreadLocal.clean(byteStore2); + IterableThreadLocal.clean(byteStore3); + super.finalize(); + } + public void setDeleted(boolean deleted) { this.deleted = deleted; } @@ -573,5 +582,8 @@ public class MCAFile { } } } + IterableThreadLocal.clean(byteStore1); + IterableThreadLocal.clean(byteStore2); + IterableThreadLocal.clean(byteStore3); } } diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java index 4536d523..8654ba48 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java @@ -10,6 +10,7 @@ import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.RunnableVal4; +import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MainUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.Vector; @@ -38,6 +39,12 @@ public class MCAQueue extends NMSMappedFaweQueue> 4; + int otherBCZ = (obz) >> 4; + int otherTCX = (otx) >> 4; + int otherTCZ = (otz) >> 4; + int cx = newChunk.getX(); + int cz = newChunk.getZ(); + int cbx = (cx << 4) - oX; + int cbz = (cz << 4) - oZ; + + boolean changed = false; + for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) { + for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) { + FaweChunk chunk; + synchronized (this) { + chunk = this.getFaweChunk(otherCX, otherCZ); + } + if (!(chunk instanceof NullFaweChunk)) { + changed = true; + MCAChunk other = (MCAChunk) chunk; + int ocbx = otherCX << 4; + int ocbz = otherCZ << 4; + int octx = ocbx + 15; + int octz = ocbz + 15; + int offsetY = 0; + int minX = obx > ocbx ? (obx - ocbx) & 15 : 0; + int maxX = otx < octx ? (otx - ocbx) : 15; + int minZ = obz > ocbz ? (obz - ocbz) & 15 : 0; + int maxZ = otz < octz ? (otz - ocbz) : 15; + int offsetX = ocbx - cbx; + int offsetZ = ocbz - cbz; + newChunk.copyFrom(other, minX, maxX, 0, 255, minZ, maxZ, offsetX, offsetY, offsetZ); + } + } + } + return changed; + } + public void pasteRegion(MCAQueue from, final RegionWrapper regionFrom, Vector offset) throws IOException { int oX = offset.getBlockX(); int oZ = offset.getBlockZ(); @@ -206,6 +266,7 @@ public class MCAQueue extends NMSMappedFaweQueue> T filterRegion(final T filter, final RegionWrapper region) { diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java index 6d6b8064..02a8f006 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java @@ -1,5 +1,6 @@ package com.boydti.fawe.jnbt.anvil; +import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.io.BufferedRandomAccessFile; import com.boydti.fawe.util.MainUtil; import java.io.File; @@ -103,8 +104,8 @@ public abstract class MCAWriter { byte[] fileBuf = new byte[1 << 16]; int mcaXMin = 0; int mcaZMin = 0; - int mcaXMax = mcaXMin + width >> 9; - int mcaZMax = mcaZMin + length >> 9; + int mcaXMax = mcaXMin + ((width - 1) >> 9); + int mcaZMax = mcaZMin + ((length - 1) >> 9); for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) { for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) { @@ -208,5 +209,9 @@ public abstract class MCAWriter { } } pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); + pool.shutdown(); + IterableThreadLocal.clean(byteStore1); + IterableThreadLocal.clean(byteStore2); + IterableThreadLocal.clean(deflateStore); } } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/SplatterBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/SplatterBrush.java index bd96b4da..93a5f756 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/SplatterBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/SplatterBrush.java @@ -12,7 +12,6 @@ import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import java.util.Arrays; @@ -33,7 +32,7 @@ public class SplatterBrush extends ScatterBrush { if (solid) { Pattern tmp; try { - tmp = new BlockPattern(p.apply(position)); + tmp = p.apply(position); } catch (BiomePattern.BiomePatternException ignore) { tmp = ignore.getPattern(); } diff --git a/core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java b/core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java index b4331df4..ae2b52bb 100644 --- a/core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java +++ b/core/src/main/java/com/boydti/fawe/object/collection/IterableThreadLocal.java @@ -1,5 +1,9 @@ package com.boydti.fawe.object.collection; +import java.lang.ref.Reference; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -30,7 +34,86 @@ public abstract class IterableThreadLocal extends ThreadLocal implements I return null; } + public void clean() { + IterableThreadLocal.clean(this); + } + + public static void clean(ThreadLocal instance) { + try { + ThreadGroup rootGroup = Thread.currentThread( ).getThreadGroup( ); + ThreadGroup parentGroup; + while ( ( parentGroup = rootGroup.getParent() ) != null ) { + rootGroup = parentGroup; + } + Thread[] threads = new Thread[ rootGroup.activeCount() ]; + if (threads.length != 0) { + while (rootGroup.enumerate(threads, true) == threads.length) { + threads = new Thread[threads.length * 2]; + } + } + Field tl = Thread.class.getDeclaredField("threadLocals"); + tl.setAccessible(true); + Method methodRemove = null; + for (Thread thread : threads) { + if (thread != null) { + Object tlm = tl.get(thread); + if (tlm != null) { + if (methodRemove == null) { + methodRemove = tlm.getClass().getDeclaredMethod("remove", ThreadLocal.class); + methodRemove.setAccessible(true); + } + methodRemove.invoke(tlm, instance); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void cleanAll() { + try { + // Get a reference to the thread locals table of the current thread + Thread thread = Thread.currentThread(); + Field threadLocalsField = Thread.class.getDeclaredField("threadLocals"); + threadLocalsField.setAccessible(true); + Object threadLocalTable = threadLocalsField.get(thread); + + // Get a reference to the array holding the thread local variables inside the + // ThreadLocalMap of the current thread + Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap"); + Field tableField = threadLocalMapClass.getDeclaredField("table"); + tableField.setAccessible(true); + Object table = tableField.get(threadLocalTable); + + // The key to the ThreadLocalMap is a WeakReference object. The referent field of this object + // is a reference to the actual ThreadLocal variable + Field referentField = Reference.class.getDeclaredField("referent"); + referentField.setAccessible(true); + + for (int i = 0; i < Array.getLength(table); i++) { + // Each entry in the table array of ThreadLocalMap is an Entry object + // representing the thread local reference and its value + Object entry = Array.get(table, i); + if (entry != null) { + // Get a reference to the thread local object and remove it from the table + ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry); + clean(threadLocal); + } + } + } catch(Exception e) { + // We will tolerate an exception here and just log it + throw new IllegalStateException(e); + } + } + public final Collection getAll() { return Collections.unmodifiableCollection(allValues); } + + @Override + protected void finalize() throws Throwable { + clean(this); + super.finalize(); + } } diff --git a/core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java b/core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java index 1d9f1f25..17b8df15 100644 --- a/core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java +++ b/core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java @@ -47,7 +47,7 @@ import java.io.Serializable; * @version 1.0, 2009-03-17 * @since 1.6 */ -public class SparseBitSet implements Cloneable, Serializable { +public final class SparseBitSet implements Cloneable, Serializable { /* My apologies for listing all the additional authors, but concepts, code, and even comments have been re-used in this class definition from code in the JDK that was written and/or maintained by these people. I owe a debt, @@ -541,14 +541,6 @@ public class SparseBitSet implements Cloneable, Serializable { return cache.cardinality; } - /** - * Sets the bit at the specified index to false. - * - * @param i a bit index. - * @throws IndexOutOfBoundsException if the specified index is negative - * or equal to Integer.MAX_VALUE. - * @since 1.6 - */ public void clear(int i) { /* In the interests of speed, no check is made here on whether the level3 block goes to all zero. This may be found and corrected @@ -559,13 +551,14 @@ public class SparseBitSet implements Cloneable, Serializable { return; final int w = i >> SHIFT3; long[][] a2; - if ((a2 = bits[w >> SHIFT1]) == null) + int ws1 = w >> SHIFT1; + if (bits.length <= ws1 || (a2 = bits[ws1]) == null) return; long[] a3; if ((a3 = a2[(w >> SHIFT2) & MASK2]) == null) return; a3[w & MASK3] &= ~(1L << i); // Clear the indicated bit - cache.hash = 0; // Invalidate size, etc., + cache.hash = 0; // Invalidate size, etc., } /** @@ -1798,6 +1791,7 @@ public class SparseBitSet implements Cloneable, Serializable { long[][] a2; long[] a3; long word; + int last = 0; for (int w1 = 0; w1 != aLength1; ++w1) if ((a2 = a1[w1]) != null) for (int w2 = 0; w2 != LENGTH2; ++w2) @@ -1805,7 +1799,7 @@ public class SparseBitSet implements Cloneable, Serializable { final int base = (w1 << SHIFT1) + (w2 << SHIFT2); for (int w3 = 0; w3 != LENGTH3; ++w3) if ((word = a3[w3]) != 0) { - s.writeInt(base + w3); + s.writeInt(-last + (last = (base + w3))); s.writeLong(word); --count; } @@ -1844,8 +1838,9 @@ public class SparseBitSet implements Cloneable, Serializable { /* Read the keys and values, them into the set array, areas, and blocks. */ long[][] a2; long[] a3; + int w = 0; for (int n = 0; n != count; ++n) { - final int w = s.readInt(); + w += s.readInt(); final int w3 = w & MASK3; final int w2 = (w >> SHIFT2) & MASK2; final int w1 = w >> SHIFT1; diff --git a/core/src/main/java/com/boydti/fawe/object/collection/SparseBlockSet.java b/core/src/main/java/com/boydti/fawe/object/collection/SparseBlockSet.java new file mode 100644 index 00000000..2877e825 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/collection/SparseBlockSet.java @@ -0,0 +1,36 @@ +package com.boydti.fawe.object.collection; + +import java.io.Serializable; + +public class SparseBlockSet implements Serializable { + private SparseBitSet[] sets; + + public SparseBlockSet(int depth) { + sets = new SparseBitSet[depth]; + for (int i = 0; i < sets.length; i++) { + sets[i] = new SparseBitSet(); + } + } + + public void setBlock(int index, int id) { + for (int i = 0; i < sets.length; i++) { + SparseBitSet set = sets[i]; + if (((id >> i) & 1) == 1) { + set.set(index); + } else { + set.clear(index); + } + } + } + + public int getBlock(int index) { + int id = 0; + for (int i = 0; i < sets.length; i++) { + SparseBitSet set = sets[i]; + if (set.get(index)) { + id += 1 << i; + } + } + return id; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/regions/general/plot/CreateFromImage.java b/core/src/main/java/com/boydti/fawe/regions/general/plot/CreateFromImage.java index 2ec6f41d..8f582838 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/plot/CreateFromImage.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/plot/CreateFromImage.java @@ -60,7 +60,7 @@ import javax.imageio.ImageIO; aliases = {"createfromheightmap", "createfromimage", "cfhm"}, category = CommandCategory.APPEARANCE, requiredType = RequiredType.NONE, - description = "Generate a world from an image heightmap: [More info](https://www.youtube.com/watch?v=cJZk1GTig7A)", + description = "Generate a world from an image heightmap: [More info](https://goo.gl/friFbV)", usage = "/plots cfi [url or dimensions]" ) public class CreateFromImage extends Command { diff --git a/core/src/main/java/com/boydti/fawe/regions/general/plot/MoveTo512.java b/core/src/main/java/com/boydti/fawe/regions/general/plot/MoveTo512.java index a2370623..09c49f71 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/plot/MoveTo512.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/plot/MoveTo512.java @@ -1,5 +1,6 @@ package com.boydti.fawe.regions.general.plot; +import com.boydti.fawe.Fawe; import com.boydti.fawe.example.NullFaweChunk; import com.boydti.fawe.jnbt.anvil.MCAChunk; import com.boydti.fawe.jnbt.anvil.MCAQueue; @@ -13,6 +14,8 @@ import com.intellectualcrafters.plot.commands.CommandCategory; import com.intellectualcrafters.plot.commands.MainCommand; import com.intellectualcrafters.plot.commands.RequiredType; import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.database.DBFunc; +import com.intellectualcrafters.plot.database.SQLManager; import com.intellectualcrafters.plot.generator.HybridPlotWorld; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.Plot; @@ -27,6 +30,11 @@ import com.plotsquared.general.commands.Command; import com.plotsquared.general.commands.CommandDeclaration; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import org.bukkit.Bukkit; +import org.bukkit.World; @CommandDeclaration( command = "moveto512", @@ -41,8 +49,107 @@ public class MoveTo512 extends Command { super(MainCommand.getInstance(), true); } - public static void main(String[] args) { + private MCAChunk emptyPlot(MCAChunk chunk, HybridPlotWorld hpw) { + int maxLayer = (hpw.PLOT_HEIGHT) >> 4; + for (int i = maxLayer + 1; i < chunk.ids.length; i++) { + chunk.ids[i] = null; + chunk.data[i] = null; + } + for (int layer = 0; layer <= maxLayer; layer++) { + byte[] ids = chunk.ids[layer]; + if (ids == null) { + ids = chunk.ids[layer] = new byte[4096]; + chunk.data[layer] = new byte[2048]; + chunk.skyLight[layer] = new byte[2048]; + chunk.blockLight[layer] = new byte[2048]; + } else { + Arrays.fill(ids, (byte) 0); + Arrays.fill(chunk.data[layer], (byte) 0); + Arrays.fill(chunk.skyLight[layer], (byte) 0); + Arrays.fill(chunk.blockLight[layer], (byte) 0); + } + if (layer == maxLayer) { + int yMax = hpw.PLOT_HEIGHT & 15; + for (int y = yMax + 1; y < 15; y++) { + Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255); + } + if (layer == 0) { + Arrays.fill(ids, 0, 256, (byte) 7); + for (int y = 1; y < yMax; y++) { + int y8 = y << 8; + Arrays.fill(ids, y8, y8 + 256, (byte) 3); + } + } else { + for (int y = 0; y < yMax; y++) { + int y8 = y << 8; + Arrays.fill(ids, y8, y8 + 256, (byte) 3); + } + } + int yMax15 = yMax & 15; + int yMax158 = yMax15 << 8; + Arrays.fill(ids, yMax158, yMax158 + 256, (byte) 2); + if (yMax != 15) { + Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0); + } + } else if (layer == 0){ + Arrays.fill(ids, 256, 4096, (byte) 3); + Arrays.fill(ids, 0, 256, (byte) 7); + } else { + Arrays.fill(ids, (byte) 3); + } + } + return chunk; + } + private MCAChunk emptyRoad(MCAChunk chunk, HybridPlotWorld hpw) { + int maxLayer = (hpw.ROAD_HEIGHT) >> 4; + for (int i = maxLayer + 1; i < chunk.ids.length; i++) { + chunk.ids[i] = null; + chunk.data[i] = null; + } + for (int layer = 0; layer <= maxLayer; layer++) { + byte[] ids = chunk.ids[layer]; + if (ids == null) { + ids = chunk.ids[layer] = new byte[4096]; + chunk.data[layer] = new byte[2048]; + chunk.skyLight[layer] = new byte[2048]; + chunk.blockLight[layer] = new byte[2048]; + } else { + Arrays.fill(ids, (byte) 0); + Arrays.fill(chunk.data[layer], (byte) 0); + Arrays.fill(chunk.skyLight[layer], (byte) 0); + Arrays.fill(chunk.blockLight[layer], (byte) 0); + } + if (layer == maxLayer) { + int yMax = hpw.ROAD_HEIGHT & 15; + for (int y = yMax + 1; y < 15; y++) { + Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255); + } + if (layer == 0) { + Arrays.fill(ids, 0, 256, (byte) 7); + for (int y = 1; y <= yMax; y++) { + int y8 = y << 8; + Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id); + } + } else { + for (int y = 0; y <= yMax; y++) { + int y8 = y << 8; + Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id); + } + } + if (yMax != 15) { + int yMax15 = yMax & 15; + int yMax158 = yMax15 << 8; + Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0); + } + } else if (layer == 0){ + Arrays.fill(ids, 256, 4096, (byte) hpw.ROAD_BLOCK.id); + Arrays.fill(ids, 0, 256, (byte) 7); + } else { + Arrays.fill(ids, (byte) hpw.ROAD_BLOCK.id); + } + } + return chunk; } @Override @@ -52,46 +159,92 @@ public class MoveTo512 extends Command { check(area, C.COMMAND_SYNTAX, getUsage()); checkTrue(area instanceof HybridPlotWorld, C.NOT_VALID_HYBRID_PLOT_WORLD); + for (World world : Bukkit.getWorlds()) { + world.save(); + } + FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(area.worldname, true, false); MCAQueue queueFrom = new MCAQueue(area.worldname, defaultQueue.getSaveFolder(), defaultQueue.hasSky()); String world = args[0]; - File folder = new File(PS.imp().getWorldContainer(), world); + File folder = new File(PS.imp().getWorldContainer(), world + File.separator + "region"); checkTrue(!folder.exists(), C.SETUP_WORLD_TAKEN, world); HybridPlotWorld hpw = (HybridPlotWorld) area; - int minRoad = 5; - int pLen = Math.max(hpw.PLOT_WIDTH, 512 - minRoad); - int roadWidth = pLen - 512; + int minRoad = 7; + int pLen = Math.min(hpw.PLOT_WIDTH, 512 - minRoad); + int roadWidth = 512 - pLen; int roadPosLower; if ((roadWidth & 1) == 0) { roadPosLower = (short) (Math.floor(roadWidth / 2) - 1); } else { roadPosLower = (short) Math.floor(roadWidth / 2); } - int roadPosUpper = 512 - roadWidth + roadPosLower; + int roadPosUpper = 512 - roadWidth + roadPosLower + 1; + + final ThreadLocal roadCache = new ThreadLocal() { + @Override + protected boolean[] initialValue() { + return new boolean[64]; + } + }; + + MCAChunk reference = new MCAChunk(null, 0, 0); + { + reference.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0); + reference.fillCuboid(0, 15, 1, hpw.PLOT_HEIGHT - 1, 0, 15, 3, (byte) 0); + reference.fillCuboid(0, 15, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, 0, 15, 2, (byte) 0); + } + + Map rawPlots = area.getPlotsRaw(); + ArrayList plots = new ArrayList(rawPlots.values()); + int size = plots.size(); PlotId nextId = new PlotId(0, 0); - for (Plot plot : area.getPlots()) { + + long start = System.currentTimeMillis(); + + int percent = 0; + for (Plot plot : plots) { + Fawe.debug(((percent += 100) / size) + "% complete!"); + Location bot = plot.getBottomAbs(); Location top = plot.getTopAbs(); - int oX = roadPosLower - bot.getX(); - int oZ = roadPosLower - bot.getZ(); + int oX = roadPosLower - bot.getX() + 1; + int oZ = roadPosLower - bot.getZ() + 1; + + { // Move + PlotId id = plot.getId(); + Fawe.debug("Moving " + plot.getId() + " to " + nextId); + id.x = nextId.x; + id.y = nextId.y; + id.recalculateHash(); + } MCAWriter writer = new MCAWriter(512, 512, folder) { @Override public boolean shouldWrite(int chunkX, int chunkZ) { - return true; + int bx = chunkX << 4; + int bz = chunkZ << 4; + int tx = bx + 15; + int tz = bz + 15; + return !(tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper); } @Override public MCAChunk write(MCAChunk newChunk, int bx, int tx, int bz, int tz) { + Arrays.fill(newChunk.biomes, (byte) 4); + if (!newChunk.tiles.isEmpty()) newChunk.tiles.clear(); if (tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper) { - newChunk.fillCuboid(0, 15, 0, hpw.ROAD_HEIGHT, 0, 15, hpw.ROAD_BLOCK.id, hpw.ROAD_BLOCK.data); - newChunk.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0); + return emptyRoad(newChunk, hpw); } else { + boolean partRoad = (bx <= roadPosLower || bz <= roadPosLower || tx >= roadPosUpper || tz >= roadPosUpper); + + boolean changed = false; + emptyPlot(newChunk, hpw); + int obx = bx - oX; int obz = bz - oZ; int otx = tx - oX; @@ -102,13 +255,17 @@ public class MoveTo512 extends Command { int otherTCZ = (otz) >> 4; int cx = newChunk.getX(); int cz = newChunk.getZ(); - int cbx = (cx << 4) - oX; int cbz = (cz << 4) - oZ; + for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) { for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) { - FaweChunk chunk = queueFrom.getFaweChunk(otherCX, otherCZ); + FaweChunk chunk; + synchronized (queueFrom) { + chunk = queueFrom.getFaweChunk(otherCX, otherCZ); + } if (!(chunk instanceof NullFaweChunk)) { + changed = true; MCAChunk other = (MCAChunk) chunk; int ocbx = otherCX << 4; int ocbz = otherCZ << 4; @@ -125,43 +282,50 @@ public class MoveTo512 extends Command { } } } - if (bx < roadPosLower || bz < roadPosLower || tx > roadPosUpper || tz > roadPosUpper) { - boolean[] gx = new boolean[16]; - boolean[] wx = new boolean[16]; - boolean[] gz = new boolean[16]; - boolean[] wz = new boolean[16]; + if (!changed || reference.idsEqual(newChunk, false)) { + return null; + } + if (partRoad) { + boolean[] rwp = roadCache.get(); for (short i = 0; i < 16; i++) { int vx = bx + i; int vz = bz + i; - gz[i] = vz < roadPosLower || vz > roadPosUpper; - wz[i] = vz == roadPosLower || vz == roadPosUpper; - gx[i] = vx < roadPosLower || vx > roadPosUpper; - wx[i] = vx == roadPosLower || vx == roadPosUpper; + rwp[i] = vx < roadPosLower || vx > roadPosUpper; + rwp[i + 32] = vx == roadPosLower || vx == roadPosUpper; + rwp[i + 16] = vz < roadPosLower || vz > roadPosUpper; + rwp[i + 48] = vz == roadPosLower || vz == roadPosUpper; } for (int z = 0; z < 16; z++) { + final boolean rwpz16 = rwp[z + 16]; + final boolean rwpz48 = rwp[z + 48]; for (int x = 0; x < 16; x++) { - if (gx[x] || gz[z]) { - for (int y = 1; y < hpw.ROAD_HEIGHT; y++) { + if (rwpz16 || rwp[x]) { + for (int y = 1; y <= hpw.ROAD_HEIGHT; y++) { newChunk.setBlock(x, y, z, hpw.ROAD_BLOCK.id, hpw.ROAD_BLOCK.data); } - } else if (wx[x] || wz[z]) { - for (int y = 1; y < hpw.WALL_HEIGHT; y++) { + for (int y = hpw.ROAD_HEIGHT + 1; y < 256; y++) { + newChunk.setBlock(x, y, z, 0, 0); + } + } else if (rwpz48 || rwp[x + 32]) { + for (int y = 1; y <= hpw.WALL_HEIGHT; y++) { newChunk.setBlock(x, y, z, hpw.WALL_FILLING.id, hpw.WALL_FILLING.data); } - newChunk.setBlock(x, hpw.WALL_HEIGHT, z, hpw.CLAIMED_WALL_BLOCK.id, hpw.CLAIMED_WALL_BLOCK.data); + for (int y = hpw.WALL_HEIGHT + 2; y < 256; y++) { + newChunk.setBlock(x, y, z, 0, 0); + } + newChunk.setBlock(x, hpw.WALL_HEIGHT + 1, z, hpw.CLAIMED_WALL_BLOCK.id, hpw.CLAIMED_WALL_BLOCK.data); } } } - newChunk.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0); } } - return newChunk; } }; - writer.setMCAOffset(nextId.x, nextId.y); + writer.setMCAOffset(nextId.x - 1, nextId.y - 1); try { writer.generate(); + System.gc(); } catch (IOException e) { e.printStackTrace(); return; @@ -169,7 +333,28 @@ public class MoveTo512 extends Command { queueFrom.clear(); nextId = nextId.getNextId(1); } + Fawe.debug("Anvil copy completed in " + ((System.currentTimeMillis() - start) / 1000d) + "s"); + Fawe.debug("Updating database, please wait..."); + rawPlots.clear(); + for (Plot plot : plots) { + rawPlots.put(plot.getId(), plot); + DBFunc.movePlot(plot, plot); + } + SQLManager db = (SQLManager) DBFunc.dbManager; + db.addNotifyTask(new Runnable() { + @Override + public void run() { + Fawe.debug("Instructions"); + Fawe.debug(" - Stop the server"); + Fawe.debug(" - Rename the folder for the new world to the current world"); + Fawe.debug(" - Change the plot size to " + pLen); + Fawe.debug(" - Change the road size to " + roadWidth); + Fawe.debug(" - Start the server"); + } + }); + ConfigurationSection section = PS.get().worlds.getConfigurationSection("worlds." + world); + if (section == null) section = PS.get().worlds.createSection("worlds." + world); area.saveConfiguration(section); section.set("plot.size", pLen); section.set("road.width", roadWidth); diff --git a/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotSquaredFeature.java b/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotSquaredFeature.java index 261199ce..6c177e3c 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotSquaredFeature.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotSquaredFeature.java @@ -36,10 +36,10 @@ public class PlotSquaredFeature extends FaweMaskManager { new PlotSetBiome(); } try { + new MoveTo512(); if (Settings.Enabled_Components.WORLDS) { new CreateFromImage(); new ReplaceAll(); - new MoveTo512(); } } catch (Throwable e) { Fawe.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands"); 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 c8977519..cd1eeca6 100644 --- a/core/src/main/java/com/boydti/fawe/util/SetQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/SetQueue.java @@ -34,7 +34,7 @@ public class SetQueue { * Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the server */ private long last; - private long secondLast; + private long allocate = 50; private long lastSuccess; /** @@ -78,6 +78,7 @@ public class SetQueue { @Override public void run() { try { + long now = System.currentTimeMillis(); targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0); do { Runnable task = tasks.poll(); @@ -88,13 +89,15 @@ public class SetQueue { } } while (Fawe.get().getTimer().isAbove(targetTPS)); if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) { - lastSuccess = System.currentTimeMillis(); + last = lastSuccess = now; runEmptyTasks(); return; } if (!MemUtil.isMemoryFree()) { final int mem = MemUtil.calculateMemory(); if (mem != Integer.MAX_VALUE) { + last = now; + allocate = Math.max(5, allocate - 1); if ((mem <= 1) && Settings.IMP.PREVENT_CRASHES) { for (FaweQueue queue : getAllQueues()) { queue.saveMemory(); @@ -110,13 +113,26 @@ public class SetQueue { } } FaweQueue queue = getNextQueue(); - if (queue == null || !Fawe.get().getTimer().isAbove(targetTPS)) { + if (queue == null) { + last = now; + return; + } + if (!Fawe.get().getTimer().isAbove(targetTPS)) { + allocate = Math.max(5, allocate - 1); + last = now; return; } if (Thread.currentThread() != Fawe.get().getMainThread()) { throw new IllegalStateException("This shouldn't be possible for placement to occur off the main thread"); } - long time = Settings.IMP.QUEUE.EXTRA_TIME_MS + 50 + Math.min((50 + SetQueue.this.last) - (SetQueue.this.last = System.currentTimeMillis()), SetQueue.this.secondLast - System.currentTimeMillis()); + long diff = (50 + SetQueue.this.last) - (SetQueue.this.last = now); + long absDiff = Math.abs(diff); + if (diff == 0) { + allocate = Math.min(50, allocate + 1); + } else if (diff < 0) { + allocate = Math.max(5, allocate + diff); + } + long time = Settings.IMP.QUEUE.EXTRA_TIME_MS + allocate - absDiff - System.currentTimeMillis() + now; // Disable the async catcher as it can't discern async vs parallel boolean parallel = Settings.IMP.QUEUE.PARALLEL_THREADS > 1; queue.startSet(parallel); @@ -142,7 +158,6 @@ public class SetQueue { // completer = new ExecutorCompletionService(pool); // } } - secondLast = System.currentTimeMillis(); queue.endSet(parallel); } catch (Throwable e) { e.printStackTrace(); diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 48871c76..6ea2d0ef 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1444,7 +1444,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting */ @SuppressWarnings("deprecation") public int fillXZ(final Vector origin, final BaseBlock block, final double radius, final int depth, final boolean recursive) throws MaxChangedBlocksException { - return this.fillXZ(origin, new BlockPattern(block), radius, depth, recursive); + return this.fillXZ(origin, (Pattern) block, radius, depth, recursive); } /** @@ -1562,7 +1562,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting final Region region = new CuboidRegion(this.getWorld(), // Causes clamping of Y range position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, height - 1, apothem - 1)); - final Pattern pattern = new BlockPattern(new BaseBlock(BlockID.AIR)); + final Pattern pattern = (new BaseBlock(BlockID.AIR)); return this.setBlocks(region, pattern); } @@ -1583,7 +1583,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting final Region region = new CuboidRegion(this.getWorld(), // Causes clamping of Y range position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, -height + 1, apothem - 1)); - final Pattern pattern = new BlockPattern(new BaseBlock(BlockID.AIR)); + final Pattern pattern = (new BaseBlock(BlockID.AIR)); return this.setBlocks(region, pattern); } @@ -1605,7 +1605,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting final Vector adjustment = new Vector(1, 1, 1).multiply(apothem - 1); final Region region = new CuboidRegion(this.getWorld(), // Causes clamping of Y range position.add(adjustment.multiply(-1)), position.add(adjustment)); - final Pattern pattern = new BlockPattern(new BaseBlock(BlockID.AIR)); + final Pattern pattern = (new BaseBlock(BlockID.AIR)); return this.replaceBlocks(region, mask, pattern); } @@ -1657,7 +1657,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } try { if (hasExtraExtents()) { - RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(extent, new BlockPattern(block)), this); + RegionVisitor visitor = new RegionVisitor(region, new BlockReplace(extent, (block)), this); Operations.completeBlindly(visitor); this.changes += visitor.getAffected(); } else { @@ -1689,7 +1689,10 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting checkNotNull(region); checkNotNull(pattern); if (pattern instanceof BlockPattern) { - return setBlocks(region, ((BlockPattern) pattern).getBlock()); + return setBlocks(region, ((BaseBlock) pattern)); + } + if (pattern instanceof BaseBlock) { + return setBlocks(region, (BaseBlock) pattern); } final BlockReplace replace = new BlockReplace(EditSession.this, pattern); final RegionVisitor visitor = new RegionVisitor(region, replace, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null); @@ -1714,7 +1717,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting // return changes = region.getArea(); // } // TODO fast replace - return this.replaceBlocks(region, filter, new BlockPattern(replacement)); + return this.replaceBlocks(region, filter, (replacement)); } @@ -1730,8 +1733,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting */ @SuppressWarnings("deprecation") public int replaceBlocks(final Region region, final Set filter, final Pattern pattern) throws MaxChangedBlocksException { -// if (pattern instanceof BlockPattern) { -// return replaceBlocks(region, filter, ((BlockPattern) pattern).getBlock()); +// if (pattern instanceof BaseBlock) { +// return replaceBlocks(region, filter, ((BaseBlock) pattern)); // } final Mask mask = filter == null ? new ExistingBlockMask(this) : new FuzzyBlockMask(this, filter); return this.replaceBlocks(region, mask, pattern); @@ -1794,7 +1797,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting */ @SuppressWarnings("deprecation") public int makeCuboidFaces(final Region region, final BaseBlock block) throws MaxChangedBlocksException { - return this.makeCuboidFaces(region, new BlockPattern(block)); + return this.makeCuboidFaces(region, (Pattern) (block)); } /** @@ -1848,7 +1851,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting */ @SuppressWarnings("deprecation") public int makeCuboidWalls(final Region region, final BaseBlock block) throws MaxChangedBlocksException { - return this.makeCuboidWalls(region, new BlockPattern(block)); + return this.makeCuboidWalls(region, (Pattern) (block)); } /** @@ -1917,7 +1920,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting @SuppressWarnings("deprecation") public int overlayCuboidBlocks(final Region region, final BaseBlock block) throws MaxChangedBlocksException { checkNotNull(block); - return this.overlayCuboidBlocks(region, new BlockPattern(block)); + return this.overlayCuboidBlocks(region, (Pattern) (block)); } /** @@ -2013,7 +2016,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting final Vector to = region.getMinimumPoint(); final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, EditSession.this, to); - final com.sk89q.worldedit.function.pattern.Pattern pattern = replacement != null ? new BlockPattern(replacement) : new BlockPattern(new BaseBlock(BlockID.AIR)); + final com.sk89q.worldedit.function.pattern.Pattern pattern = replacement != null ? replacement : (new BaseBlock(BlockID.AIR)); final BlockReplace remove = new BlockReplace(EditSession.this, pattern) { private MutableBlockVector mutable = new MutableBlockVector(); @@ -2089,7 +2092,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), liquidMask); - final BlockReplace replace = new BlockReplace(EditSession.this, new BlockPattern(new BaseBlock(BlockID.AIR))); + final BlockReplace replace = new BlockReplace(EditSession.this, new BaseBlock(BlockID.AIR)); final RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this); // Around the origin in a 3x3 block @@ -2148,7 +2151,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), blockMask); - BlockReplace replace = new BlockReplace(this, new BlockPattern(FaweCache.getBlock(stationary, 0))); + BlockReplace replace = new BlockReplace(this, (FaweCache.getBlock(stationary, 0))); NonRisingVisitor visitor = new NonRisingVisitor(mask, replace, (int) (radius * 2 + 1), this); // Around the origin in a 3x3 block diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 8e730ef8..4d6c98cc 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -80,7 +80,6 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.command.InvalidUsageException; @@ -102,7 +101,7 @@ import javafx.scene.paint.Color; * Commands to set brush shape. */ @Command(aliases = {"brush", "br", "/b"}, - desc = "Commands to build and draw from far away. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Brushes)" + desc = "Commands to build and draw from far away. [More Info](https://git.io/vSPYf)" ) public class BrushCommands extends MethodCommands { @@ -287,8 +286,8 @@ public class BrushCommands extends MethodCommands { } else { brush = new SphereBrush(); } - if (fill instanceof BlockPattern) { - BaseBlock block = ((BlockPattern) fill).getBlock(); + if (fill instanceof BaseBlock) { + BaseBlock block = (BaseBlock) fill; switch (block.getId()) { case BlockID.SAND: case BlockID.GRAVEL: @@ -595,7 +594,7 @@ public class BrushCommands extends MethodCommands { public BrushSettings extinguishBrush(Player player, LocalSession session, EditSession editSession, @Optional("5") double radius, CommandContext context) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); - Pattern fill = new BlockPattern(new BaseBlock(0)); + Pattern fill = (new BaseBlock(0)); return get(context) .setBrush(new SphereBrush()) .setSize(radius) diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java index a5155ac5..c8314465 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushOptionsCommands.java @@ -45,7 +45,8 @@ import java.util.zip.GZIPInputStream; /** * Tool commands. */ -@Command(aliases = {}, desc = "Tool commands") + +@Command(aliases = {"brush", "br", "/b"}, desc = "Tool commands") public class BrushOptionsCommands extends MethodCommands { public BrushOptionsCommands(WorldEdit we) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index e41a8a8d..0ad0397e 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -73,7 +73,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; /** * Clipboard commands. */ -@Command(aliases = {}, desc = "Related commands to copy and pasting blocks: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Clipboard)") +@Command(aliases = {}, desc = "Related commands to copy and pasting blocks: [More Info](https://goo.gl/z2ScQR)") public class ClipboardCommands { private final WorldEdit worldEdit; diff --git a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index dd9c259a..c59dd331 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -68,7 +68,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; /** * Commands for the generation of shapes and other objects. */ -@Command(aliases = {}, desc = "Create structures and features: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Generation)") +@Command(aliases = {}, desc = "Create structures and features: [More Info](https://goo.gl/KuLFRW)") public class GenerationCommands { private final WorldEdit worldEdit; @@ -125,8 +125,8 @@ public class GenerationCommands { public void image(Player player, LocalSession session, EditSession editSession, String arg, @Optional("true") boolean randomize, @Optional("100") int threshold) throws WorldEditException, ParameterException, IOException { TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold); URL url = new URL(arg); - if (!url.getHost().equalsIgnoreCase("i.imgur.com")) { - throw new IOException("Only i.imgur.com links are allowed!"); + if (!url.getHost().equalsIgnoreCase("i.imgur.com") && !url.getHost().equalsIgnoreCase("empcraft.com")) { + throw new IOException("Only i.imgur.com or empcraft.com/ui links are allowed!"); } FawePlayer fp = FawePlayer.wrap(player); BufferedImage image = MainUtil.toRGB(ImageIO.read(url)); diff --git a/core/src/main/java/com/sk89q/worldedit/command/MaskCommands.java b/core/src/main/java/com/sk89q/worldedit/command/MaskCommands.java index cc774623..d44656b0 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/MaskCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/MaskCommands.java @@ -46,7 +46,7 @@ import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.biome.BaseBiome; @Command(aliases = {"masks"}, - desc = "Help for the various masks. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit---FAWE-mask-list)" + desc = "Help for the various masks. [More Info](https://git.io/v9r4K)" ) public class MaskCommands extends MethodCommands { public MaskCommands(WorldEdit worldEdit) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java index 5c3229b4..16693e82 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java @@ -43,7 +43,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; /** * Commands for moving the player around. */ -@Command(aliases = {}, desc = "Commands for moving the player around: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Getting_around)") +@Command(aliases = {}, desc = "Commands for moving the player around: [More Info](https://goo.gl/uQTUiT)") public class NavigationCommands { @SuppressWarnings("unused") diff --git a/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java b/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java index 670321b6..41c42f18 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/PatternCommands.java @@ -58,7 +58,7 @@ import java.util.Set; import javafx.scene.paint.Color; @Command(aliases = {"patterns"}, - desc = "Help for the various patterns. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/WorldEdit-and-FAWE-patterns)" + desc = "Help for the various patterns. [More Info](https://git.io/vSPmA)" ) public class PatternCommands extends MethodCommands { public PatternCommands(WorldEdit worldEdit) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index c1c1e622..3e41028d 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -53,7 +53,6 @@ import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.LayerVisitor; import com.sk89q.worldedit.internal.annotation.Direction; @@ -330,11 +329,7 @@ public class RegionCommands extends MethodCommands { public void set(FawePlayer player, LocalSession session, EditSession editSession, @Selection Region selection, Pattern to, CommandContext context) throws WorldEditException { player.checkConfirmation(getArguments(context)); int affected; - if (to instanceof BlockPattern) { - affected = editSession.setBlocks(selection, ((BlockPattern) to).getBlock()); - } else { - affected = editSession.setBlocks(selection, to); - } + affected = editSession.setBlocks(selection, to); if (affected != 0) { BBC.OPERATION.send(player, affected); if (!player.hasPermission("fawe.tips")) diff --git a/core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java index 7c29b832..117199bb 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java @@ -37,7 +37,7 @@ import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; /** * Commands related to scripting. */ -@Command(aliases = {}, desc = "Run craftscripts: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Scripting)") +@Command(aliases = {}, desc = "Run craftscripts: [More Info](https://goo.gl/dHDxLG)") public class ScriptingCommands { private final WorldEdit worldEdit; diff --git a/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java index 39af915e..5c7e6708 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java @@ -32,7 +32,7 @@ import com.sk89q.worldedit.command.tool.RecursivePickaxe; import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.entity.Player; -@Command(aliases = {"superpickaxe", "pickaxe", "sp"}, desc = "Super-pickaxe commands: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Super_pickaxe)") +@Command(aliases = {"superpickaxe", "pickaxe", "sp"}, desc = "Super-pickaxe commands: [More Info](https://goo.gl/aBtGHo)") public class SuperPickaxeCommands { private final WorldEdit we; diff --git a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 8e83d192..52c53680 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -44,7 +44,7 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.command.parametric.Optional; -@Command(aliases = {"brush", "br", "/b", "tool"}, desc = "Bind functions to held items: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Tools)") +@Command(aliases = {"brush", "br", "/b", "tool"}, desc = "Bind functions to held items: [More Info](https://goo.gl/xPnPxj)") public class ToolCommands { private final WorldEdit we; diff --git a/core/src/main/java/com/sk89q/worldedit/command/TransformCommands.java b/core/src/main/java/com/sk89q/worldedit/command/TransformCommands.java index 100b1293..abba660c 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/TransformCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/TransformCommands.java @@ -22,7 +22,7 @@ import com.sk89q.worldedit.util.command.parametric.Optional; import java.util.Set; @Command(aliases = {"transforms"}, - desc = "Help for the various transforms. [More Info](https://github.com/boy0001/FastAsyncWorldedit/wiki/Transforms)" + desc = "Help for the various transforms. [More Info](https://git.io/v9KHO)" ) public class TransformCommands extends MethodCommands { public TransformCommands(WorldEdit worldEdit) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 43c14dc2..c58d46c8 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -51,7 +51,6 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.internal.expression.Expression; @@ -116,8 +115,8 @@ public class UtilityCommands extends MethodCommands { worldEdit.checkMaxRadius(radius); Vector pos = session.getPlacementPosition(player); int affected = 0; - if (pattern instanceof BlockPattern) { - affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, (int) depth, false); + if (pattern instanceof BaseBlock) { + affected = editSession.fillXZ(pos, ((BaseBlock) pattern), radius, (int) depth, false); } else { affected = editSession.fillXZ(pos, pattern, radius, (int) depth, false); } @@ -137,8 +136,8 @@ public class UtilityCommands extends MethodCommands { worldEdit.checkMaxRadius(radius); Vector pos = session.getPlacementPosition(player); int affected = 0; - if (pattern instanceof BlockPattern) { - affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, (int) depth, true); + if (pattern instanceof BaseBlock) { + affected = editSession.fillXZ(pos, ((BaseBlock) pattern), radius, (int) depth, true); } else { affected = editSession.fillXZ(pos, pattern, radius, (int) depth, true); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java b/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java index 438b3c55..78976541 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java +++ b/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java @@ -45,7 +45,6 @@ import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.regions.CuboidRegion; @@ -106,8 +105,8 @@ public class SelectionCommand extends SimpleCommand { Field field = replace.getClass().getDeclaredField("pattern"); field.setAccessible(true); Pattern pattern = (Pattern) field.get(replace); - if (pattern instanceof BlockPattern) { - BaseBlock block = ((BlockPattern) pattern).getBlock(); + if (pattern instanceof BaseBlock) { + BaseBlock block = ((BaseBlock) pattern); final FaweQueue queue = editSession.getQueue(); final int minY = cuboid.getMinimumY(); final int maxY = cuboid.getMaximumY(); diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java b/core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java index 40848255..d3b8ae31 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java @@ -13,7 +13,6 @@ import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.world.World; @@ -53,7 +52,7 @@ public class RecursivePickaxe implements BlockTool { editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop); final int radius = (int) range; - final BlockReplace replace = new BlockReplace(editSession, new BlockPattern(editSession.nullBlock)); + final BlockReplace replace = new BlockReplace(editSession, (editSession.nullBlock)); editSession.setMask((Mask) null); RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius, editSession); visitor.visit(pos); 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 b44ef9f4..77150ea7 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 @@ -238,13 +238,10 @@ public final class CommandManager { .registerMethods(new BrushOptionsCommands(worldEdit)) .registerMethods(new ToolCommands(worldEdit)) .registerMethods(new UtilityCommands(worldEdit)) - .group("worldedit", "we", "fawe") - .describeAs("FAWE commands") - .registerMethods(new WorldEditCommands(worldEdit)).parent().group("schematic", "schem", "/schematic", "/schem") - .describeAs("Schematic commands for saving/loading areas") - .registerMethods(new SchematicCommands(worldEdit)).parent().group("snapshot", "snap") - .describeAs("Schematic commands for saving/loading areas") - .registerMethods(new SnapshotCommands(worldEdit)).parent().group("brush", "br", "/b", "tool").describeAs("Bind brushes and tools to items") + .registerSubMethods(new WorldEditCommands(worldEdit)) + .registerSubMethods(new SchematicCommands(worldEdit)) + .registerSubMethods(new SnapshotCommands(worldEdit)) + .groupAndDescribe(BrushCommands.class) .registerMethods(new ToolCommands(worldEdit)) .registerMethods(new BrushOptionsCommands(worldEdit)) .registerMethods(new BrushCommands(worldEdit), new BrushProcessor(worldEdit)) @@ -254,7 +251,8 @@ public final class CommandManager { .register(adapt(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply") .register(adapt(new ShapedBrushCommand(new PaintCommand(new TreeGeneratorParser("treeType")), "worldedit.brush.forest")), "forest") .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise") - .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower").parent() + .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower") + .parent() .group("superpickaxe", "pickaxe", "sp").describeAs("Super-pickaxe commands") .registerMethods(new SuperPickaxeCommands(worldEdit)) .parent().graph().getDispatcher(); @@ -374,7 +372,7 @@ public final class CommandManager { final Actor finalActor = actor; locals.put("arguments", args); - final long start = System.currentTimeMillis(); + long start = System.currentTimeMillis(); try { // This is a bit of a hack, since the call method can only throw CommandExceptions // everything needs to be wrapped at least once. Which means to handle all WorldEdit diff --git a/core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/core/src/main/java/com/sk89q/worldedit/extent/Extent.java index d4f6f055..71e85689 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -17,7 +17,6 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; @@ -176,17 +175,17 @@ public interface Extent extends InputExtent, OutputExtent { } default public void addOres(Region region, Mask mask) throws WorldEditException { - addOre(region, mask, new BlockPattern(BlockID.DIRT), 33, 10, 100, 0, 255); - addOre(region, mask, new BlockPattern(BlockID.GRAVEL), 33, 8, 100, 0, 255); - addOre(region, mask, new BlockPattern(BlockID.STONE, 1), 33, 10, 100, 0, 79); - addOre(region, mask, new BlockPattern(BlockID.STONE, 3), 33, 10, 100, 0, 79); - addOre(region, mask, new BlockPattern(BlockID.STONE, 5), 33, 10, 100, 0, 79); - addOre(region, mask, new BlockPattern(BlockID.COAL_ORE), 17, 20, 100, 0, 127); - addOre(region, mask, new BlockPattern(BlockID.IRON_ORE), 9, 20, 100, 0, 63); - addOre(region, mask, new BlockPattern(BlockID.GOLD_ORE), 9, 2, 100, 0, 31); - addOre(region, mask, new BlockPattern(BlockID.REDSTONE_ORE), 8, 8, 100, 0, 15); - addOre(region, mask, new BlockPattern(BlockID.DIAMOND_ORE), 8, 1, 100, 0, 15); - addOre(region, mask, new BlockPattern(BlockID.LAPIS_LAZULI_ORE), 7, 1, 100, 0, 15); - addOre(region, mask, new BlockPattern(BlockID.EMERALD_ORE), 5, 1, 100, 4, 31); + addOre(region, mask, FaweCache.getBlock(BlockID.DIRT, 0), 33, 10, 100, 0, 255); + addOre(region, mask, FaweCache.getBlock(BlockID.GRAVEL, 0), 33, 8, 100, 0, 255); + addOre(region, mask, FaweCache.getBlock(BlockID.STONE, 1), 33, 10, 100, 0, 79); + addOre(region, mask, FaweCache.getBlock(BlockID.STONE, 3), 33, 10, 100, 0, 79); + addOre(region, mask, FaweCache.getBlock(BlockID.STONE, 5), 33, 10, 100, 0, 79); + addOre(region, mask, FaweCache.getBlock(BlockID.COAL_ORE, 0), 17, 20, 100, 0, 127); + addOre(region, mask, FaweCache.getBlock(BlockID.IRON_ORE, 0), 9, 20, 100, 0, 63); + addOre(region, mask, FaweCache.getBlock(BlockID.GOLD_ORE, 0), 9, 2, 100, 0, 31); + addOre(region, mask, FaweCache.getBlock(BlockID.REDSTONE_ORE, 0), 8, 8, 100, 0, 15); + addOre(region, mask, FaweCache.getBlock(BlockID.DIAMOND_ORE, 0), 8, 1, 100, 0, 15); + addOre(region, mask, FaweCache.getBlock(BlockID.LAPIS_LAZULI_ORE, 0), 7, 1, 100, 0, 15); + addOre(region, mask, FaweCache.getBlock(BlockID.EMERALD_ORE, 0), 5, 1, 100, 4, 31); } } diff --git a/core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java b/core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java index e7e11fb2..9bcab1e0 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java +++ b/core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java @@ -7,6 +7,10 @@ import com.sk89q.worldedit.blocks.BaseBlock; import static com.google.common.base.Preconditions.checkNotNull; +/** + * @deprecated Just use BaseBlock directly + */ +@Deprecated public class BlockPattern implements Pattern { private BaseBlock block; diff --git a/core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java b/core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java index c0df5765..5e4d8364 100644 --- a/core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java +++ b/core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java @@ -19,11 +19,14 @@ package com.sk89q.worldedit.util.command.fluent; +import com.boydti.fawe.config.Commands; +import com.sk89q.minecraft.util.commands.Command; import com.sk89q.worldedit.util.command.CallableProcessor; import com.sk89q.worldedit.util.command.CommandCallable; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.SimpleDispatcher; import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; +import javax.annotation.Nullable; /** * A collection of commands. @@ -93,7 +96,7 @@ public class DispatcherNode { * @return this object * @see ParametricBuilder#registerMethodsAsCommands(com.sk89q.worldedit.util.command.Dispatcher, Object) */ - public DispatcherNode registerMethods(Object object, CallableProcessor processor) { + public DispatcherNode registerMethods(Object object, @Nullable CallableProcessor processor) { ParametricBuilder builder = graph.getBuilder(); if (builder == null) { throw new RuntimeException("No ParametricBuilder set"); @@ -102,6 +105,43 @@ public class DispatcherNode { return this; } + /** + * Build and register sub commands with this dispatcher using the + * {@link ParametricBuilder} assigned on the objects registered command aliases {@link com.sk89q.minecraft.util.commands.Command}. + * + * @param object the object provided to the {@link ParametricBuilder} + * @return this object + */ + public DispatcherNode registerSubMethods(Object object) { + return registerSubMethods(object, null); + } + + /** + * Build and register sub commands with this dispatcher using the + * {@link ParametricBuilder} assigned on the objects registered command aliases {@link com.sk89q.minecraft.util.commands.Command}. + * + * @param object the object provided to the {@link ParametricBuilder} + * @param processor the command processor + * @return this object + */ + public DispatcherNode registerSubMethods(Object object, @Nullable CallableProcessor processor) { + Class clazz = object.getClass(); + return groupAndDescribe(clazz).registerMethods(object, processor).parent(); + } + + public DispatcherNode groupAndDescribe(Class clazz) { + Command cmd = (Command) clazz.getAnnotation(Command.class); + if (cmd == null) { + throw new RuntimeException("This class does not have any command annotations"); + } + cmd = Commands.translate(clazz, cmd); + DispatcherNode res = group(cmd.aliases()); + if (cmd.desc() != null && !cmd.desc().isEmpty()) { + res = res.describeAs(cmd.desc()); + } + return res; + } + /** * Create a new command that will contain sub-commands. *

@@ -114,7 +154,8 @@ public class DispatcherNode { public DispatcherNode group(String... alias) { SimpleDispatcher command = new SimpleDispatcher(); getDispatcher().registerCommand(command, alias); - return new DispatcherNode(graph, this, command); + DispatcherNode res = new DispatcherNode(graph, this, command); + return res; } /**