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 74521376..5c0f7e60 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 @@ -33,7 +33,7 @@ public class AbstractDelegateFaweClipboard extends FaweClipboard { } @Override - public boolean setBiome(int x, int z, byte biome) { + public boolean setBiome(int x, int z, int biome) { return parent.setBiome(x, z, biome); } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java index 163d7c9c..c0f6ef81 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java @@ -7,11 +7,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; @@ -24,6 +26,8 @@ public class CPUOptimizedClipboard extends FaweClipboard { private int width; private int area; private int volume; + + private byte[] biomes = null; private byte[] ids; private byte[] datas; private byte[] add; @@ -46,6 +50,48 @@ public class CPUOptimizedClipboard extends FaweClipboard { entities = new HashSet<>(); } + @Override + public boolean hasBiomes() { + return biomes != null; + } + + @Override + public boolean setBiome(int x, int z, int 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)); + } public void convertTilesToIndex() { if (nbtMapLoc.isEmpty()) { 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 a2b4287c..633e84ac 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 @@ -82,8 +82,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { area = width * length; this.volume = length * width * height; - long size = (braf.length() - HEADER_SIZE) >> 1; - if (size == ((long) width * height * length) + area) { + if ((braf.length() - HEADER_SIZE) == (volume << 1) + area) { hasBiomes = true; } autoCloseTask(); @@ -103,16 +102,12 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { 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()); - } + close(); + this.braf = new RandomAccessFile(file, "rw"); + this.braf.setLength(HEADER_SIZE + (volume << 1) + area); + init(); } catch (IOException e) { + e.printStackTrace(); return false; } } @@ -125,7 +120,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } @Override - public boolean setBiome(int x, int z, byte biome) { + public boolean setBiome(int x, int z, int biome) { setBiome(getIndex(x, 0, z), biome); return true; } @@ -133,7 +128,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { @Override public void setBiome(int index, int biome) { if (initBiome()) { - mbb.put(HEADER_SIZE + volume + index, (byte) biome); + mbb.put(HEADER_SIZE + (volume << 1) + index, (byte) biome); } } @@ -142,7 +137,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { if (!hasBiomes()) { return EditSession.nullBiome; } - int biomeId = mbb.get(HEADER_SIZE + volume + index) & 0xFF; + int biomeId = mbb.get(HEADER_SIZE + (volume << 1) + index) & 0xFF; return FaweCache.CACHE_BIOME[biomeId]; } @@ -150,9 +145,11 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { public void streamBiomes(NBTStreamer.ByteReader task) { if (!hasBiomes()) return; int index = 0; + int offset = HEADER_SIZE + (volume << 1); for (int z = 0; z < length; z++) { for (int x = 0; x < width; x++, index++) { - task.run(index, getBiome(index).getId()); + int biome = mbb.get(offset + index) & 0xFF; + task.run(index, biome); } } } @@ -268,7 +265,7 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable { } 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")); + this(width, height, length, MainUtil.getFile(Fawe.imp() != null ? Fawe.imp().getDirectory() : new File("."), Settings.IMP.PATHS.CLIPBOARD + File.separator + UUID.randomUUID() + ".bd")); } private void closeDirectBuffer(ByteBuffer cb) { 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 f701024f..fe865f8a 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 @@ -27,7 +27,7 @@ public abstract class FaweClipboard { public abstract boolean hasBiomes(); - public abstract boolean setBiome(int x, int z, byte biome); + public abstract boolean setBiome(int x, int z, int biome); public abstract BaseBiome getBiome(int x, int z); 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 08208575..b486810c 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 @@ -95,7 +95,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard { } @Override - public boolean setBiome(int x, int z, byte biome) { + public boolean setBiome(int x, int z, int biome) { setBiome(getIndex(x, 0, z), biome); return true; } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java index 3ccc5238..5941e5ef 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/OffsetFaweClipboard.java @@ -2,6 +2,7 @@ package com.boydti.fawe.object.clipboard; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.world.biome.BaseBiome; public class OffsetFaweClipboard extends AbstractDelegateFaweClipboard { private final int ox, oy, oz; @@ -27,6 +28,16 @@ public class OffsetFaweClipboard extends AbstractDelegateFaweClipboard { return super.setBlock(ox + x, oy + y, oz + z, block); } + @Override + public boolean setBiome(int x, int z, int biome) { + return super.setBiome(ox + x, oz + z, biome); + } + + @Override + public BaseBiome getBiome(int x, int z) { + return super.getBiome(ox + x, oz + z); + } + @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { return super.setTile(ox + x, oy + y, oz + z, tag); 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 c463f897..d13765da 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 @@ -20,7 +20,11 @@ public abstract class ReadOnlyClipboard extends FaweClipboard { } public static ReadOnlyClipboard of(final EditSession editSession, final Region region) { - return new WorldCopyClipboard(editSession, region); + return of(editSession, region, true, false); + } + + public static ReadOnlyClipboard of(final EditSession editSession, final Region region, boolean copyEntities, boolean copyBiomes) { + return new WorldCopyClipboard(editSession, region, copyEntities, copyBiomes); } public Region getRegion() { @@ -48,7 +52,7 @@ public abstract class ReadOnlyClipboard extends FaweClipboard { } @Override - public boolean setBiome(int x, int z, byte biome) { + public boolean setBiome(int x, int z, int biome) { throw new UnsupportedOperationException("Clipboard is immutable"); } 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 40776f87..ae4be687 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 @@ -16,17 +16,26 @@ 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.ArrayList; import java.util.List; import java.util.Map; public class WorldCopyClipboard extends ReadOnlyClipboard { public final int mx, my, mz; + private final boolean hasBiomes; + private final boolean hasEntities; private MutableBlockVector2D mutableBlockVector2D = new MutableBlockVector2D(); public final EditSession editSession; public WorldCopyClipboard(EditSession editSession, Region region) { + this(editSession, region, true, false); + } + + public WorldCopyClipboard(EditSession editSession, Region region, boolean hasEntities, boolean hasBiomes) { super(region); + this.hasBiomes = hasBiomes; + this.hasEntities = hasEntities; final Vector origin = region.getMinimumPoint(); this.mx = origin.getBlockX(); this.my = origin.getBlockY(); @@ -50,12 +59,13 @@ public class WorldCopyClipboard extends ReadOnlyClipboard { @Override public List getEntities() { + if (!hasEntities) return new ArrayList<>(); return editSession.getEntities(getRegion()); } @Override public boolean hasBiomes() { - return true; + return hasBiomes; } @Override 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 985fde29..b3a23605 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 @@ -5,6 +5,10 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.regions.Region; public class WorldCutClipboard extends WorldCopyClipboard { + public WorldCutClipboard(EditSession editSession, Region region, boolean copyEntities, boolean copyBiome) { + super(editSession, region, copyEntities, copyBiome); + } + public WorldCutClipboard(EditSession editSession, Region region) { super(editSession, region); } diff --git a/core/src/main/java/com/boydti/fawe/object/function/block/BiomeCopy.java b/core/src/main/java/com/boydti/fawe/object/function/block/BiomeCopy.java new file mode 100644 index 00000000..8ffdb6de --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/function/block/BiomeCopy.java @@ -0,0 +1,31 @@ +package com.boydti.fawe.object.function.block; + +import com.sk89q.worldedit.MutableBlockVector2D; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.RegionFunction; + +public class BiomeCopy implements RegionFunction { + protected final Extent source; + protected final Extent destination; + private final MutableBlockVector2D mPos2d; + + public BiomeCopy(Extent source, Extent destination) { + this.source = source; + this.destination = destination; + this.mPos2d = new MutableBlockVector2D(); + this.mPos2d.setComponents(Integer.MIN_VALUE, Integer.MIN_VALUE); + } + + @Override + public boolean apply(Vector position) throws WorldEditException { + int x = position.getBlockX(); + int z = position.getBlockZ(); + if (x != mPos2d.getBlockX() || z != mPos2d.getBlockZ()) { + mPos2d.setComponents(x, z); + return destination.setBiome(mPos2d, source.getBiome(mPos2d)); + } + return false; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/object/function/block/SimpleBlockCopy.java b/core/src/main/java/com/boydti/fawe/object/function/block/SimpleBlockCopy.java index 8458780a..a50c3c2a 100644 --- a/core/src/main/java/com/boydti/fawe/object/function/block/SimpleBlockCopy.java +++ b/core/src/main/java/com/boydti/fawe/object/function/block/SimpleBlockCopy.java @@ -7,8 +7,8 @@ import com.sk89q.worldedit.function.RegionFunction; public class SimpleBlockCopy implements RegionFunction { - private final Extent source; - private final Extent destination; + protected final Extent source; + protected final Extent destination; public SimpleBlockCopy(Extent source, Extent destination) { this.source = source; diff --git a/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java b/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java index b1ba505b..2c09e637 100644 --- a/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java +++ b/core/src/main/java/com/boydti/fawe/object/schematic/Schematic.java @@ -7,6 +7,7 @@ import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.MaskTraverser; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.MutableBlockVector2D; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; @@ -157,9 +158,15 @@ public class Schematic { public void paste(Extent extent, WorldData worldData, Vector to, boolean pasteAir, Transform transform) { checkNotNull(transform); Region region = clipboard.getRegion(); - BlockTransformExtent source = new BlockTransformExtent(clipboard, transform, worldData.getBlockRegistry()); + Extent source = clipboard; + if (worldData != null && transform != null) { + source = new BlockTransformExtent(clipboard, transform, worldData.getBlockRegistry()); + } ForwardExtentCopy copy = new ForwardExtentCopy(source, clipboard.getRegion(), clipboard.getOrigin(), extent, to); - copy.setTransform(transform); + if (transform != null) { + copy.setTransform(transform); + } + copy.setCopyBiomes(!(clipboard instanceof BlockArrayClipboard) || ((BlockArrayClipboard) clipboard).IMP.hasBiomes()); if (extent instanceof EditSession) { EditSession editSession = (EditSession) extent; Mask sourceMask = editSession.getSourceMask(); @@ -175,11 +182,14 @@ public class Schematic { Operations.completeBlindly(copy); } - public void paste(Extent extent, Vector to, boolean pasteAir) { + public void paste(Extent extent, Vector to, final boolean pasteAir) { Region region = clipboard.getRegion().clone(); final int maxY = extent.getMaximumPoint().getBlockY(); final Vector bot = clipboard.getMinimumPoint(); final Vector origin = clipboard.getOrigin(); + + final boolean copyBiomes = !(clipboard instanceof BlockArrayClipboard) || ((BlockArrayClipboard) clipboard).IMP.hasBiomes(); + // Optimize for BlockArrayClipboard if (clipboard instanceof BlockArrayClipboard && region instanceof CuboidRegion) { // To is relative to the world origin (player loc + small clipboard offset) (As the positions supplied are relative to the clipboard min) @@ -187,29 +197,62 @@ public class Schematic { final int rely = to.getBlockY() + bot.getBlockY() - origin.getBlockY(); final int relz = to.getBlockZ() + bot.getBlockZ() - origin.getBlockZ(); BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; - bac.IMP.forEach(new FaweClipboard.BlockReader() { - @Override - public void run(int x, int y, int z, BaseBlock block) { - try { - extent.setBlock(x + relx, y + rely, z + relz, block); - } catch (WorldEditException e) { - throw new RuntimeException(e); + if (copyBiomes) { + bac.IMP.forEach(new FaweClipboard.BlockReader() { + MutableBlockVector2D mpos2d = new MutableBlockVector2D(); + { + mpos2d.setComponents(Integer.MIN_VALUE, Integer.MIN_VALUE); } - } - }, pasteAir); + @Override + public void run(int x, int y, int z, BaseBlock block) { + try { + int xx = x + relx; + int zz = z + relz; + if (xx != mpos2d.getBlockX() || zz != mpos2d.getBlockZ()) { + mpos2d.setComponents(xx, zz); + extent.setBiome(mpos2d, bac.IMP.getBiome(x, z)); + } + if (!pasteAir && block.getId() == 0) { + return; + } + extent.setBlock(xx, y + rely, zz, block); + } catch (WorldEditException e) { throw new RuntimeException(e);} + } + }, true); + } else { + bac.IMP.forEach(new FaweClipboard.BlockReader() { + @Override + public void run(int x, int y, int z, BaseBlock block) { + try { + extent.setBlock(x + relx, y + rely, z + relz, block); + } catch (WorldEditException e) { throw new RuntimeException(e);} + } + }, pasteAir); + } } else { // To must be relative to the clipboard origin ( player location - clipboard origin ) (as the locations supplied are relative to the world origin) final int relx = to.getBlockX() - origin.getBlockX(); final int rely = to.getBlockY() - origin.getBlockY(); final int relz = to.getBlockZ() - origin.getBlockZ(); RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() { + MutableBlockVector2D mpos2d_2 = new MutableBlockVector2D(); + MutableBlockVector2D mpos2d = new MutableBlockVector2D(); + { + mpos2d.setComponents(Integer.MIN_VALUE, Integer.MIN_VALUE); + } @Override public boolean apply(Vector mutable) throws WorldEditException { BaseBlock block = clipboard.getBlock(mutable); - if (block.getId() == 0 && !pasteAir) { + int xx = mutable.getBlockX() + relx; + int zz = mutable.getBlockZ() + relz; + if (copyBiomes && xx != mpos2d.getBlockX() && zz != mpos2d.getBlockZ()) { + mpos2d.setComponents(xx, zz); + extent.setBiome(mpos2d, clipboard.getBiome(mpos2d_2.setComponents(mutable.getBlockX(), mutable.getBlockZ()))); + } + if (!pasteAir && block.getId() == 0) { return false; } - extent.setBlock(mutable.getBlockX() + relx, mutable.getBlockY() + rely, mutable.getBlockZ() + relz, block); + extent.setBlock(xx, mutable.getBlockY() + rely, zz, block); return false; } }, (HasFaweQueue) (null)); diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 726c2b69..bb614afa 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1968,6 +1968,10 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting return this.changes = naturalizer.getAffected(); } + public int stackCuboidRegion(final Region region, final Vector dir, final int count, final boolean copyAir) { + return stackCuboidRegion(region, dir, count, copyAir, true, false); + } + /** * Stack a cuboid region. * @@ -1978,13 +1982,15 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting * @return number of blocks affected * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int stackCuboidRegion(final Region region, final Vector dir, final int count, final boolean copyAir) { + public int stackCuboidRegion(final Region region, final Vector dir, final int count, final boolean copyAir, boolean copyEntities, boolean copyBiomes) { checkNotNull(region); checkNotNull(dir); checkArgument(count >= 1, "count >= 1 required"); final Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); final Vector to = region.getMinimumPoint(); final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, EditSession.this, to); + copy.setCopyEntities(copyEntities); + copy.setCopyBiomes(copyBiomes); copy.setRepetitions(count); copy.setTransform(new AffineTransform().translate(dir.multiply(size))); Mask sourceMask = getSourceMask(); @@ -2012,6 +2018,10 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int moveRegion(final Region region, final Vector dir, final int distance, final boolean copyAir, final BaseBlock replacement) { + return moveRegion(region, dir, distance, copyAir, true, false, replacement); + } + + public int moveRegion(final Region region, final Vector dir, final int distance, final boolean copyAir, final boolean copyEntities, final boolean copyBiomes, final BaseBlock replacement) { checkNotNull(region); checkNotNull(dir); checkArgument(distance >= 1, "distance >= 1 required"); @@ -2038,6 +2048,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } }; + copy.setCopyBiomes(copyBiomes); + copy.setCopyEntities(copyEntities); copy.setSourceFunction(remove); copy.setRepetitions(1); copy.setTransform(new AffineTransform().translate(dir.multiply(distance))); 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 d18ee8b9..367fb592 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -157,6 +157,7 @@ public class ClipboardCommands extends MethodCommands { clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setCopyEntities(!skipEntities); + copy.setCopyBiomes(copyBiomes); Mask sourceMask = editSession.getSourceMask(); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(editSession); @@ -180,13 +181,14 @@ public class ClipboardCommands extends MethodCommands { "Flags:\n" + " -e skips entity copy\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.lazycut") public void lazyCut(Player player, LocalSession session, EditSession editSession, @Selection final Region region, @Switch('e') boolean skipEntities, - @Switch('m') Mask mask) throws WorldEditException { + @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)); @@ -202,7 +204,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, skipEntities); + ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region, !skipEntities, copyBiomes); BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard); clipboard.setOrigin(session.getPlacementPosition(player)); session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorldData())); @@ -218,6 +220,7 @@ public class ClipboardCommands extends MethodCommands { "Flags:\n" + " -e skips entity copy\n" + " -m sets a source mask so that excluded blocks become air\n" + + " -b copies biomes\n" + "WARNING: Cutting and pasting entities cannot yet be undone!", min = 0, max = 1 @@ -226,7 +229,7 @@ public class ClipboardCommands extends MethodCommands { @Logging(REGION) public void cut(FawePlayer fp, Player player, LocalSession session, EditSession editSession, @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean skipEntities, - @Switch('m') Mask mask, CommandContext context) throws WorldEditException { + @Switch('m') Mask mask, @Switch('b') boolean copyBiomes, CommandContext context) throws WorldEditException { fp.checkConfirmationRegion(getArguments(context), region); Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); @@ -244,6 +247,7 @@ public class ClipboardCommands extends MethodCommands { ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); copy.setCopyEntities(!skipEntities); + copy.setCopyBiomes(copyBiomes); Mask sourceMask = editSession.getSourceMask(); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(editSession); @@ -361,6 +365,8 @@ public class ClipboardCommands extends MethodCommands { "Pastes the clipboard's contents.\n" + "Flags:\n" + " -a skips air blocks\n" + + " -b skips pasting biomes\n" + + " -e skips pasting entities\n" + " -o pastes at the original position\n" + " -s selects the region after pasting", min = 0, @@ -369,7 +375,7 @@ public class ClipboardCommands extends MethodCommands { @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) public void paste(Player player, LocalSession session, EditSession editSession, - @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, + @Switch('a') boolean ignoreAirBlocks, @Switch('b') boolean ignoreBiomes, @Switch('e') boolean ignoreEntities, @Switch('o') boolean atOrigin, @Switch('s') boolean selectPasted) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); if (holder.getTransform().isIdentity() && editSession.getSourceMask() == null) { @@ -383,6 +389,8 @@ public class ClipboardCommands extends MethodCommands { .createPaste(editSession, editSession.getWorldData()) .to(to) .ignoreAirBlocks(ignoreAirBlocks) + .ignoreBiomes(ignoreBiomes) + .ignoreEntities(ignoreEntities) .build(); Operations.completeLegacy(operation); diff --git a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index dc9a3b99..44e2906f 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -523,7 +523,10 @@ public class RegionCommands extends MethodCommands { desc = "Move the contents of the selection", help = "Moves the contents of the selection.\n" + - "The -s flag shifts the selection to the target location.\n" + + " -s flag shifts the selection to the target location.\n" + + " -b also copies biomes\n" + + " -e ignores entities\n" + + " -a ignores air\n" + "Optionally fills the old location with .", min = 0, max = 3 @@ -535,11 +538,14 @@ public class RegionCommands extends MethodCommands { @Optional("1") @Range(min = 1) int count, @Optional(Direction.AIM) @Direction Vector direction, @Optional("air") BaseBlock replace, + @Switch('b') boolean copyBiomes, + @Switch('e') boolean skipEntities, + @Switch('a') boolean skipAir, @Switch('s') boolean moveSelection, CommandContext context) throws WorldEditException { player.checkConfirmationRegion(getArguments(context), region); - int affected = editSession.moveRegion(region, direction, count, true, replace); + int affected = editSession.moveRegion(region, direction, count, !skipAir, !skipEntities, copyBiomes, replace); if (moveSelection) { try { @@ -598,12 +604,14 @@ public class RegionCommands extends MethodCommands { @Optional("1") @Range(min = 1) int count, @Optional(Direction.AIM) @Direction Vector direction, @Switch('s') boolean moveSelection, + @Switch('b') boolean copyBiomes, + @Switch('e') boolean skipEntities, @Switch('a') boolean ignoreAirBlocks, @Switch('m') Mask sourceMask, CommandContext context) throws WorldEditException { player.checkConfirmationStack(getArguments(context), region, count); if (sourceMask != null) { editSession.addSourceMask(sourceMask); } - int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks); + int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes); if (moveSelection) { try { 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 0a7e08b4..5a049eca 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 @@ -219,12 +219,17 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent { @Override public BaseBiome getBiome(Vector2D position) { - return new BaseBiome(0); + int x = position.getBlockX() - mx; + int z = position.getBlockZ() - mz; + return IMP.getBiome(x, z); } @Override public boolean setBiome(Vector2D position, BaseBiome biome) { - return false; + int x = position.getBlockX() - mx; + int z = position.getBlockZ() - mz; + IMP.setBiome(x, z, biome.getId()); + return true; } @Nullable 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 efe68c80..6b1e1061 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 @@ -23,12 +23,14 @@ import com.boydti.fawe.example.MappedFaweQueue; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.extent.BlockTranslateExtent; import com.boydti.fawe.object.extent.PositionTransformExtent; +import com.boydti.fawe.object.function.block.BiomeCopy; import com.boydti.fawe.object.function.block.SimpleBlockCopy; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.function.CombinedRegionFunction; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; @@ -69,6 +71,7 @@ public class ForwardExtentCopy implements Operation { private Transform currentTransform = null; private int affected; private boolean copyEntities = true; + private boolean copyBiomes = false; /** * Create a new copy using the region's lowest minimum point as the @@ -147,6 +150,14 @@ public class ForwardExtentCopy implements Operation { return copyEntities; } + public void setCopyBiomes(boolean copyBiomes) { + this.copyBiomes = copyBiomes; + } + + public boolean isCopyBiomes() { + return copyBiomes; + } + /** * Set a mask that gets applied to the source extent. * @@ -257,6 +268,9 @@ public class ForwardExtentCopy implements Operation { if (sourceFunction != null) { copy = new CombinedRegionFunction(copy, sourceFunction); } + if (copyBiomes && (!(source instanceof BlockArrayClipboard) || ((BlockArrayClipboard) source).IMP.hasBiomes())) { + copy = new CombinedRegionFunction(copy, new BiomeCopy(source, finalDest)); + } RegionVisitor blockVisitor = new RegionVisitor(region, copy, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null); List entities = isCopyEntities() ? source.getEntities(region) : new ArrayList<>(); diff --git a/core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java b/core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java index 64e51615..993ef3af 100644 --- a/core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java +++ b/core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java @@ -23,6 +23,7 @@ import com.boydti.fawe.util.MaskTraverser; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -48,6 +49,8 @@ public class PasteBuilder { private Vector to = new Vector(); private boolean ignoreAirBlocks; + private boolean ignoreBiomes; + private boolean ignoreEntities; /** * Create a new instance. @@ -88,6 +91,16 @@ public class PasteBuilder { return this; } + public PasteBuilder ignoreBiomes(boolean ignoreBiomes) { + this.ignoreBiomes = ignoreBiomes; + return this; + } + + public PasteBuilder ignoreEntities(boolean ignoreEntities) { + this.ignoreEntities = ignoreEntities; + return this; + } + /** * Build the operation. * @@ -100,6 +113,8 @@ public class PasteBuilder { } ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to); copy.setTransform(transform); + copy.setCopyEntities(!ignoreEntities); + copy.setCopyBiomes((!ignoreBiomes) && (!(clipboard instanceof BlockArrayClipboard) || ((BlockArrayClipboard) clipboard).IMP.hasBiomes())); if (targetExtent instanceof EditSession) { Mask sourceMask = ((EditSession) targetExtent).getSourceMask(); if (sourceMask != null) {