From 36fc147cc2171d2937f68850f79a9d3931526602 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 30 Jul 2017 23:38:55 +1000 Subject: [PATCH] Start work on biome copy (will finish later) --- .../fawe/jnbt/CorruptSchematicStreamer.java | 9 ++ .../boydti/fawe/jnbt/SchematicStreamer.java | 8 ++ .../fawe/object/changeset/FaweChangeSet.java | 30 +++--- .../AbstractDelegateFaweClipboard.java | 31 ++++++ .../clipboard/DiskOptimizedClipboard.java | 101 ++++++++++++++++-- .../fawe/object/clipboard/FaweClipboard.java | 13 +++ .../clipboard/MemoryOptimizedClipboard.java | 46 ++++++++ .../object/clipboard/ReadOnlyClipboard.java | 31 ++++++ .../object/clipboard/WorldCopyClipboard.java | 13 +++ .../object/clipboard/WorldCutClipboard.java | 2 +- .../java/com/boydti/fawe/util/MainUtil.java | 2 +- .../java/com/boydti/fawe/util/Updater.java | 2 +- .../java/com/sk89q/jnbt/NBTInputStream.java | 11 +- .../worldedit/command/ClipboardCommands.java | 28 ++--- .../extent/clipboard/io/SchematicWriter.java | 15 +++ .../function/operation/ForwardExtentCopy.java | 23 ++-- 16 files changed, 319 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/com/boydti/fawe/jnbt/CorruptSchematicStreamer.java b/core/src/main/java/com/boydti/fawe/jnbt/CorruptSchematicStreamer.java index e0b2e35f..bb3bd7b9 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/CorruptSchematicStreamer.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/CorruptSchematicStreamer.java @@ -202,6 +202,15 @@ public class CorruptSchematicStreamer { } } }); + match("Blocks", new CorruptSchematicStreamer.CorruptReader() { + @Override + public void run(DataInputStream in) throws IOException { + int length = in.readInt(); + for (int i = 0; i < length; i++) { + fc.setBiome(i, in.read()); + } + } + }); Vector dimensions = guessDimensions(volume.get(), width.get(), height.get(), length.get()); Vector min = new Vector(originX.get(), originY.get(), originZ.get()); Vector offset = new Vector(offsetX.get(), offsetY.get(), offsetZ.get()); 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 fc1ee1c8..2a1948b3 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/SchematicStreamer.java @@ -60,6 +60,14 @@ public class SchematicStreamer extends NBTStreamer { } } }); + ByteReader biomeReader = new ByteReader() { + @Override + public void run(int index, int value) { + fc.setBiome(index, value); + } + }; + addReader("Schematic.AWEBiomes.#", biomeReader); // AWE stores as an int[] + addReader("Schematic.Biomes.#", biomeReader); // FAWE stores as a byte[] (4x smaller) // Tiles addReader("Schematic.TileEntities.#", new RunnableVal2() { diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java index 62e3f281..8ae7da85 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java @@ -285,15 +285,13 @@ public abstract class FaweChangeSet implements ChangeSet { continue; } int startY = layer << 4; + int index = 0; for (int y = 0; y < 16; y++) { - short[][] i1 = FaweCache.CACHE_J[y]; int yy = y + startY; for (int z = 0; z < 16; z++) { int zz = z + bz; - short[] i2 = i1[z]; - for (int x = 0; x < 16; x++) { + for (int x = 0; x < 16; x++, index++) { int xx = x + bx; - int index = i2[x]; int combinedIdCurrent = currentLayer[index]; switch (combinedIdCurrent) { case 0: @@ -314,26 +312,34 @@ public abstract class FaweChangeSet implements ChangeSet { { // Tiles created Map tiles = next.getTiles(); - for (Map.Entry entry : tiles.entrySet()) { - addTileCreate(entry.getValue()); + if (!tiles.isEmpty()) { + for (Map.Entry entry : tiles.entrySet()) { + addTileCreate(entry.getValue()); + } } // Tiles removed tiles = previous.getTiles(); - for (Map.Entry entry : tiles.entrySet()) { - addTileRemove(entry.getValue()); + if (!tiles.isEmpty()) { + for (Map.Entry entry : tiles.entrySet()) { + addTileRemove(entry.getValue()); + } } } // Entity changes { // Entities created Set entities = next.getEntities(); - for (CompoundTag entityTag : entities) { - addEntityCreate(entityTag); + if (!entities.isEmpty()) { + for (CompoundTag entityTag : entities) { + addEntityCreate(entityTag); + } } // Entities removed entities = previous.getEntities(); - for (CompoundTag entityTag : entities) { - addEntityRemove(entityTag); + if (!entities.isEmpty()) { + for (CompoundTag entityTag : entities) { + addEntityRemove(entityTag); + } } } } 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 25efbad0..74521376 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 @@ -7,6 +7,7 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.List; public class AbstractDelegateFaweClipboard extends FaweClipboard { @@ -26,6 +27,26 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard { return parent.setBlock(x, y, z, block); } + @Override + public boolean hasBiomes() { + return parent.hasBiomes(); + } + + @Override + public boolean setBiome(int x, int z, byte biome) { + return parent.setBiome(x, z, biome); + } + + @Override + public BaseBiome getBiome(int x, int z) { + return parent.getBiome(x, z); + } + + @Override + public BaseBiome getBiome(int index) { + return parent.getBiome(index); + } + @Override public void setId(int index, int id) { parent.setId(index, id); @@ -41,6 +62,11 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard { return parent.getBlock(index); } + @Override + public void setBiome(int index, int biome) { + parent.setBiome(index, biome); + } + @Override public void setAdd(int index, int id) { parent.setAdd(index, id); @@ -96,6 +122,11 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard { parent.forEach(task, air); } + @Override + public void streamBiomes(NBTStreamer.ByteReader task) { + parent.streamBiomes(task); + } + @Override public void streamIds(NBTStreamer.ByteReader task) { parent.streamIds(task); 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 f84f9860..a2b4287c 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 @@ -18,6 +18,7 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -48,6 +49,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { protected int height; protected int width; protected int area; + protected int volume; private final HashMap nbtMap; private final HashSet entities; @@ -58,6 +60,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { private int last; private FileChannel fc; + private boolean hasBiomes; public DiskOptimizedClipboard(int width, int height, int length, UUID uuid) { this(width, height, length, MainUtil.getFile(Fawe.get() != null ? Fawe.imp().getDirectory() : new File("."), Settings.IMP.PATHS.CLIPBOARD + File.separator + uuid + ".bd")); @@ -71,14 +74,18 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { 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) mbb.getChar(); height = (int) mbb.getChar(); length = (int) mbb.getChar(); area = width * length; + this.volume = length * width * height; + + long size = (braf.length() - HEADER_SIZE) >> 1; + if (size == ((long) width * height * length) + area) { + hasBiomes = true; + } autoCloseTask(); } catch (IOException e) { throw new RuntimeException(e); @@ -92,6 +99,69 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } } + private boolean initBiome() { + if (!hasBiomes) { + try { + hasBiomes = true; + if (mbb != null) { + this.mbb.force(); + this.fc.close(); + closeDirectBuffer(mbb); + long volume = (long) length * height * width; + this.braf.setLength(HEADER_SIZE + volume + area); + this.fc = braf.getChannel(); + this.mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, file.length()); + } + } catch (IOException e) { + return false; + } + } + return true; + } + + @Override + public boolean hasBiomes() { + return hasBiomes; + } + + @Override + public boolean setBiome(int x, int z, byte biome) { + setBiome(getIndex(x, 0, z), biome); + return true; + } + + @Override + public void setBiome(int index, int biome) { + if (initBiome()) { + mbb.put(HEADER_SIZE + volume + index, (byte) biome); + } + } + + @Override + public BaseBiome getBiome(int index) { + if (!hasBiomes()) { + return EditSession.nullBiome; + } + int biomeId = mbb.get(HEADER_SIZE + volume + index) & 0xFF; + return FaweCache.CACHE_BIOME[biomeId]; + } + + @Override + public void streamBiomes(NBTStreamer.ByteReader task) { + if (!hasBiomes()) return; + int index = 0; + for (int z = 0; z < length; z++) { + for (int x = 0; x < width; x++, index++) { + task.run(index, getBiome(index).getId()); + } + } + } + + @Override + public BaseBiome getBiome(int x, int z) { + return getBiome(getIndex(x, 0, z)); + } + @Override public Vector getDimensions() { return new Vector(width, height, length); @@ -128,6 +198,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { this.height = height; this.length = length; this.area = width * length; + this.volume = width * length * height; try { if (!file.exists()) { File parent = file.getParentFile(); @@ -177,7 +248,8 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { height = dimensions.getBlockY(); length = dimensions.getBlockZ(); area = width * length; - long size = width * height * length * 2l + HEADER_SIZE; + volume = width * length * height; + long size = width * height * length * 2l + HEADER_SIZE + (hasBiomes() ? area : 0); braf.setLength(size); init(); mbb.position(2); @@ -216,17 +288,24 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { cb = null; } + @Override + protected void finalize() throws Throwable { + close(); + } + @Override public void close() { try { - mbb.force(); - fc.close(); - braf.close(); - file.setWritable(true); - closeDirectBuffer(mbb); - mbb = null; - fc = null; - braf = null; + if (mbb != null) { + mbb.force(); + fc.close(); + braf.close(); + file.setWritable(true); + closeDirectBuffer(mbb); + mbb = null; + fc = null; + braf = null; + } } catch (IOException 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 5e3fe345..f701024f 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 @@ -11,6 +11,7 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -24,8 +25,18 @@ public abstract class FaweClipboard { public abstract boolean setBlock(int x, int y, int z, BaseBlock block); + public abstract boolean hasBiomes(); + + public abstract boolean setBiome(int x, int z, byte biome); + + public abstract BaseBiome getBiome(int x, int z); + + public abstract BaseBiome getBiome(int index); + public abstract BaseBlock getBlock(int index); + public abstract void setBiome(int index, int biome); + public abstract void setId(int index, int id); public abstract void setData(int index, int data); @@ -59,6 +70,8 @@ public abstract class FaweClipboard { public abstract void run(int x, int y, int z, BaseBlock block); } + public abstract void streamBiomes(final NBTStreamer.ByteReader task); + public void streamIds(final NBTStreamer.ByteReader task) { forEach(new BlockReader() { private int index = 0; diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java index dd522296..08208575 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java @@ -9,11 +9,13 @@ import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -37,6 +39,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard { private byte[][] add; private byte[] buffer = new byte[MainUtil.getMaxCompressedLength(BLOCK_SIZE)]; + private byte[] biomes = null; private final HashMap nbtMapLoc; private final HashMap nbtMapIndex; @@ -86,6 +89,49 @@ public class MemoryOptimizedClipboard extends FaweClipboard { nbtMapLoc.clear(); } + @Override + public boolean hasBiomes() { + return biomes != null; + } + + @Override + public boolean setBiome(int x, int z, byte biome) { + setBiome(getIndex(x, 0, z), biome); + return true; + } + + @Override + public void setBiome(int index, int biome) { + if (biomes == null) { + biomes = new byte[area]; + } + biomes[index] = (byte) biome; + } + + @Override + public void streamBiomes(NBTStreamer.ByteReader task) { + if (!hasBiomes()) return; + int index = 0; + for (int z = 0; z < length; z++) { + for (int x = 0; x < width; x++, index++) { + task.run(index, biomes[index] & 0xFF); + } + } + } + + @Override + public BaseBiome getBiome(int index) { + if (!hasBiomes()) { + return EditSession.nullBiome; + } + return FaweCache.CACHE_BIOME[biomes[index] & 0xFF]; + } + + @Override + public BaseBiome getBiome(int x, int z) { + return getBiome(getIndex(x, 0, z)); + } + private CompoundTag getTag(int index) { convertTilesToIndex(); return nbtMapIndex.get(index); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java index 9db2d05f..c463f897 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.clipboard; +import com.boydti.fawe.jnbt.NBTStreamer; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; @@ -8,6 +9,7 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.List; public abstract class ReadOnlyClipboard extends FaweClipboard { @@ -40,9 +42,38 @@ public abstract class ReadOnlyClipboard extends FaweClipboard { throw new UnsupportedOperationException("World based clipboards do not provide index access"); } + @Override + public BaseBiome getBiome(int index) { + throw new UnsupportedOperationException("World based clipboards do not provide index access"); + } + + @Override + public boolean setBiome(int x, int z, byte biome) { + throw new UnsupportedOperationException("Clipboard is immutable"); + } + + @Override + public void setBiome(int index, int biome) { + throw new UnsupportedOperationException("Clipboard is immutable"); + } + + @Override + public void streamBiomes(NBTStreamer.ByteReader task) { + Vector dim = getDimensions(); + int index = 0; + for (int z = 0; z <= dim.getBlockZ(); z++) { + for (int x = 0; x <= dim.getBlockX(); x++, index++) { + task.run(index, getBiome(x, z).getId()); + } + } + } + @Override public abstract BaseBlock getBlock(int x, int y, int z); + @Override + public abstract BaseBiome getBiome(int x, int z); + @Override public abstract List getEntities(); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java index 99df9297..40776f87 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCopyClipboard.java @@ -5,6 +5,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MutableBlockVector2D; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; @@ -14,12 +15,14 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.List; import java.util.Map; public class WorldCopyClipboard extends ReadOnlyClipboard { public final int mx, my, mz; + private MutableBlockVector2D mutableBlockVector2D = new MutableBlockVector2D(); public final EditSession editSession; public WorldCopyClipboard(EditSession editSession, Region region) { @@ -40,11 +43,21 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { return editSession.getLazyBlock(x, y, z); } + @Override + public BaseBiome getBiome(int x, int z) { + return editSession.getBiome(mutableBlockVector2D.setComponents(mx + x, mz + z)); + } + @Override public List getEntities() { return editSession.getEntities(getRegion()); } + @Override + public boolean hasBiomes() { + return true; + } + @Override public void forEach(BlockReader task, boolean air) { Vector min = region.getMinimumPoint(); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java index 90f451f5..985fde29 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/WorldCutClipboard.java @@ -30,4 +30,4 @@ public class WorldCutClipboard extends WorldCopyClipboard { super.forEach(task, air); editSession.flushQueue(); } -} +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/util/MainUtil.java b/core/src/main/java/com/boydti/fawe/util/MainUtil.java index f72481de..8c01c16e 100644 --- a/core/src/main/java/com/boydti/fawe/util/MainUtil.java +++ b/core/src/main/java/com/boydti/fawe/util/MainUtil.java @@ -325,7 +325,6 @@ public class MainUtil { if (amount == 0) { return new FaweOutputStream(os); } - os = new BufferedOutputStream(os, buffer); int gzipAmount = amount > 6 ? 1 : 0; for (int i = 0; i < gzipAmount; i++) { os = new ZstdOutputStream(os, 22); @@ -343,6 +342,7 @@ public class MainUtil { os = new LZ4BlockOutputStream(os, buffer, factory.highCompressor()); } } + os = new BufferedOutputStream(os, buffer); return new FaweOutputStream(os); } diff --git a/core/src/main/java/com/boydti/fawe/util/Updater.java b/core/src/main/java/com/boydti/fawe/util/Updater.java index d9a27abe..44467542 100644 --- a/core/src/main/java/com/boydti/fawe/util/Updater.java +++ b/core/src/main/java/com/boydti/fawe/util/Updater.java @@ -35,7 +35,7 @@ public class Updater { return; } try { - String downloadUrl = "http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target/FastAsyncWorldEdit-%platform%-%version%.jar"; + String downloadUrl = "https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target/FastAsyncWorldEdit-%platform%-%version%.jar"; String versionUrl = "http://empcraft.com/fawe/version.php?%platform%"; URL url = new URL(versionUrl.replace("%platform%", platform)); try (Scanner reader = new Scanner(url.openStream())) { diff --git a/core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index 122c01b9..efa55be9 100644 --- a/core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -246,8 +246,15 @@ public final class NBTInputStream implements Closeable { is.skipBytes(length << 2); return; } - for (int i = 0; i < length; i++) { - reader.run(i, is.readInt()); + if (reader instanceof NBTStreamer.ByteReader) { + NBTStreamer.ByteReader byteReader = (NBTStreamer.ByteReader) reader; + for (int i = 0; i < length; i++) { + byteReader.run(i, is.readInt()); + } + } else { + for (int i = 0; i < length; i++) { + reader.run(i, is.readInt()); + } } return; default: 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 baf0be91..d18ee8b9 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -92,15 +92,16 @@ public class ClipboardCommands extends MethodCommands { desc = "Lazily copy the selection to the clipboard", help = "Lazily copy the selection to the clipboard\n" + "Flags:\n" + - " -e controls whether entities are copied\n" + + " -e skips copying entities\n" + " -m sets a source mask so that excluded blocks become air\n" + + " -b copies biomes\n" + "WARNING: Pasting entities cannot yet be undone!", max = 0 ) @CommandPermissions("worldedit.clipboard.lazycopy") public void lazyCopy(Player player, LocalSession session, EditSession editSession, - @Selection final Region region, @Switch('e') boolean copyEntities, - @Switch('m') Mask mask) throws WorldEditException { + @Selection final Region region, @Switch('e') boolean skipEntities, + @Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException { Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1)); @@ -113,7 +114,7 @@ public class ClipboardCommands extends MethodCommands { final int mx = origin.getBlockX(); final int my = origin.getBlockY(); final int mz = origin.getBlockZ(); - ReadOnlyClipboard lazyClipboard = ReadOnlyClipboard.of(editSession, region); + ReadOnlyClipboard lazyClipboard = ReadOnlyClipboard.of(editSession, region, !skipEntities, copyBiomes); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard); clipboard.setOrigin(session.getPlacementPosition(player)); @@ -130,16 +131,17 @@ public class ClipboardCommands extends MethodCommands { desc = "Copy the selection to the clipboard", help = "Copy the selection to the clipboard\n" + "Flags:\n" + - " -e controls whether entities are copied\n" + + " -e skips copying entities\n" + " -m sets a source mask so that excluded blocks become air\n" + + " -b copies biomes\n" + "WARNING: Pasting entities cannot yet be undone!", min = 0, max = 0 ) @CommandPermissions("worldedit.clipboard.copy") public void copy(FawePlayer fp, Player player, LocalSession session, EditSession editSession, - @Selection Region region, @Switch('e') boolean copyEntities, - @Switch('m') Mask mask, CommandContext context) throws WorldEditException { + @Selection Region region, @Switch('e') boolean skipEntities, + @Switch('m') Mask mask, CommandContext context, @Switch('b') boolean copyBiomes) throws WorldEditException { fp.checkConfirmationRegion(getArguments(context), region); Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); @@ -154,6 +156,7 @@ public class ClipboardCommands extends MethodCommands { clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); + copy.setCopyEntities(!skipEntities); Mask sourceMask = editSession.getSourceMask(); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(editSession); @@ -175,14 +178,14 @@ public class ClipboardCommands extends MethodCommands { desc = "Lazily cut the selection to the clipboard", help = "Lazily cut the selection to the clipboard\n" + "Flags:\n" + - " -e controls whether entities are cut\n" + + " -e skips entity copy\n" + " -m sets a source mask so that excluded blocks become air\n" + "WARNING: Pasting entities cannot yet be undone!", max = 0 ) @CommandPermissions("worldedit.clipboard.lazycut") public void lazyCut(Player player, LocalSession session, EditSession editSession, - @Selection final Region region, @Switch('e') boolean copyEntities, + @Selection final Region region, @Switch('e') boolean skipEntities, @Switch('m') Mask mask) throws WorldEditException { Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); @@ -199,7 +202,7 @@ public class ClipboardCommands extends MethodCommands { final int mx = origin.getBlockX(); final int my = origin.getBlockY(); final int mz = origin.getBlockZ(); - ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region); + ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region, skipEntities); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard); clipboard.setOrigin(session.getPlacementPosition(player)); session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorldData())); @@ -213,7 +216,7 @@ public class ClipboardCommands extends MethodCommands { desc = "Cut the selection to the clipboard", help = "Copy the selection to the clipboard\n" + "Flags:\n" + - " -e controls whether entities are copied\n" + + " -e skips entity copy\n" + " -m sets a source mask so that excluded blocks become air\n" + "WARNING: Cutting and pasting entities cannot yet be undone!", min = 0, @@ -222,7 +225,7 @@ public class ClipboardCommands extends MethodCommands { @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) public void cut(FawePlayer fp, Player player, LocalSession session, EditSession editSession, - @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities, + @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean skipEntities, @Switch('m') Mask mask, CommandContext context) throws WorldEditException { fp.checkConfirmationRegion(getArguments(context), region); Vector min = region.getMinimumPoint(); @@ -240,6 +243,7 @@ public class ClipboardCommands extends MethodCommands { clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); + copy.setCopyEntities(!skipEntities); Mask sourceMask = editSession.getSourceMask(); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(editSession); diff --git a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java index fd19b5d1..2785ffc9 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java @@ -155,6 +155,21 @@ public class SchematicWriter implements ClipboardWriter { out.writeNamedTag("WEOffsetZ", (offset.getBlockZ())); out.writeNamedTag("Platform", Fawe.imp().getPlatform()); + if (clipboard.IMP.hasBiomes()) { + out.writeNamedTagName("Biomes", NBTConstants.TYPE_BYTE_ARRAY); + out.getOutputStream().writeInt(width * length); // area + clipboard.IMP.streamBiomes(new NBTStreamer.ByteReader() { + @Override + public void run(int index, int byteValue) { + try { + rawStream.writeByte(byteValue); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } + out.writeNamedTagName("Blocks", NBTConstants.TYPE_BYTE_ARRAY); out.getOutputStream().writeInt(volume); clipboard.IMP.streamIds(new NBTStreamer.ByteReader() { diff --git a/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java index 02b0e658..efe68c80 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java +++ b/core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -40,6 +40,7 @@ import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.Region; +import java.util.ArrayList; import java.util.List; @@ -67,6 +68,7 @@ public class ForwardExtentCopy implements Operation { private Transform transform = new Identity(); private Transform currentTransform = null; private int affected; + private boolean copyEntities = true; /** * Create a new copy using the region's lowest minimum point as the @@ -137,6 +139,14 @@ public class ForwardExtentCopy implements Operation { return sourceMask; } + public void setCopyEntities(boolean copyEntities) { + this.copyEntities = copyEntities; + } + + public boolean isCopyEntities() { + return copyEntities; + } + /** * Set a mask that gets applied to the source extent. * @@ -249,16 +259,17 @@ public class ForwardExtentCopy implements Operation { } RegionVisitor blockVisitor = new RegionVisitor(region, copy, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null); - List entities = source.getEntities(region); + List entities = isCopyEntities() ? source.getEntities(region) : new ArrayList<>(); for (int i = 0; i < repetitions; i++) { Operations.completeBlindly(blockVisitor); - ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform); - entityCopy.setRemoving(removingEntities); - EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); - - Operations.completeBlindly(entityVisitor); + if (!entities.isEmpty()) { + ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform); + entityCopy.setRemoving(removingEntities); + EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); + Operations.completeBlindly(entityVisitor); + } if (transExt != null) { currentTransform = currentTransform.combine(transform);