diff --git a/build.gradle b/build.gradle index 370e89d8..9f0b2eed 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ ext { date = git.head().date.format("yy.MM.dd") revision = "-${git.head().abbreviatedId}" parents = git.head().parentIds; - index = -91; // Offset to mach CI + index = -92; // Offset to mach CI int major, minor, patch; major = minor = patch = 0; for (;parents != null && !parents.isEmpty();index++) { diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 328bcb6b..fe39a454 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -105,6 +105,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.EllipsoidRegion; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.shape.ArbitraryShape; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.PasteBuilder; import com.sk89q.worldedit.session.SessionManager; import com.sk89q.worldedit.session.request.Request; @@ -460,6 +461,7 @@ public class Fawe { // Clipboards BlockArrayClipboard.inject(); // Optimizations + disk CuboidClipboard.inject(); // Optimizations + ClipboardHolder.inject(); // Closeable // Regions CuboidRegion.inject(); // Optimizations // Extents diff --git a/core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java b/core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java index 830bd8bd..345278a6 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java @@ -39,19 +39,19 @@ public class SchematicStreamer extends NBTStreamer { addReader("Schematic.Blocks.#", new ByteReader() { @Override public void run(int index, int value) { - fc.setId(index, value); + if (value != 0) fc.setId(index, value); } }); addReader("Schematic.Data.#", new ByteReader() { @Override public void run(int index, int value) { - fc.setData(index, value); + if (value != 0) fc.setData(index, value); } }); addReader("Schematic.AddBlocks.#", new ByteReader() { @Override public void run(int index, int value) { - fc.setAdd(index, value); + if (value != 0) fc.setAdd(index, value); } }); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java index 0a75693b..d8d22772 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/AbstractDelegateFaweClipboard.java @@ -71,6 +71,16 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard { parent.setDimensions(dimensions); } + @Override + public void flush() { + parent.flush(); + } + + @Override + public void close() { + parent.close(); + } + @Override public Vector getDimensions() { return parent.getDimensions(); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java index e87df98c..03013d52 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java @@ -5,7 +5,6 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.Settings; import com.boydti.fawe.jnbt.NBTStreamer; import com.boydti.fawe.object.IntegerTrio; -import com.boydti.fawe.object.io.BufferedRandomAccessFile; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; @@ -22,6 +21,11 @@ import com.sk89q.worldedit.regions.CuboidRegion; import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -50,8 +54,11 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { private final HashSet entities; private final File file; - private final BufferedRandomAccessFile raf; + private RandomAccessFile braf; + private MappedByteBuffer mbb; + private int last; + private FileChannel fc; public DiskOptimizedClipboard(int width, int height, int length, UUID uuid) { this(width, height, length, MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.CLIPBOARD + File.separator + uuid + ".bd")); @@ -62,14 +69,16 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { nbtMap = new HashMap<>(); entities = new HashSet<>(); this.file = file; - this.raf = new BufferedRandomAccessFile(file, "rw", 16); - raf.setLength(file.length()); - long size = (raf.length() - HEADER_SIZE) >> 1; - raf.seek(2); + this.braf = new RandomAccessFile(file, "rw"); + braf.setLength(file.length()); + init(); + long size = (braf.length() - HEADER_SIZE) >> 1; + + mbb.position(2); last = Integer.MIN_VALUE; - width = (int) raf.readChar(); - height = (int) raf.readChar(); - length = (int) raf.readChar(); + width = (int) mbb.getChar(); + height = (int) mbb.getChar(); + length = (int) mbb.getChar(); area = width * length; autoCloseTask(); } catch (IOException e) { @@ -77,6 +86,13 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } } + private void init() throws IOException { + if (this.fc == null) { + this.fc = braf.getChannel(); + this.mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, file.length()); + } + } + @Override public Vector getDimensions() { return new Vector(width, height, length); @@ -90,15 +106,15 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { return true; } }; - raf.seek(8); + mbb.position(8); last = Integer.MIN_VALUE; - int ox = raf.readShort(); - int oy = raf.readShort(); - int oz = raf.readShort(); + int ox = mbb.getShort(); + int oy = mbb.getShort(); + int oz = mbb.getShort(); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, this); clipboard.setOrigin(new Vector(ox, oy, oz)); return clipboard; - } catch (IOException e) { + } catch (Throwable e) { MainUtil.handleError(e); } return null; @@ -115,22 +131,26 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { this.area = width * length; try { if (!file.exists()) { - file.getParentFile().mkdirs(); + File parent = file.getParentFile(); + if (parent != null) { + file.getParentFile().mkdirs(); + } file.createNewFile(); } } catch (Exception e) { MainUtil.handleError(e); } - this.raf = new BufferedRandomAccessFile(file, "rw", 16); + this.braf = new RandomAccessFile(file, "rw"); long volume = (long) width * (long) height * (long) length * 2l + (long) HEADER_SIZE; - raf.setLength(0); - raf.setLength(volume); + braf.setLength(0); + braf.setLength(volume); + init(); // write length etc - raf.seek(2); + mbb.position(2); last = Integer.MIN_VALUE; - raf.writeChar(width); - raf.writeChar(height); - raf.writeChar(length); + mbb.putChar((char) width); + mbb.putChar((char) height); + mbb.putChar((char) length); } catch (IOException e) { throw new RuntimeException(e); } @@ -139,12 +159,12 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setOrigin(Vector offset) { try { - raf.seek(8); + mbb.position(8); last = Integer.MIN_VALUE; - raf.writeShort(offset.getBlockX()); - raf.writeShort(offset.getBlockY()); - raf.writeShort(offset.getBlockZ()); - } catch (IOException e) { + mbb.putShort((short) offset.getBlockX()); + mbb.putShort((short) offset.getBlockY()); + mbb.putShort((short) offset.getBlockZ()); + } catch (Throwable e) { MainUtil.handleError(e); } } @@ -157,34 +177,51 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { length = dimensions.getBlockZ(); area = width * length; long size = width * height * length * 2l + HEADER_SIZE; - raf.setLength(size); - raf.seek(2); + braf.setLength(size); + init(); + mbb.position(2); last = Integer.MIN_VALUE; - raf.writeChar(width); - raf.writeChar(height); - raf.writeChar(length); + mbb.putChar((char) width); + mbb.putChar((char) height); + mbb.putChar((char) length); } catch (IOException e) { MainUtil.handleError(e); } } + @Override public void flush() { - try { - raf.flush(); - } catch (IOException e) { - MainUtil.handleError(e); - } + mbb.force(); } public DiskOptimizedClipboard(int width, int height, int length) { this(width, height, length, MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.CLIPBOARD + File.separator + UUID.randomUUID() + ".bd")); } + private void closeDirectBuffer(ByteBuffer cb) { + if (cb==null || !cb.isDirect()) return; + + // we could use this type cast and call functions without reflection code, + // but static import from sun.* package is risky for non-SUN virtual machine. + //try { ((sun.nio.ch.DirectBuffer)cb).cleaner().clean(); } catch (Exception ex) { } + try { + Method cleaner = cb.getClass().getMethod("cleaner"); + cleaner.setAccessible(true); + Method clean = Class.forName("sun.misc.Cleaner").getMethod("clean"); + clean.setAccessible(true); + clean.invoke(cleaner.invoke(cb)); + } catch(Exception ex) { } + cb = null; + } + + @Override public void close() { try { - raf.close(); + mbb.force(); + fc.close(); + braf.close(); file.setWritable(true); - System.gc(); + closeDirectBuffer(mbb); } catch (IOException e) { MainUtil.handleError(e); } @@ -213,37 +250,37 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void streamIds(NBTStreamer.ByteReader task) { try { - raf.seek(HEADER_SIZE); + mbb.force(); + mbb.position(HEADER_SIZE); int index = 0; for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++) { - int combinedId = raf.readChar(); + int combinedId = mbb.getChar(); task.run(index++, FaweCache.getId(combinedId)); } } } - } catch (IOException e) { + } catch (Throwable e) { MainUtil.handleError(e); } } - public static long start; - @Override public void streamDatas(NBTStreamer.ByteReader task) { try { - raf.seek(HEADER_SIZE); + mbb.force(); + mbb.position(HEADER_SIZE); int index = 0; for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++) { - int combinedId = raf.readChar(); + int combinedId = mbb.getChar(); task.run(index++, FaweCache.getData(combinedId)); } } } - } catch (IOException e) { + } catch (Throwable e) { MainUtil.handleError(e); } } @@ -256,7 +293,8 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void forEach(final BlockReader task, boolean air) { try { - raf.seek(HEADER_SIZE); + mbb.force(); + mbb.position(HEADER_SIZE); IntegerTrio trio = new IntegerTrio(); final boolean hasTile = !nbtMap.isEmpty(); if (air) { @@ -264,7 +302,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++) { - char combinedId = raf.readChar(); + char combinedId = mbb.getChar(); BaseBlock block = FaweCache.CACHE_BLOCK[combinedId]; if (block.canStoreNBTData()) { trio.set(x, y, z); @@ -282,7 +320,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++) { - char combinedId = raf.readChar(); + char combinedId = mbb.getChar(); BaseBlock block = FaweCache.CACHE_BLOCK[combinedId]; task.run(x, y, z, block); } @@ -293,7 +331,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { for (int y = 0; y < height; y++) { for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++) { - int combinedId = raf.readChar(); + int combinedId = mbb.getChar(); if (combinedId != 0) { BaseBlock block = FaweCache.CACHE_BLOCK[combinedId]; if (block.canStoreNBTData()) { @@ -310,7 +348,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } } } - } catch (IOException e) { + } catch (Throwable e) { MainUtil.handleError(e); } } @@ -324,10 +362,10 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { try { int i = getIndex(x, y, z); if (i != last + 1) { - raf.seek((HEADER_SIZE) + (i << 1)); + mbb.position((HEADER_SIZE) + (i << 1)); } last = i; - int combinedId = raf.readChar(); + int combinedId = mbb.getChar(); BaseBlock block = FaweCache.CACHE_BLOCK[combinedId]; if (block.canStoreNBTData()) { CompoundTag nbt = nbtMap.get(new IntegerTrio(x, y, z)); @@ -358,13 +396,13 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { try { int i = x + ((ylast == y) ? ylasti : (ylasti = ((ylast = y)) * area)) + ((zlast == z) ? zlasti : (zlasti = (zlast = z) * width)); if (i != last + 1) { - raf.seek((HEADER_SIZE) + (i << 1)); + mbb.position((HEADER_SIZE) + (i << 1)); } last = i; final int id = block.getId(); final int data = block.getData(); int combined = (id << 4) + data; - raf.writeChar(combined); + mbb.putChar((char) combined); CompoundTag tile = block.getNbtData(); if (tile != null) { setTile(x, y, z, tile); @@ -379,16 +417,20 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setId(int i, int id) { try { + int index; if (i != last + 1) { - raf.seek((HEADER_SIZE) + (i << 1)); + index = (HEADER_SIZE) + (i << 1); + } else { + index = mbb.position(); } last = i; + mbb.position(index + 1); // 00000000 00000000 // [ id ]data - int id1 = raf.readCurrent(); - raf.writeUnsafe(id >> 4); - int id2 = raf.readCurrent(); - raf.writeUnsafe(((id & 0xFF) << 4) + (id2 & 0xFF)); + byte id2 = mbb.get(); + mbb.position(index); + mbb.put((byte) (id >> 4)); + mbb.put((byte) (((id & 0xFF) << 4) + (id2 & 0xFF))); } catch (Exception e) { MainUtil.handleError(e); } @@ -397,10 +439,10 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { public void setCombined(int i, int combined) { try { if (i != last + 1) { - raf.seek((HEADER_SIZE) + (i << 1)); + mbb.position((HEADER_SIZE) + (i << 1)); } last = i; - raf.writeChar(combined); + mbb.putChar((char) combined); } catch (Exception e) { MainUtil.handleError(e); } @@ -409,15 +451,14 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setAdd(int i, int add) { try { - if (i != last + 1) { - raf.seek((HEADER_SIZE) + (i << 1)); - } last = i; + int index = (HEADER_SIZE) + (i << 1); + mbb.position(index); // 00000000 00000000 // [ id ]data - int id = (raf.readCurrent() & 0xFF); - raf.writeUnsafe(id + (add >> 4)); - raf.read1(); + char combined = mbb.getChar(); + mbb.position(index); + mbb.putChar((char) ((combined & 0xFFFF) + (add << 12))); } catch (Exception e) { MainUtil.handleError(e); } @@ -426,17 +467,17 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setData(int i, int data) { try { + int index; if (i != last + 1) { - raf.seek((HEADER_SIZE) + (i << 1) + 1); + index = (HEADER_SIZE) + (i << 1) + 1; } else { - raf.seek(raf.getFilePointer() + 1); + index = mbb.position() + 1; } + mbb.position(index); last = i; - // 00000000 00000000 - // [ id ]data -// int skip = raf.read1(); - int id2 = raf.readCurrent(); - raf.writeUnsafe((id2 & 0xF0) + data); + byte id = mbb.get(); + mbb.position(index); + mbb.put((byte) ((id & 0xF0) + data)); } catch (Exception e) { MainUtil.handleError(e); } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java index df5aafa9..68be9980 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java @@ -94,6 +94,10 @@ public abstract class FaweClipboard { return tiles; } + public void close() {} + + public void flush() {} + /** * Stores entity data. */ diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java b/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java index ce50b64e..69ff9de6 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/MultiClipboardHolder.java @@ -34,4 +34,11 @@ public class MultiClipboardHolder extends ClipboardHolder{ public void setTransform(Transform transform) { holder.setTransform(transform); } + + @Override + public void close() { + for (ClipboardHolder holder : holders) { + if (holder != null) holder.close(); + } + } } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/RandomClipboardHolder.java b/core/src/main/java/com/boydti/fawe/object/clipboard/RandomClipboardHolder.java deleted file mode 100644 index 120b7314..00000000 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/RandomClipboardHolder.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.boydti.fawe.object.clipboard; - -import com.google.common.io.ByteSource; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.world.registry.WorldData; -import java.util.UUID; - -public class RandomClipboardHolder extends LazyClipboardHolder { - public RandomClipboardHolder(ByteSource source, ClipboardFormat format, WorldData worldData, UUID uuid) { - super(source, format, worldData, uuid); - } -} diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index 25e262af..5e4a1e23 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -28,7 +28,6 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; -import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; import com.boydti.fawe.object.extent.ResettableExtent; import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.MainUtil; @@ -45,8 +44,6 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; @@ -794,14 +791,8 @@ public class LocalSession { * @param clipboard the clipboard, or null if the clipboard is to be cleared */ public void setClipboard(@Nullable ClipboardHolder clipboard) { - if (this.clipboard != null && clipboard != null) { - Clipboard clip = clipboard.getClipboard(); - if (clip instanceof BlockArrayClipboard) { - BlockArrayClipboard bac = (BlockArrayClipboard) clip; - if (bac.IMP instanceof DiskOptimizedClipboard) { - ((DiskOptimizedClipboard) bac.IMP).flush(); - } - } + if (this.clipboard != null) { + this.clipboard.close(); } this.clipboard = clipboard; } 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 956405ee..b7fd8ce4 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -112,6 +112,7 @@ public class ClipboardCommands { if (volume >= limit.MAX_CHECKS) { throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); } + session.setClipboard(null); final Vector origin = region.getMinimumPoint(); final int mx = origin.getBlockX(); final int my = origin.getBlockY(); @@ -149,7 +150,7 @@ public class ClipboardCommands { if (volume >= limit.MAX_CHECKS) { throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS); } - + session.setClipboard(null); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId()); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); @@ -193,6 +194,7 @@ public class ClipboardCommands { if (volume >= limit.MAX_CHANGES) { throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); } + session.setClipboard(null); final Vector origin = region.getMinimumPoint(); final int mx = origin.getBlockX(); final int my = origin.getBlockY(); @@ -232,6 +234,7 @@ public class ClipboardCommands { if (volume >= limit.MAX_CHANGES) { throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES); } + session.setClipboard(null); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId()); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); diff --git a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 86b55d80..66505630 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -103,6 +103,7 @@ public class SchematicCommands { } try { WorldData wd = player.getWorld().getWorldData(); + session.setClipboard(null); ClipboardHolder[] all = format.loadAllFromInput(player, wd, filename, true); if (all != null) { MultiClipboardHolder multi = new MultiClipboardHolder(wd, all); @@ -177,6 +178,7 @@ public class SchematicCommands { final ClipboardReader reader = format.getReader(in); final WorldData worldData = player.getWorld().getWorldData(); final Clipboard clipboard; + session.setClipboard(null); if (reader instanceof SchematicReader) { clipboard = ((SchematicReader) reader).read(player.getWorld().getWorldData(), player.getUniqueId()); } else if (reader instanceof StructureFormat) { diff --git a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index ca6071c2..6aa3ffdc 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -115,6 +115,10 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent { this.mz = origin.getBlockZ(); } + public void close() { + IMP.close(); + } + @Override public Region getRegion() { return region.clone(); diff --git a/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java b/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java new file mode 100644 index 00000000..fa904787 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/session/ClipboardHolder.java @@ -0,0 +1,112 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.session; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.transform.Identity; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.registry.WorldData; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Holds the clipboard and the current transform on the clipboard. + */ +public class ClipboardHolder { + + private final WorldData worldData; + private final Clipboard clipboard; + private Transform transform = new Identity(); + + /** + * Create a new instance with the given clipboard. + * + * @param clipboard the clipboard + * @param worldData the mapping of blocks, entities, and so on + */ + public ClipboardHolder(Clipboard clipboard, WorldData worldData) { + checkNotNull(clipboard); + checkNotNull(worldData); + this.clipboard = clipboard; + this.worldData = worldData; + } + + /** + * Get the mapping used for blocks, entities, and so on. + * + * @return the mapping + */ + public WorldData getWorldData() { + return worldData; + } + + /** + * Get the clipboard. + *

+ * If there is a transformation applied, the returned clipboard will + * not contain its effect. + * + * @return the clipboard + */ + public Clipboard getClipboard() { + return clipboard; + } + + /** + * Set the transform. + * + * @param transform the transform + */ + public void setTransform(Transform transform) { + checkNotNull(transform); + this.transform = transform; + } + + /** + * Get the transform. + * + * @return the transform + */ + public Transform getTransform() { + return transform; + } + + /** + * Create a builder for an operation to paste this clipboard. + * + * @return a builder + */ + public PasteBuilder createPaste(Extent targetExtent, WorldData targetWorldData) { + return new PasteBuilder(this, targetExtent, targetWorldData); + } + + public void close() { + if (clipboard instanceof BlockArrayClipboard) { + ((BlockArrayClipboard) clipboard).close(); + } + } + + public static Class inject() { + return ClipboardHolder.class; + } + +} diff --git a/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index 76766dc5..51b63022 100644 --- a/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -221,6 +221,7 @@ public class SessionManager { private void save(SessionHolder holder) { SessionKey key = holder.key; + holder.session.setClipboard(null); if (key.isPersistent()) { try { if (holder.session.compareAndResetDirty()) {