From f55a58a3f303607dc19e212a32c57e780ded0549 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 15 Sep 2016 19:49:29 +1000 Subject: [PATCH] Various Reduce max memory allocation size - Uses multiple byte arrays instead of one large one for streams - Faster read/write as less dependent on arraycopy Remove world compression (it was buggy / there was no interest)\ EditSession can now be used as a world Fix pos1/pos2 being allowed outside the world Fixed liquid mask not being thread safe Fixed plot upload Reduce packet sending - Increase delay to being able to see blocks, but more efficient --- build.gradle | 2 +- .../fawe/bukkit/v1_10/BukkitMain_110.java | 144 ---------- .../java/com/boydti/fawe/config/Settings.java | 5 - .../boydti/fawe/example/MappedFaweQueue.java | 1 - .../com/boydti/fawe/jnbt/anvil/MCAFile.java | 2 +- .../changeset/MemoryOptimizedHistory.java | 34 +-- .../object/io/FastByteArrayOutputStream.java | 271 ++++++++++++++---- .../object/io/FastByteArraysInputStream.java | 110 +++++++ .../general/plot/FaweSchematicHandler.java | 15 +- .../boydti/fawe/util/EditSessionBuilder.java | 10 +- .../com/boydti/fawe/util/HastebinUtility.java | 23 +- .../boydti/fawe/wrappers/PlayerWrapper.java | 14 +- .../boydti/fawe/wrappers/WorldWrapper.java | 102 +------ .../com/sk89q/worldedit/CuboidClipboard.java | 2 +- .../java/com/sk89q/worldedit/EditSession.java | 196 ++++++++++++- .../worldedit/command/ClipboardCommands.java | 7 +- .../worldedit/command/SelectionCommands.java | 7 +- .../command/tool/LongRangeBuildTool.java | 34 +-- .../command/tool/brush/GravityBrush.java | 4 +- .../java/net/jpountz/lz4/LZ4StreamTest.java | 8 +- 20 files changed, 583 insertions(+), 408 deletions(-) create mode 100644 core/src/main/java/com/boydti/fawe/object/io/FastByteArraysInputStream.java diff --git a/build.gradle b/build.gradle index 83a6bba2..d78de543 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ ext { git = org.ajoberstar.grgit.Grgit.open(file(".git")) revision = "-${git.head().abbreviatedId}" parents = git.head().parentIds; - index = -43; // Offset to mach CI + index = -45; // Offset to mach CI for (;parents != null && !parents.isEmpty();index++) { commit = git.getResolve().toCommit(parents.get(0)); parents = commit.getParentIds(); diff --git a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitMain_110.java b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitMain_110.java index a062d1cd..bf19d106 100644 --- a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitMain_110.java +++ b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitMain_110.java @@ -2,29 +2,8 @@ package com.boydti.fawe.bukkit.v1_10; import com.boydti.fawe.bukkit.ABukkitMain; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.io.BufferedRandomAccessFile; -import com.boydti.fawe.object.io.FastByteArrayInputStream; -import com.boydti.fawe.object.io.FastByteArrayOutputStream; -import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.worldedit.world.World; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.lang.reflect.Field; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.zip.Deflater; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.GZIPInputStream; -import java.util.zip.InflaterInputStream; -import net.minecraft.server.v1_10_R1.RegionFile; -import net.minecraft.server.v1_10_R1.RegionFileCache; public class BukkitMain_110 extends ABukkitMain { @Override @@ -40,128 +19,5 @@ public class BukkitMain_110 extends ABukkitMain { @Override public void onEnable() { super.onEnable(); - if (Settings.EXPERIMENTAL.WORLD_COMPRESSION != -1) { - try { - ReflectionUtils.setFailsafeFieldValue(RegionFileCache.class.getDeclaredField("a"), null, new ConcurrentHashMap(8, 0.9f, 1) { - @Override - public RegionFile get(Object key) { - RegionFile existing = super.get(key); - if (existing != null) { - return existing; - } - try { - File file = (File) key; - if (!file.exists()) { - file.getParentFile().mkdirs(); - } - if (size() >= 256) { - RegionFileCache.a(); - } - RegionFile regionFile = new RegionFile(file) { - - private int[] d = ReflectionUtils.getField(RegionFile.class.getDeclaredField("d"), this); - private int[] e = ReflectionUtils.getField(RegionFile.class.getDeclaredField("e"), this); - private List f = ReflectionUtils.getField(RegionFile.class.getDeclaredField("f"), this); - public RandomAccessFile c = null; - - @Override - public DataOutputStream b(final int i, final int j) { - if (i < 0 || i >= 32 || j < 0 || j >= 32) { - return null; - } -// if (Settings.EXPERIMENTAL.FAST_WORLD_COMPRESSION) { -// try { -// return new DataOutputStream(new AsyncBufferedOutputStream(new LZ4OutputStream(new FastByteArrayOutputStream() { -// @Override -// public void close() { -// try { -// super.close(); -// } catch (IOException e1) { -// e1.printStackTrace(); -// } -// a(i, j, array, length); -// } -// }, 16000))); -// } catch (Throwable e) { -// e.printStackTrace(); -// } -// } - return new DataOutputStream(new BufferedOutputStream(new DeflaterOutputStream(new FastByteArrayOutputStream() { - @Override - public void close() throws IOException { - super.close(); - a(i, j, this.array, length); - } - }, new Deflater(Settings.EXPERIMENTAL.WORLD_COMPRESSION)))); - } - - @Override - public synchronized DataInputStream a(int i, int j) { - if ((i < 0) || (i >= 32) || (j < 0) || (j >= 32)) { - return null; - } else { - try { - int k = d[(i + j * 32)]; - if (k == 0) { - return null; - } else { - int l = k >> 8; - int i1 = k & 255; - if (l + i1 > f.size()) { - return null; - } else { - c.seek((long) (l * 4096)); - int j1 = this.c.readInt(); - if (j1 > 4096 * i1) { - return null; - } else if (j1 <= 0) { - return null; - } else { - byte b0 = c.readByte(); - byte[] abyte; - if (b0 == 1) { - abyte = new byte[j1 - 1]; - c.read(abyte); - return new DataInputStream(new BufferedInputStream(new GZIPInputStream(new FastByteArrayInputStream(abyte)))); - } else if (b0 == 2) { - abyte = new byte[j1 - 1]; - c.read(abyte); -// if (Settings.EXPERIMENTAL.FAST_WORLD_COMPRESSION) { -// return new DataInputStream(new LZ4InputStream(new FastByteArrayInputStream(abyte))); -// } - return new DataInputStream(new BufferedInputStream(new InflaterInputStream(new FastByteArrayInputStream(abyte)))); - } else { - return null; - } - } - } - } - } catch (IOException var9) { - var9.printStackTrace(); - return null; - } - } - } - }; - Field field = RegionFile.class.getDeclaredField("c"); - field.setAccessible(true); - RandomAccessFile raf2 = (RandomAccessFile) field.get(regionFile); - raf2.close(); - final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw"); - ReflectionUtils.setFailsafeFieldValue(field, regionFile, raf); - put(file, regionFile); - regionFile.getClass().getDeclaredField("c").set(regionFile, raf); - return regionFile; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - }); - ; - } catch (Throwable e) { - e.printStackTrace(); - } - } } } \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index c470f2eb..ee4540de 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -199,11 +199,6 @@ public class Settings extends Config { "Directly modify the region files.", }) public static boolean ANVIL_QUEUE_MODE = false; - @Comment({ - "Set the default world compression", - " - Only supports Bukkit 1.10 right now" - }) - public static int WORLD_COMPRESSION = -1; } public static class WEB { diff --git a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java index 241dc6d0..356b6761 100644 --- a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java @@ -206,7 +206,6 @@ public abstract class MappedFaweQueue extends FaweQueue { public void end(FaweChunk chunk) { chunk.end(); - sendChunk(chunk); } @Override 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 caff1dda..f71c760a 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 @@ -259,7 +259,7 @@ public class MCAFile { } FastByteArrayOutputStream baos = new FastByteArrayOutputStream(0); fieldBuf4.set(baos, buffer3); - DeflaterOutputStream deflater = new DeflaterOutputStream(baos, new Deflater(Settings.EXPERIMENTAL.WORLD_COMPRESSION), 1, true); + DeflaterOutputStream deflater = new DeflaterOutputStream(baos, new Deflater(6), 1, true); fieldBuf5.set(deflater, buffer2); BufferedOutputStream bos = new BufferedOutputStream(deflater, 1); fieldBuf6.set(bos, buffer1); 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 b566074d..32e7f44b 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 @@ -3,8 +3,8 @@ package com.boydti.fawe.object.changeset; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweInputStream; import com.boydti.fawe.object.FaweOutputStream; -import com.boydti.fawe.object.io.FastByteArrayInputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream; +import com.boydti.fawe.object.io.FastByteArraysInputStream; import com.boydti.fawe.util.MainUtil; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; @@ -21,23 +21,24 @@ import java.io.OutputStream; */ public class MemoryOptimizedHistory extends FaweStreamChangeSet { - private byte[] ids; + private int size = 0; + private byte[][] ids; private FastByteArrayOutputStream idsStream; private FaweOutputStream idsStreamZip; - private byte[] entC; + private byte[][] entC; private FastByteArrayOutputStream entCStream; private NBTOutputStream entCStreamZip; - private byte[] entR; + private byte[][] entR; private FastByteArrayOutputStream entRStream; private NBTOutputStream entRStreamZip; - private byte[] tileC; + private byte[][] tileC; private FastByteArrayOutputStream tileCStream; private NBTOutputStream tileCStreamZip; - private byte[] tileR; + private byte[][] tileR; private FastByteArrayOutputStream tileRStream; private NBTOutputStream tileRStreamZip; @@ -51,31 +52,32 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { try { if (idsStream != null) { idsStreamZip.close(); - ids = idsStream.toByteArray(); + size = idsStream.getSize(); + ids = idsStream.toByteArrays(); idsStream = null; idsStreamZip = null; } if (entCStream != null) { entCStreamZip.close(); - entC = entCStream.toByteArray(); + entC = entCStream.toByteArrays(); entCStream = null; entCStreamZip = null; } if (entRStream != null) { entRStreamZip.close(); - entR = entRStream.toByteArray(); + entR = entRStream.toByteArrays(); entRStream = null; entRStreamZip = null; } if (tileCStream != null) { tileCStreamZip.close(); - tileC = tileCStream.toByteArray(); + tileC = tileCStream.toByteArrays(); tileCStream = null; tileCStreamZip = null; } if (tileRStream != null) { tileRStreamZip.close(); - tileR = tileRStream.toByteArray(); + tileR = tileRStream.toByteArrays(); tileRStream = null; tileRStreamZip = null; } @@ -115,7 +117,7 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { if (ids == null) { return null; } - FaweInputStream result = MainUtil.getCompressedIS(new FastByteArrayInputStream(ids)); + FaweInputStream result = MainUtil.getCompressedIS(new FastByteArraysInputStream(ids)); result.skip(FaweStreamChangeSet.HEADER_SIZE); return result; } @@ -158,21 +160,21 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { @Override public NBTInputStream getEntityCreateIS() throws IOException { - return entC == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArrayInputStream(entC))); + return entC == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArraysInputStream(entC))); } @Override public NBTInputStream getEntityRemoveIS() throws IOException { - return entR == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArrayInputStream(entR))); + return entR == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArraysInputStream(entR))); } @Override public NBTInputStream getTileCreateIS() throws IOException { - return tileC == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArrayInputStream(tileC))); + return tileC == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArraysInputStream(tileC))); } @Override public NBTInputStream getTileRemoveIS() throws IOException { - return tileR == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArrayInputStream(tileR))); + return tileR == null ? null : new NBTInputStream(MainUtil.getCompressedIS(new FastByteArraysInputStream(tileR))); } } diff --git a/core/src/main/java/com/boydti/fawe/object/io/FastByteArrayOutputStream.java b/core/src/main/java/com/boydti/fawe/object/io/FastByteArrayOutputStream.java index 9ca3da83..37daec6c 100644 --- a/core/src/main/java/com/boydti/fawe/object/io/FastByteArrayOutputStream.java +++ b/core/src/main/java/com/boydti/fawe/object/io/FastByteArrayOutputStream.java @@ -1,96 +1,245 @@ package com.boydti.fawe.object.io; -import com.boydti.fawe.util.ByteArrays; import java.io.IOException; import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.io.Writer; +import java.util.ArrayDeque; +import java.util.Iterator; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorCompletionService; + +/** + * A speedy implementation of ByteArrayOutputStream. It's not synchronized, and it + * does not copy buffers when it's expanded. There's also no copying of the internal buffer + * if it's contents is extracted with the writeTo(stream) method. + * + * @author Rickard ?berg + * @author Brat Baker (Atlassian) + * @author Alexey + * @version $Date: 2008-01-19 10:09:56 +0800 (Sat, 19 Jan 2008) $ $Id: FastByteArrayOutputStream.java 3000 2008-01-19 02:09:56Z tm_jee $ + */ public class FastByteArrayOutputStream extends OutputStream { - /** - * The array backing the output stream. - */ - public final static int DEFAULT_INITIAL_CAPACITY = 16; + private static final int DEFAULT_BLOCK_SIZE = 8192; - /** - * The array backing the output stream. - */ - public byte[] array; + private ArrayDeque buffers = new ArrayDeque<>(); - /** - * The number of valid bytes in {@link #array}. - */ - public int length; + private byte[] buffer; + private int blockSize; + private int index; + private int size; - /** - * The current writing position. - */ - private int position; - /** - * Creates a new array output stream with an initial capacity of {@link #DEFAULT_INITIAL_CAPACITY} bytes. - */ public FastByteArrayOutputStream() { - this(DEFAULT_INITIAL_CAPACITY); + this(DEFAULT_BLOCK_SIZE); } - /** - * Creates a new array output stream with a given initial capacity. - * - * @param initialCapacity the initial length of the backing array. - */ - public FastByteArrayOutputStream(final int initialCapacity) { - array = new byte[initialCapacity]; + public FastByteArrayOutputStream(int aSize) { + blockSize = aSize; + buffer = new byte[blockSize]; } - /** - * Creates a new array output stream wrapping a given byte array. - * - * @param a the byte array to wrap. - */ - public FastByteArrayOutputStream(final byte[] a) { - array = a; + + public int getSize() { + return size + index; } - /** - * Marks this array output stream as empty. - */ - public void reset() { - length = 0; - position = 0; + public byte[][] toByteArrays() { + if (index > 0) { + byte[] buf2 = new byte[index]; + System.arraycopy(buffer, 0, buf2, 0, index); + buffers.addLast(buf2); + size += index; + index = 0; + } + byte[][] res = new byte[buffers.size()][]; + int i = 0; + for (byte[] bytes : buffers) { + res[i++] = bytes; + } + return res; } - public void trim() { - this.array = ByteArrays.trim(this.array, this.length); + public byte[] toByteArray(ExecutorCompletionService service) { + if (buffers.size() < 8) { + return toByteArray(); + } + final byte[] data = new byte[getSize()]; + // Check if we have a list of buffers + int pos = 0; + int count = 0; + if (buffers != null) { + for (final byte[] bytes : buffers) { + final int finalPos = pos; + count++; + service.submit(new Callable() { + @Override + public Object call() throws Exception { + System.arraycopy(bytes, 0, data, finalPos, bytes.length); + return null; + } + }); + pos += bytes.length; + } + } + try { + for (int i = 0; i < count; i++) { + service.take(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + // write the internal buffer directly + System.arraycopy(buffer, 0, data, pos, index); + + return data; } public byte[] toByteArray() { - trim(); - return array; + byte[] data = new byte[getSize()]; + + // Check if we have a list of buffers + int pos = 0; + + if (buffers != null) { + for (byte[] bytes : buffers) { + System.arraycopy(bytes, 0, data, pos, bytes.length); + pos += bytes.length; + } + } + + // write the internal buffer directly + System.arraycopy(buffer, 0, data, pos, index); + + return data; } - public void write(final int b) { - if (position >= array.length) array = ByteArrays.grow(array, position + 1, length); - array[position++] = (byte) b; - if (length < position) length = position; + public String toString() { + return new String(toByteArray()); } - public void write(final byte[] b, final int off, final int len) throws IOException { - ByteArrays.ensureOffsetLength(b, off, len); - if (position + len > array.length) array = ByteArrays.grow(array, position + len, position); - System.arraycopy(b, off, array, position, len); - if (position + len > length) length = position += len; + @Override + public void write(byte[] b) throws IOException { + if (b.length > blockSize) { + if (index > 0) { + byte[] buf2 = new byte[index]; + System.arraycopy(buffer, 0, buf2, 0, index); + buffer = buf2; + addBuffer(); + } + size += b.length; + buffers.addLast(b); + } else { + write(b, 0, b.length); + } } - public void position(long newPosition) { - if (position > Integer.MAX_VALUE) throw new IllegalArgumentException("Position too large: " + newPosition); - position = (int) newPosition; + public void write(int datum) { + if (index == blockSize) { + addBuffer(); + } + // store the byte + buffer[index++] = (byte) datum; } - public long position() { - return position; + public void write(byte[] data, int offset, int length) throws IOException { + if ((offset < 0) || ((offset + length) > data.length) || (length < 0)) { + throw new IndexOutOfBoundsException(); + } else { + if ((index + length) > blockSize) { + int copyLength; + + do { + if (index == blockSize) { + addBuffer(); + } + + copyLength = blockSize - index; + + if (length < copyLength) { + copyLength = length; + } + + System.arraycopy(data, offset, buffer, index, copyLength); + offset += copyLength; + index += copyLength; + length -= copyLength; + } while (length > 0); + } else { + // Copy in the subarray + System.arraycopy(data, offset, buffer, index, length); + index += length; + } + } } - public long length() throws IOException { - return length; + public void writeTo(OutputStream out) throws IOException { + // Check if we have a list of buffers + if (buffers != null) { + Iterator iter = buffers.iterator(); + + while (iter.hasNext()) { + byte[] bytes = (byte[]) iter.next(); + out.write(bytes, 0, blockSize); + } + } + + // write the internal buffer directly + out.write(buffer, 0, index); + } + + public void writeTo(RandomAccessFile out) throws IOException { + // Check if we have a list of buffers + if (buffers != null) { + Iterator iter = buffers.iterator(); + + while (iter.hasNext()) { + byte[] bytes = (byte[]) iter.next(); + out.write(bytes, 0, blockSize); + } + } + + // write the internal buffer directly + out.write(buffer, 0, index); + } + + public void writeTo(Writer out, String encoding) throws IOException { + if (buffers != null) { + writeToViaSmoosh(out, encoding); + } else { + writeToViaString(out, encoding); + } + } + + private void writeToViaString(Writer out, String encoding) throws IOException { + byte[] bufferToWrite = buffer; // this is always the last buffer to write + int bufferToWriteLen = index; // index points to our place in the last buffer + writeToImpl(out, encoding, bufferToWrite, bufferToWriteLen); + } + + private void writeToViaSmoosh(Writer out, String encoding) throws IOException { + byte[] bufferToWrite = toByteArray(); + int bufferToWriteLen = bufferToWrite.length; + writeToImpl(out, encoding, bufferToWrite, bufferToWriteLen); + } + + private void writeToImpl(Writer out, String encoding, byte[] bufferToWrite, int bufferToWriteLen) + throws IOException { + String writeStr; + if (encoding != null) { + writeStr = new String(bufferToWrite, 0, bufferToWriteLen, encoding); + } else { + writeStr = new String(bufferToWrite, 0, bufferToWriteLen); + } + out.write(writeStr); + } + + private void addBuffer() { + buffers.addLast(buffer); + buffer = new byte[blockSize]; + size += index; + index = 0; } } \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/io/FastByteArraysInputStream.java b/core/src/main/java/com/boydti/fawe/object/io/FastByteArraysInputStream.java new file mode 100644 index 00000000..d4900606 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/io/FastByteArraysInputStream.java @@ -0,0 +1,110 @@ +package com.boydti.fawe.object.io; + +import java.io.InputStream; + +public class FastByteArraysInputStream extends InputStream { + private final byte[][] buffers; + private final int length; + + private byte[] current; + + private int layer; + private int localIndex; + private int globalIndex; + private int curLen; + + + public FastByteArraysInputStream(byte[][] buffers) { + this.buffers = buffers; + int size = 0; + for (byte[] bytes : buffers) { + size += bytes.length; + } + this.length = size; + current = buffers.length == 0 ? new byte[layer++] : buffers[layer++]; + curLen = current.length; + } + + @Override + public boolean markSupported() { + return false; + } + + @Override + public void reset() { + } + + @Override + public void close() { + } + + @Override + public void mark(int dummy) { + } + + @Override + public int available() { + return this.length - this.globalIndex; + } + + @Override + public long skip(long n) { + if (n <= this.length - this.globalIndex) { + this.globalIndex += (int) n; + this.localIndex += (int) n; + ensureBuffer(); + return n; + } + n = this.length - this.globalIndex; + layer = buffers.length - 1; + this.current = buffers[layer]; + this.curLen = current.length; + this.localIndex = current.length; + this.globalIndex = this.length; + return n; + } + + @Override + public int read() { + if (curLen != localIndex) { + globalIndex++; + return this.current[localIndex++] & 0xFF; + } else if (length == globalIndex) { + return -1; + } else { + localIndex = 0; + current = buffers[layer++]; + curLen = current.length; + globalIndex++; + return this.current[localIndex++] & 0xFF; + } + } + + @Override + public int read(byte[] b, int offset, int length) { + if (this.length <= this.globalIndex) { + return length == 0 ? 0 : -1; + } + int n = Math.min(length, this.length - this.globalIndex); + int read = 0; + int amount = Math.min(curLen - localIndex, n - read); + System.arraycopy(this.current, localIndex, b, offset + read, amount); + read += amount; + localIndex += amount; + globalIndex += amount; + ensureBuffer(); + return read; + } + + public void ensureBuffer() { + while (localIndex >= curLen && layer < buffers.length) { + localIndex -= curLen; + current = buffers[layer++]; + this.curLen = current.length; + } + } + + public long length() { + return this.length; + } +} diff --git a/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweSchematicHandler.java b/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweSchematicHandler.java index c3f4646b..e5c12c69 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweSchematicHandler.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweSchematicHandler.java @@ -59,7 +59,7 @@ public class FaweSchematicHandler extends SchematicHandler { Location pos1 = corners[0]; Location pos2 = corners[1]; final CuboidRegion region = new CuboidRegion(new Vector(pos1.getX(), pos1.getY(), pos1.getZ()), new Vector(pos2.getX(), pos2.getY(), pos2.getZ())); - final EditSession editSession = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build(); + final EditSession editSession = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build(); final int mx = pos1.getX(); final int my = pos1.getY(); @@ -144,12 +144,13 @@ public class FaweSchematicHandler extends SchematicHandler { @Override public void run(OutputStream output) { try { - GZIPOutputStream gzip = new GZIPOutputStream(output, true); - com.sk89q.jnbt.CompoundTag weTag = (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag); - NBTOutputStream nos = new NBTOutputStream(gzip); - Map map = weTag.getValue(); - nos.writeNamedTag("Schematic", map.containsKey("Schematic") ? map.get("Schematic") : weTag); - gzip.flush(); + try (GZIPOutputStream gzip = new GZIPOutputStream(output, true)) { + com.sk89q.jnbt.CompoundTag weTag = (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag); + try (NBTOutputStream nos = new NBTOutputStream(gzip)) { + Map map = weTag.getValue(); + nos.writeNamedTag("Schematic", map.containsKey("Schematic") ? map.get("Schematic") : weTag); + } + } } catch (IOException e) { e.printStackTrace(); } diff --git a/core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java b/core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java index 71abc746..d432bbcf 100644 --- a/core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java +++ b/core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java @@ -1,6 +1,5 @@ package com.boydti.fawe.util; -import com.boydti.fawe.FaweAPI; import com.boydti.fawe.config.Settings; import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; import com.boydti.fawe.object.FaweLimit; @@ -20,10 +19,12 @@ import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; + import static com.google.common.base.Preconditions.checkNotNull; public class EditSessionBuilder { private World world; + private String worldName; private FaweQueue queue; private FawePlayer player; private FaweLimit limit; @@ -57,8 +58,9 @@ public class EditSessionBuilder { this.world = world; } - public EditSessionBuilder(@Nonnull String world) { - this(FaweAPI.getWorld(world)); + public EditSessionBuilder(@Nonnull String worldName) { + checkNotNull(worldName); + this.worldName = worldName; } public EditSessionBuilder player(@Nullable FawePlayer player) { @@ -164,6 +166,6 @@ public class EditSessionBuilder { } public EditSession build() { - return new EditSession(world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); + return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); } } diff --git a/core/src/main/java/com/boydti/fawe/util/HastebinUtility.java b/core/src/main/java/com/boydti/fawe/util/HastebinUtility.java index 2e7ae290..0c110ef1 100644 --- a/core/src/main/java/com/boydti/fawe/util/HastebinUtility.java +++ b/core/src/main/java/com/boydti/fawe/util/HastebinUtility.java @@ -1,5 +1,6 @@ package com.boydti.fawe.util; +import com.boydti.fawe.object.RunnableVal; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; @@ -16,17 +17,15 @@ public class HastebinUtility { public static final String BIN_URL = "http://hastebin.com/documents", USER_AGENT = "Mozilla/5.0"; public static final Pattern PATTERN = Pattern.compile("\\{\"key\":\"([\\S\\s]*)\"\\}"); - public static String upload(final String string) throws IOException { + public static String upload(final RunnableVal writeTask) throws IOException { final URL url = new URL(BIN_URL); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("User-Agent", USER_AGENT); connection.setDoOutput(true); - - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(string.getBytes()); - outputStream.flush(); + try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) { + writeTask.run(os); } StringBuilder response; @@ -47,6 +46,19 @@ public class HastebinUtility { } } + public static String upload(final String s) throws IOException { + return upload(new RunnableVal() { + @Override + public void run(DataOutputStream value) { + try { + value.writeChars(s); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } + public static String upload(final File file) throws IOException { final StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { @@ -57,6 +69,7 @@ public class HastebinUtility { } } return upload(content.toString()); + } } diff --git a/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java b/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java index 20d43776..3911721e 100644 --- a/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java +++ b/core/src/main/java/com/boydti/fawe/wrappers/PlayerWrapper.java @@ -3,12 +3,10 @@ package com.boydti.fawe.wrappers; import com.boydti.fawe.Fawe; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSessionFactory; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.PlayerDirection; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; @@ -202,14 +200,10 @@ public class PlayerWrapper implements Player { public void floatAt(final int x, final int y, final int z, final boolean alwaysGlass) { EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory(); final EditSession edit = factory.getEditSession(parent.getWorld(), -1, null, this); - try { - edit.setBlock(new Vector(x, y - 1, z), new BaseBlock( BlockType.GLASS.getID())); - LocalSession session = Fawe.get().getWorldEdit().getSession(this); - if (session != null) { - session.remember(edit, true, false, FawePlayer.wrap(this).getLimit().MAX_HISTORY); - } - } catch (MaxChangedBlocksException e) { - MainUtil.handleError(e); + edit.setBlockFast(new Vector(x, y - 1, z), new BaseBlock( BlockType.GLASS.getID())); + LocalSession session = Fawe.get().getWorldEdit().getSession(this); + if (session != null) { + session.remember(edit, true, false, FawePlayer.wrap(this).getLimit().MAX_HISTORY); } TaskManager.IMP.sync(new RunnableVal() { @Override diff --git a/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java b/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java index b1cc7488..5c52d932 100644 --- a/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java +++ b/core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java @@ -1,10 +1,6 @@ package com.boydti.fawe.wrappers; -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.object.changeset.FaweChangeSet; -import com.boydti.fawe.object.extent.FaweRegionExtent; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.BlockVector2D; @@ -22,7 +18,6 @@ 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; @@ -31,7 +26,6 @@ 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 LocalWorld { @@ -250,101 +244,7 @@ public class WorldWrapper extends LocalWorld { @Override public boolean regenerate(final Region region, final EditSession session) { - final FaweQueue queue = session.getQueue(); - queue.setChangeTask(null); - final FaweChangeSet fcs = (FaweChangeSet) session.getChangeSet(); - final FaweRegionExtent fe = session.getRegionExtent(); - session.setSize(1); - final boolean cuboid = region instanceof CuboidRegion; - Set chunks = region.getChunks(); - for (Vector2D chunk : chunks) { - final int cx = chunk.getBlockX(); - final int cz = chunk.getBlockZ(); - final int bx = cx << 4; - final int bz = cz << 4; - Vector cmin = new Vector(bx, 0, bz); - Vector cmax = cmin.add(15, getMaxY(), 15); - final boolean containsBot1 = (fe == null || fe.contains(cmin.getBlockX(), cmin.getBlockY(), cmin.getBlockZ())); - final boolean containsBot2 = region.contains(cmin); - final boolean containsTop1 = (fe == null || fe.contains(cmax.getBlockX(), cmax.getBlockY(), cmax.getBlockZ())); - final boolean containsTop2 = region.contains(cmax); - if ((containsBot2 && containsTop2 && !containsBot1 && !containsTop1)) { - continue; - } - RunnableVal r = new RunnableVal() { - @Override - public void run(Vector2D chunk) { - if (cuboid && containsBot1 && containsBot2 && containsTop1 && containsTop2) { - 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.getCombinedId4DataDebug(xx, y, zz, 0, session); - 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 { - Vector mutable = new Vector(0,0,0); - for (int x = 0; x < 16; x++) { - int xx = x + bx; - mutable.x = xx; - for (int z = 0; z < 16; z++) { - int zz = z + bz; - mutable.z = zz; - for (int y = 0; y < getMaxY() + 1; y++) { - mutable.y = y; - int from = queue.getCombinedId4Data(xx, y, zz); - boolean contains = (fe == null || fe.contains(xx, y, zz)) && region.contains(mutable); - if (contains) { - if (fcs != null) { - if (!FaweCache.hasNBT(from >> 4)) { - fcs.add(xx, y, zz, from, 0); - } else { - try { - BaseBlock block = getLazyBlock(mutable); - fcs.add(mutable, 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); - queue.setBlock(xx, y, zz, id, data); - if (FaweCache.hasNBT(id)) { - BaseBlock block = getBlock(new Vector(xx, y, zz)); - if (block.hasNbtData()) { - queue.setTile(xx, y, zz, block.getNbtData()); - } - } - } - } - } - } - } - queue.regenerateChunk(cx, cz); - } - }; - r.value = chunk; - TaskManager.IMP.sync(r); - } - session.flushQueue(); - return false; + return session.regenerate(region); } @Override diff --git a/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java b/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java index 46adb5cb..eeb6b50d 100644 --- a/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java +++ b/core/src/main/java/com/sk89q/worldedit/CuboidClipboard.java @@ -689,7 +689,7 @@ public class CuboidClipboard { if (noAir && block.isAir()) { continue; } - editSession.setBlock(new Vector(x, y, z).add(newOrigin), block); + editSession.setBlockFast(new Vector(x, y, z).add(newOrigin), block); } } } diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 3aa088c9..c37158a8 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit; import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; @@ -33,6 +34,7 @@ import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.HistoryExtent; import com.boydti.fawe.object.NullChangeSet; import com.boydti.fawe.object.RegionWrapper; +import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; @@ -46,8 +48,11 @@ import com.boydti.fawe.util.ExtentTraverser; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.Perm; import com.boydti.fawe.util.SetQueue; +import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.wrappers.WorldWrapper; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.entity.BaseEntity; @@ -144,7 +149,7 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY; * {@link Extent}s that are chained together. For example, history is logged * using the {@link ChangeSetExtent}.

*/ -public class EditSession implements Extent { +public class EditSession extends AbstractWorld { /** * Used by {@link #setBlock(Vector, BaseBlock, Stage)} to * determine which {@link Extent}s should be bypassed. @@ -154,6 +159,7 @@ public class EditSession implements Extent { } private World world; + private String worldName; private FaweQueue queue; private AbstractDelegateExtent extent; private HistoryExtent history; @@ -182,7 +188,14 @@ public class EditSession implements Extent { PlayerDirection.UP.vector(), PlayerDirection.DOWN.vector(), }; + @Deprecated public EditSession(@Nonnull World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) { + this(null, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, bus, event); + } + + public EditSession(@Nullable String worldName, @Nullable World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) { + this.worldName = worldName == null ? world == null ? queue == null ? "" : queue.getWorldName() : world.getName() : worldName; + if (world == null && this.worldName != null) world = FaweAPI.getWorld(this.worldName); this.world = world = WorldWrapper.wrap((AbstractWorld) world); if (bus == null) { bus = WorldEdit.getInstance().getEventBus(); @@ -255,7 +268,7 @@ public class EditSession implements Extent { if (world instanceof MCAWorld) { queue = ((MCAWorld) world).getQueue(); } else { - queue = SetQueue.IMP.getNewQueue(world, fastmode, autoQueue); + queue = SetQueue.IMP.getNewQueue(this, fastmode, autoQueue); } } else if (Settings.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) { queue = new MCAQueue(queue); @@ -283,7 +296,7 @@ public class EditSession implements Extent { } } this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); - this.maxY = this.world == null ? 255 : world.getMaxY(); + this.maxY = getWorld() == null ? 255 : world.getMaxY(); } /** @@ -791,7 +804,9 @@ public class EditSession implements Extent { * @param naturalOnly look at natural blocks or all blocks * @return height of highest block found or 'minY' */ - public int getHighestTerrainBlock(final int x, final int z, final int minY, final int maxY, final boolean naturalOnly) { + public int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, final boolean naturalOnly) { + maxY = Math.min(getMaximumPoint().getBlockY(), Math.max(0, maxY)); + minY = Math.max(0, minY); for (int y = maxY; y >= minY; --y) { BaseBlock block = getLazyBlock(x, y, z); final int id = block.getId(); @@ -956,7 +971,11 @@ public class EditSession implements Extent { } @Override - public boolean setBlock(final Vector position, final BaseBlock block) throws MaxChangedBlocksException { + public boolean setBlock(final Vector position, final BaseBlock block, final boolean ignorePhysics) throws MaxChangedBlocksException { + return setBlockFast(position, block); + } + + public boolean setBlockFast(final Vector position, final BaseBlock block) { this.changes++; try { return this.extent.setBlock(position, block); @@ -975,7 +994,7 @@ public class EditSession implements Extent { */ @SuppressWarnings("deprecation") public boolean setBlock(final Vector position, final Pattern pattern) throws MaxChangedBlocksException { - return this.setBlock(position, pattern.next(position)); + return this.setBlockFast(position, pattern.next(position)); } /** @@ -1020,7 +1039,7 @@ public class EditSession implements Extent { */ @Deprecated public boolean setBlockIfAir(final Vector position, final BaseBlock block) throws MaxChangedBlocksException { - return this.getBlock(position).isAir() && this.setBlock(position, block); + return this.getBlock(position).isAir() && this.setBlockFast(position, block); } @Override @@ -1756,15 +1775,16 @@ public class EditSession implements Extent { checkNotNull(origin); checkArgument(radius >= 0, "radius >= 0 required"); Mask liquidMask; - if (getWorld() != null) { - liquidMask = getWorld().createLiquidMask(); - } else { + // Not thread safe, use hardcoded liquidmask +// if (getWorld() != null) { +// liquidMask = getWorld().createLiquidMask(); +// } else { liquidMask = new BlockMask(this, new BaseBlock(BlockID.STATIONARY_LAVA, -1), new BaseBlock(BlockID.LAVA, -1), new BaseBlock(BlockID.STATIONARY_WATER, -1), new BaseBlock(BlockID.WATER, -1)); - } +// } final MaskIntersection mask = new MaskIntersection( new BoundedHeightMask(0, EditSession.this.getMaximumPoint().getBlockY()), new RegionMask( @@ -2471,7 +2491,7 @@ public class EditSession implements Extent { // read block from world BaseBlock material = FaweCache.CACHE_BLOCK[this.queue.getCombinedId4DataDebug(sourcePosition.getBlockX(), sourcePosition.getBlockY(), sourcePosition.getBlockZ(), 0, this)]; // queue operation - this.setBlock(position, material); + this.setBlockFast(position, material); } return changes; } @@ -2545,7 +2565,7 @@ public class EditSession implements Extent { continue outer; } } - this.setBlock(position, pattern.next(position)); + this.setBlockFast(position, pattern.next(position)); } return changes; @@ -2812,6 +2832,156 @@ public class EditSession implements Extent { return (x * x) + (z * z); } + + @Override + public String getName() { + return worldName; + } + + @Override + public int getBlockLightLevel(Vector position) { + return queue.getEmmittedLight((int) position.x, (int) position.y, (int) position.z); + } + + @Override + public boolean clearContainerBlockContents(Vector position) { + BaseBlock block = getBlock(position); + CompoundTag nbt = block.getNbtData(); + if (nbt != null) { + if (nbt.containsKey("items")) { + block.setNbtData(null); + try { + return setBlock(position, block); + } catch (WorldEditException e) { + e.printStackTrace(); + } + } + } + return false; + } + + public boolean regenerate(final Region region) { + return regenerate(region, this); + } + + @Override + public boolean regenerate(final Region region, final EditSession session) { + final FaweQueue queue = session.getQueue(); + queue.setChangeTask(null); + final FaweChangeSet fcs = (FaweChangeSet) session.getChangeSet(); + final FaweRegionExtent fe = session.getRegionExtent(); + session.setSize(1); + final boolean cuboid = region instanceof CuboidRegion; + Set chunks = region.getChunks(); + for (Vector2D chunk : chunks) { + final int cx = chunk.getBlockX(); + final int cz = chunk.getBlockZ(); + final int bx = cx << 4; + final int bz = cz << 4; + Vector cmin = new Vector(bx, 0, bz); + Vector cmax = cmin.add(15, getMaxY(), 15); + final boolean containsBot1 = (fe == null || fe.contains(cmin.getBlockX(), cmin.getBlockY(), cmin.getBlockZ())); + final boolean containsBot2 = region.contains(cmin); + final boolean containsTop1 = (fe == null || fe.contains(cmax.getBlockX(), cmax.getBlockY(), cmax.getBlockZ())); + final boolean containsTop2 = region.contains(cmax); + if ((containsBot2 && containsTop2 && !containsBot1 && !containsTop1)) { + continue; + } + RunnableVal r = new RunnableVal() { + @Override + public void run(Vector2D chunk) { + if (cuboid && containsBot1 && containsBot2 && containsTop1 && containsTop2) { + 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.getCombinedId4DataDebug(xx, y, zz, 0, session); + 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 { + Vector mutable = new Vector(0,0,0); + for (int x = 0; x < 16; x++) { + int xx = x + bx; + mutable.x = xx; + for (int z = 0; z < 16; z++) { + int zz = z + bz; + mutable.z = zz; + for (int y = 0; y < getMaxY() + 1; y++) { + mutable.y = y; + int from = queue.getCombinedId4Data(xx, y, zz); + boolean contains = (fe == null || fe.contains(xx, y, zz)) && region.contains(mutable); + if (contains) { + if (fcs != null) { + if (!FaweCache.hasNBT(from >> 4)) { + fcs.add(xx, y, zz, from, 0); + } else { + try { + BaseBlock block = getLazyBlock(mutable); + fcs.add(mutable, 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); + queue.setBlock(xx, y, zz, id, data); + if (FaweCache.hasNBT(id)) { + BaseBlock block = getBlock(new Vector(xx, y, zz)); + if (block.hasNbtData()) { + queue.setTile(xx, y, zz, block.getNbtData()); + } + } + } + } + } + } + } + queue.regenerateChunk(cx, cz); + } + }; + r.value = chunk; + TaskManager.IMP.sync(r); + } + session.flushQueue(); + return false; + } + + @Override + public void dropItem(Vector position, BaseItemStack item) { + if (getWorld() != null) { + getWorld().dropItem(position, item); + } + } + + public boolean generateTree(TreeGenerator.TreeType type, Vector position) throws MaxChangedBlocksException { + return generateTree(type, this, position); + } + + @Override + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector position) throws MaxChangedBlocksException { + if (getWorld() != null) { + return getWorld().generateTree(type, editSession, position); + } + return false; + } + public static Class inject() { return EditSession.class; } 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 524cfbd9..476b589f 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -32,7 +32,6 @@ import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -353,11 +352,7 @@ public class ClipboardCommands { pos.x += relx; pos.y += rely; pos.z += relz; - try { - editSession.setBlock(pos, block); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } + editSession.setBlockFast(pos, block); } }, !ignoreAirBlocks); } else { diff --git a/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 7f335762..6ac397da 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -99,14 +99,13 @@ public class SelectionCommands { } else { pos = player.getBlockIn(); } - + pos = pos.clampY(0, editSession.getMaximumPoint().getBlockY()); if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos, ActorSelectorLimits.forActor(player))) { BBC.SELECTOR_ALREADY_SET.send(player); return; } - session.getRegionSelector(player.getWorld()) - .explainPrimarySelection(player, session, pos); + session.getRegionSelector(player.getWorld()).explainPrimarySelection(player, session, pos); } @Command( @@ -134,7 +133,7 @@ public class SelectionCommands { } else { pos = player.getBlockIn(); } - + pos = pos.clampY(0, editSession.getMaximumPoint().getBlockY()); if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos, ActorSelectorLimits.forActor(player))) { BBC.SELECTOR_ALREADY_SET.send(player); return; diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index b45b1431..3b8e3330 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -50,18 +50,13 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo WorldVectorFace pos = getTargetFace(player); if (pos == null) return false; EditSession eS = session.createEditSession(player); - try { - if (secondary.getType() == BlockID.AIR) { - eS.setBlock(pos, secondary); - } else { - eS.setBlock(pos.getFaceVector(), secondary); - } - eS.flushQueue(); - return true; - } catch (MaxChangedBlocksException e) { - // one block? eat it + if (secondary.getType() == BlockID.AIR) { + eS.setBlockFast(pos, secondary); + } else { + eS.setBlockFast(pos.getFaceVector(), secondary); } - return false; + eS.flushQueue(); + return true; } @@ -70,18 +65,13 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo WorldVectorFace pos = getTargetFace(player); if (pos == null) return false; EditSession eS = session.createEditSession(player); - try { - if (primary.getType() == BlockID.AIR) { - eS.setBlock(pos, primary); - } else { - eS.setBlock(pos.getFaceVector(), primary); - } - eS.flushQueue(); - return true; - } catch (MaxChangedBlocksException e) { - // one block? eat it + if (primary.getType() == BlockID.AIR) { + eS.setBlockFast(pos, primary); + } else { + eS.setBlockFast(pos.getFaceVector(), primary); } - return false; + eS.flushQueue(); + return true; } public WorldVectorFace getTargetFace(Player player) { diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 777a05ce..927fc7fa 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -66,9 +66,9 @@ public class GravityBrush implements Brush { if (block != EditSession.nullBlock && (mask == null || mask.test(mutablePos))) { if (freeSpot != y) { mutablePos.y = freeSpot; - editSession.setBlock(mutablePos, block); + editSession.setBlockFast(mutablePos, block); mutablePos.y = y; - editSession.setBlock(mutablePos, EditSession.nullBlock); + editSession.setBlockFast(mutablePos, EditSession.nullBlock); } freeSpot++; } diff --git a/core/src/main/java/net/jpountz/lz4/LZ4StreamTest.java b/core/src/main/java/net/jpountz/lz4/LZ4StreamTest.java index 5bc47412..160f8549 100644 --- a/core/src/main/java/net/jpountz/lz4/LZ4StreamTest.java +++ b/core/src/main/java/net/jpountz/lz4/LZ4StreamTest.java @@ -1,7 +1,7 @@ package net.jpountz.lz4; -import com.boydti.fawe.object.io.FastByteArrayInputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream; +import com.boydti.fawe.object.io.FastByteArraysInputStream; import com.boydti.fawe.util.MainUtil; import java.io.IOException; import java.io.InputStream; @@ -19,7 +19,7 @@ public class LZ4StreamTest { private Random rand; private byte randomContent[]; - private byte compressedOutput[]; + private byte compressedOutput[][]; @Before public void setUp() throws IOException { @@ -69,13 +69,13 @@ public class LZ4StreamTest { os.close(); - compressedOutput = compressedOutputStream.toByteArray(); + compressedOutput = compressedOutputStream.toByteArrays(); } @Test public void randomizedTest() throws IOException { try { - InputStream is = new LZ4InputStream(new FastByteArrayInputStream(compressedOutput)); + InputStream is = new LZ4InputStream(new FastByteArraysInputStream(compressedOutput)); int currentContentPosition = 0;