From c797dcb194a385c47fedf7379f7c4cf2bec07bae Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 12 May 2019 23:32:04 +1000 Subject: [PATCH] WIP filter patterns --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 9 +- .../boydti/fawe/bukkit/beta/BukkitQueue.java | 2 + .../com/sk89q/worldedit/blocks/LazyBlock.java | 94 ------- .../boydti/fawe/beta/ArrayFilterBlock.java | 88 ++++++ .../com/boydti/fawe/beta/CharFilterBlock.java | 260 ++++++++++++------ .../boydti/fawe/beta/ChunkFilterBlock.java | 19 ++ .../com/boydti/fawe/beta/DelegateFilter.java | 3 - .../com/boydti/fawe/beta/DirectionMask.java | 5 + .../com/boydti/fawe/beta/FilterBlock.java | 82 ++++-- .../com/boydti/fawe/beta/FilterBlockMask.java | 5 + .../main/java/com/boydti/fawe/beta/Flood.java | 192 +++++++++++++ .../java/com/boydti/fawe/beta/IChunk.java | 5 +- .../beta/{IGetBlocks.java => IChunkGet.java} | 6 +- .../beta/{ISetBlocks.java => IChunkSet.java} | 5 +- .../com/boydti/fawe/beta/IDelegateChunk.java | 5 + .../com/boydti/fawe/beta/IDelegateFilter.java | 6 +- .../com/boydti/fawe/beta/IQueueExtent.java | 22 +- .../boydti/fawe/beta/SimpleFilterBlock.java | 70 +++++ .../fawe/beta/filters/ArrayImageMask.java | 26 ++ .../beta/implementation/QueueHandler.java | 3 +- .../implementation/SimpleCharQueueExtent.java | 4 +- .../beta/implementation/WorldChunkCache.java | 20 +- .../implementation/blocks/CharGetBlocks.java | 4 +- .../implementation/blocks/CharSetBlocks.java | 4 +- .../implementation/holder/ChunkHolder.java | 32 ++- .../implementation/holder/DelegateChunk.java | 3 + .../jnbt/anvil/HeightMapMCAGenerator.java | 20 +- .../com/boydti/fawe/object/FaweQueue.java | 2 +- .../fawe/object/brush/SurfaceSpline.java | 3 +- .../brush/visualization/VirtualWorld.java | 7 +- .../object/collection/BlockVectorSet.java | 2 +- .../object/collection/DifferentialArray.java | 6 +- .../DifferentialCharBlockBuffer.java | 213 ++++++++++++++ .../collection/LocalBlockVectorSet.java | 2 +- .../object/pattern/AngleColorPattern.java | 36 ++- .../pattern/RandomFullClipboardPattern.java | 6 +- .../object/queue/FaweQueueDelegateExtent.java | 12 - .../boydti/fawe/util/EditSessionBuilder.java | 231 +++++++++++++++- .../com/boydti/fawe/util/TextureUtil.java | 2 +- .../boydti/fawe/wrappers/WorldWrapper.java | 5 - .../java/com/sk89q/worldedit/EditSession.java | 98 +++---- .../worldedit/command/tool/AreaPickaxe.java | 2 +- .../command/tool/brush/GravityBrush.java | 2 +- .../event/extent/EditSessionEvent.java | 13 +- .../extent/AbstractDelegateExtent.java | 240 +++++----------- .../com/sk89q/worldedit/extent/Extent.java | 52 +--- .../sk89q/worldedit/extent/InputExtent.java | 48 ++-- .../sk89q/worldedit/extent/OutputExtent.java | 18 +- .../worldedit/extent/PassthroughExtent.java | 177 ++++++++++++ .../sk89q/worldedit/function/mask/Mask.java | 3 + .../function/pattern/FawePattern.java | 26 +- .../worldedit/function/pattern/Pattern.java | 20 +- .../worldedit/function/visitor/ScanChunk.java | 255 ++++++++++++++--- .../sk89q/worldedit/math/BlockVector3.java | 201 ++++++-------- .../sk89q/worldedit/math/BlockVector3Imp.java | 87 ++++++ .../worldedit/math/MutableBlockVector3.java | 31 ++- .../sk89q/worldedit/world/AbstractWorld.java | 5 - .../worldedit/world/block/BaseBlock.java | 21 +- .../worldedit/world/block/BlockState.java | 10 +- .../worldedit/world/block/BlockType.java | 10 +- .../world/block/ImmutableBaseBlock.java | 28 ++ 61 files changed, 2075 insertions(+), 793 deletions(-) delete mode 100644 worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java rename worldedit-core/src/main/java/com/boydti/fawe/beta/{IGetBlocks.java => IChunkGet.java} (77%) rename worldedit-core/src/main/java/com/boydti/fawe/beta/{ISetBlocks.java => IChunkSet.java} (84%) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 7739a66b7..605f18d8b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -1,10 +1,9 @@ package com.boydti.fawe.bukkit.beta; import com.boydti.fawe.Fawe; -import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IQueueExtent; -import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; @@ -49,7 +48,7 @@ public class BukkitChunkHolder> extends ChunkHolder { } @Override - public IGetBlocks get() { + public IChunkGet get() { BukkitQueue extent = (BukkitQueue) getExtent(); return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ()); } @@ -78,7 +77,7 @@ public class BukkitChunkHolder> extends ChunkHolder { int Z = getZ(); BukkitQueue extent = (BukkitQueue) getExtent(); BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet(); - ISetBlocks set = getOrCreateSet(); + IChunkSet set = getOrCreateSet(); Chunk nmsChunk = extent.ensureLoaded(X, Z); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index debf5283c..3d34e3cb9 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -13,7 +13,9 @@ import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java deleted file mode 100644 index d87e7c571..000000000 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/LazyBlock.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.blocks; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.math.BlockVector3; - -/** - * A implementation of a lazy block for {@link Extent#getLazyBlock(Vector)} - * that takes the block's ID and metadata, but will defer loading of NBT - * data until time of access. - * - *

NBT data is later loaded using a call to {@link Extent#getBlock(Vector)} - * with a stored {@link Extent} and location.

- * - *

All mutators on this object will throw an - * {@link UnsupportedOperationException}.

- */ -public class LazyBlock extends BaseBlock { - - private final Extent extent; - private final BlockVector3 position; - private boolean loaded = false; - - /** - * Create a new lazy block. - * - * @param type the block type - * @param extent the extent to later load the full block data from - * @param position the position to later load the full block data from - */ - public LazyBlock(BlockType type, Extent extent, BlockVector3 position) { - super(type); - checkNotNull(extent); - checkNotNull(position); - this.extent = extent; - this.position = position; - } - - /** - * Create a new lazy block. - * - * @param state the block state - * @param extent the extent to later load the full block data from - * @param position the position to later load the full block data from - */ - public LazyBlock(BlockState state, Extent extent, BlockVector3 position) { - super(state); - checkNotNull(extent); - checkNotNull(position); - this.extent = extent; - this.position = position; - } - - @Override - public CompoundTag getNbtData() { - if (!loaded) { - BaseBlock loadedBlock = extent.getFullBlock(position); - this.nbtData = loadedBlock.getNbtData(); - loaded = true; - } - return super.getNbtData(); - } - - @Override - public void setNbtData(CompoundTag nbtData) { - throw new UnsupportedOperationException("This object is immutable"); - } - -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java new file mode 100644 index 000000000..c005b82f8 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ArrayFilterBlock.java @@ -0,0 +1,88 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.awt.image.BufferedImage; +import java.util.concurrent.ThreadLocalRandom; + +public class ArrayFilterBlock extends SimpleFilterBlock { + private final char[] blocks; + private final byte[] heights; + private final int yOffset; + private int x, z, index; + private char ordinal; + private final int width, length; + + public ArrayFilterBlock(Extent extent, char[] blocks, byte[] heights, int width, int length, int yOffset) { + super(extent); + this.blocks = blocks; + this.width = width; + this.length = length; + this.heights = heights; + this.yOffset = yOffset; + } + + public void filter2D(Filter filter) { + for (z = 0; z < length; z++) { + for (x = 0; x < width; x++, index++) { + ordinal = blocks[ordinal]; + filter.applyBlock(this); + } + } + } + + @Override + public void setOrdinal(int ordinal) { + blocks[index] = (char) ordinal; + } + + @Override + public void setState(BlockState state) { + blocks[index] = state.getOrdinalChar(); + } + + @Override + public void setFullBlock(BaseBlock block) { + blocks[index] = block.getOrdinalChar(); + } + + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public BlockState getState() { + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getBaseBlock() { + return getState().toBaseBlock(); + } + + @Override + public CompoundTag getTag() { + return null; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return (heights[index] & 0xFF) + yOffset; + } + + @Override + public int getZ() { + return z; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java index 42a90e24c..6fcfbea45 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CharFilterBlock.java @@ -4,6 +4,7 @@ import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -12,11 +13,10 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import javax.annotation.Nullable; import static com.sk89q.worldedit.world.block.BlockTypes.states; -public class CharFilterBlock implements FilterBlock { - private IQueueExtent queue; +public class CharFilterBlock extends ChunkFilterBlock { private CharGetBlocks get; - private ISetBlocks set; + private IChunkSet set; private char[] getArr; private @Nullable char[] setArr; @@ -25,14 +25,12 @@ public class CharFilterBlock implements FilterBlock { // local private int layer, index, x, y, z, xx, yy, zz, X, Z; - @Override - public final FilterBlock init(final IQueueExtent queue) { - this.queue = queue; - return this; + public CharFilterBlock(IQueueExtent queueExtent) { + super(queueExtent); } @Override - public final FilterBlock init(final int X, final int Z, final IGetBlocks chunk) { + public final ChunkFilterBlock init(final int X, final int Z, final IChunkGet chunk) { this.get = (CharGetBlocks) chunk; this.X = X; this.Z = Z; @@ -41,11 +39,32 @@ public class CharFilterBlock implements FilterBlock { return this; } - @Override - public final void filter(final IGetBlocks iget, final ISetBlocks iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) { + public void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask) { + final int maxDepth = flood.getMaxDepth(); + final boolean checkDepth = maxDepth < Character.MAX_VALUE; + if (init(iget, iset, layer)) { + while ((index = flood.poll()) != -1) { + x = index & 15; + z = (index >> 4) & 15; + y = (index >> 8) & 15; + + if (mask.applyBlock(this)) { + int depth = index >> 12; + + if (checkDepth && depth > maxDepth) { + continue; + } + + flood.apply(x, y, z, depth); + } + } + } + } + + private final boolean init(final IChunkGet iget, final IChunkSet iset, final int layer) { this.layer = layer; final CharGetBlocks get = (CharGetBlocks) iget; - if (!get.hasSection(layer)) return; + if (!get.hasSection(layer)) return false; this.set = iset; getArr = get.sections[layer].get(get, layer); if (set.hasSection(layer)) { @@ -56,17 +75,24 @@ public class CharFilterBlock implements FilterBlock { setArr = null; } this.yy = layer << 4; - if (region == null) { - if (min != null && max != null) { - iterate(min, max, layer, filter); + return true; + } + + @Override + public final void filter(final IChunkGet iget, final IChunkSet iset, final int layer, final Filter filter, final @Nullable Region region, BlockVector3 min, BlockVector3 max) { + if (init(iget, iset, layer)) { + if (region == null) { + if (min != null && max != null) { + iterate(min, max, layer, filter); + } else { + iterate(filter); + } } else { - iterate(filter); - } - } else { - if (min != null && max != null) { - iterate(region, min, max, layer, filter); - } else { - iterate(region, filter); + if (min != null && max != null) { + iterate(region, min, max, layer, filter); + } else { + iterate(region, filter); + } } } } @@ -227,7 +253,7 @@ public class CharFilterBlock implements FilterBlock { @Override public final CompoundTag getTag() { - return null; + return get.getTag(x, y + (layer << 4), z); } public final BlockState getOrdinalBelow() { @@ -310,71 +336,135 @@ public class CharFilterBlock implements FilterBlock { public final BlockState getStateRelative(final int x, final int y, final int z) { final int newX = this.x + x; - if (newX >> 4 == 0) { - final int newZ = this.z + z; - if (newZ >> 4 == 0) { - final int newY = this.y + y; - final int layerAdd = newY >> 4; - switch (layerAdd) { - case 0: - return states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: { - final int newLayer = layer + layerAdd; - if (newLayer < 16) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; - } - case -1: - case -2: - case -3: - case -4: - case -5: - case -6: - case -7: - case -8: - case -9: - case -10: - case -11: - case -12: - case -13: - case -14: - case -15: { - final int newLayer = layer + layerAdd; - if (newLayer >= 0) { - final int index = ((newY & 15) << 8) + (newZ << 4) + newX; - return states[get.sections[newLayer].get(get, newLayer, index)]; - } - break; + final int newZ = this.z + z; + if (newX >> 4 == 0 && newZ >> 4 == 0) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; + switch (layerAdd) { + case 0: + return states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + final int newLayer = layer + layerAdd; + if (newLayer < 16) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + return states[get.sections[newLayer].get(get, newLayer, index)]; } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + final int newLayer = layer + layerAdd; + if (newLayer >= 0) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + return states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; } - return BlockTypes.__RESERVED__.getDefaultState(); } + return BlockTypes.__RESERVED__.getDefaultState(); } -// queue.get - // TODO return normal get block final int newY = this.y + y + yy; if (newY >= 0 && newY <= 256) { - return queue.getBlock(xx + newX, newY, this.zz + this.z + z); + return getExtent().getBlock(xx + newX, newY, this.zz + newZ); } return BlockTypes.__RESERVED__.getDefaultState(); } + public final BaseBlock getFullBlockRelative(final int x, final int y, final int z) { + final int newX = this.x + x; + final int newZ = this.z + z; + if (newX >> 4 == 0 && newZ >> 4 == 0) { + final int newY = this.y + y; + final int layerAdd = newY >> 4; + BlockState state = BlockTypes.__RESERVED__.getDefaultState(); + switch (layerAdd) { + case 0: + state = states[getArr[this.index + ((y << 8) + (z << 4) + x)]]; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + final int newLayer = layer + layerAdd; + if (newLayer < 16) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + state = states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + case -1: + case -2: + case -3: + case -4: + case -5: + case -6: + case -7: + case -8: + case -9: + case -10: + case -11: + case -12: + case -13: + case -14: + case -15: { + final int newLayer = layer + layerAdd; + if (newLayer >= 0) { + final int index = ((newY & 15) << 8) + (newZ << 4) + newX; + state = states[get.sections[newLayer].get(get, newLayer, index)]; + } + break; + } + } + if (state.getMaterial().hasContainer()) { + final CompoundTag tag = get.getTag(x, y + (layer << 4), z); + return state.toBaseBlock(tag); + } + } + final int newY = this.y + y + yy; + if (newY >= 0 && newY <= 256) { + return getExtent().getFullBlock(xx + newX, newY, this.zz + newZ); + } + return BlockTypes.__RESERVED__.getDefaultState().toBaseBlock(); + } + /* Set delegate */ @@ -383,6 +473,22 @@ public class CharFilterBlock implements FilterBlock { return delegate = FULL; } + @Override + public BiomeType getBiome(int x, int z) { + if ((x >> 4) == X && (z >> 4) == Z) { + return get.getBiome(x & 15, z & 15); + } + return getExtent().getBiome(x, z); + } + + @Override + public boolean setBiome(int x, int y, int z, BiomeType biome) { + if ((x >> 4) == X && (z >> 4) == Z) { + return set.setBiome(x & 15, z & 15, biome); + } + return getExtent().setBiome(x, y, z, biome); + } + private interface SetDelegate { void set(CharFilterBlock block, char value); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java new file mode 100644 index 000000000..59560279b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/ChunkFilterBlock.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.beta; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; + +import javax.annotation.Nullable; + +public abstract class ChunkFilterBlock extends FilterBlock { + public ChunkFilterBlock(Extent extent) { + super(extent); + } + + public abstract ChunkFilterBlock init(int X, int Z, IChunkGet chunk); + + public abstract void flood(final IChunkGet iget, final IChunkSet iset, final int layer, Flood flood, FilterBlockMask mask); + + public abstract void filter(IChunkGet get, IChunkSet set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java index eb941c5a9..5bc48aa80 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DelegateFilter.java @@ -10,7 +10,4 @@ public abstract class DelegateFilter implements IDelegateFilter { public Filter getParent() { return parent; } - - @Override - public abstract Filter fork(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java new file mode 100644 index 000000000..4efce15ec --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/DirectionMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface DirectionMask { + boolean apply(int fromX, int fromY, int fromZ, int toX, int toY, int toZ); +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java index 96a06562e..007b25a6d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlock.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.block.BaseBlock; @@ -8,64 +9,97 @@ import com.sk89q.worldedit.world.block.BlockState; import javax.annotation.Nullable; -public interface FilterBlock { - FilterBlock init(IQueueExtent queue); +public abstract class FilterBlock extends BlockVector3 implements Extent { + private final Extent extent; - FilterBlock init(int X, int Z, IGetBlocks chunk); + public FilterBlock(Extent extent) { + this.extent = extent; + } - void filter(IGetBlocks get, ISetBlocks set, int layer, Filter filter, @Nullable Region region, BlockVector3 min, BlockVector3 max); + public final Extent getExtent() { + return extent; + } - void setOrdinal(int ordinal); + public abstract void setOrdinal(int ordinal); - void setState(BlockState state); + public abstract void setState(BlockState state); - void setFullBlock(BaseBlock block); + public abstract void setFullBlock(BaseBlock block); - int getOrdinal(); + public abstract int getOrdinal(); - BlockState getState(); + public abstract BlockState getState(); - BaseBlock getBaseBlock(); + public abstract BaseBlock getBaseBlock(); - CompoundTag getTag(); + public abstract CompoundTag getTag(); - default BlockState getOrdinalBelow() { + @Override + public BlockVector3 getMinimumPoint() { + return getExtent().getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return getExtent().getMaximumPoint(); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return getStateRelative(x - getX(), y - getY(), z - getZ()); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return getFullBlockRelative(x - getX(), y - getY(), z - getZ()); + } + + public BlockState getOrdinalBelow() { return getStateRelative(0, -1, 0); } - default BlockState getStateAbove() { + public BlockState getStateAbove() { return getStateRelative(0, 1, 0); } - default BlockState getStateRelativeY(final int y) { + public BlockState getStateRelativeY(final int y) { return getStateRelative(0, y, 0); } - int getX(); + public BlockState getStateRelative(final int x, final int y, final int z) { + return getFullBlockRelative(x, y, z).toBlockState(); + } - int getY(); + public BaseBlock getFullBlockRelative(int x, int y, int z) { + return getExtent().getFullBlock(x + getX(), y + getY(), z + getZ()); + } - int getZ(); + @Override + public abstract int getX(); - default int getLocalX() { + @Override + public abstract int getY(); + + @Override + public abstract int getZ(); + + public int getLocalX() { return getX() & 15; } - default int getLocalY() { + public int getLocalY() { return getY() & 15; } - default int getLocalZ() { + public int getLocalZ() { return getZ() & 15; } - default int getChunkX() { + public int getChunkX() { return getX() >> 4; } - default int getChunkZ() { + public int getChunkZ() { return getZ() >> 4; } - - BlockState getStateRelative(final int x, final int y, final int z); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java new file mode 100644 index 000000000..e7728435c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/FilterBlockMask.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.beta; + +public interface FilterBlockMask { + boolean applyBlock(final FilterBlock block); +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java new file mode 100644 index 000000000..bfc567181 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/Flood.java @@ -0,0 +1,192 @@ +package com.boydti.fawe.beta; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.beta.implementation.QueueHandler; +import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class Flood { + private final int maxBranch; + private final int maxDepth; + private final Direction[] directions; + + private int[] queue; + private long[] visit; + + private int[][] queues; + private long[][] visits; + + private int X, Y, Z; + + private ConcurrentLinkedQueue queuePool = new ConcurrentLinkedQueue<>(); + private final Long2ObjectLinkedOpenHashMap chunkVisits; + private final Long2ObjectLinkedOpenHashMap chunkQueues; + + public Flood(int maxBranch, int maxDepth, Direction[] directions) { + this.maxBranch = maxBranch; + this.maxDepth = maxDepth; + this.directions = directions; + + this.queues = new int[27][]; + this.visits = new long[27][]; + + this.chunkVisits = new Long2ObjectLinkedOpenHashMap<>(); + this.chunkQueues = new Long2ObjectLinkedOpenHashMap<>(); + } + + public synchronized void run(World world) { + QueueHandler queueHandler = Fawe.get().getQueueHandler(); + IQueueExtent fq = queueHandler.getQueue(world); + while (!chunkQueues.isEmpty()) { + long firstKey = chunkQueues.firstLongKey(); + int X = MathMan.unpairIntX(firstKey); + int Z = MathMan.unpairIntY(firstKey); + int[][] chunkQueue = chunkQueues.get(firstKey); + // apply + } + } + + private void init(int X, int Y, int Z) { + this.X = X; + this.Y = Y; + this.Z = Z; + } + + public void start(int x, int y, int z) { + push(x, y, z, 0); + } + + private void push(int x, int y, int z, int depth) { + int X = x >> 4; + int Z = z >> 4; + long pair = MathMan.pairInt(X, Z); + int layer = y >> 4; + int[] section = getOrCreateQueue(pair, layer); + int val = (x & 15) + ((z & 15) << 4) + ((y & 15) << 8) + (depth << 12); + push(section, val); + } + + private int[] getOrCreateQueue(long pair, int layer) { + int[][] arrs = chunkQueues.get(pair); + if (arrs == null) { + chunkQueues.put(pair, arrs = new int[16][]); + } + int[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = newQueue(); + } + return section; + } + + private int[] newQueue() { + int[] arr = queuePool.poll(); + if (arr != null) { + arr[0] = 2; + arr[1] = 2; + return arr; + } + return new int[4096]; + } + + public int poll() { + int index = queue[0]; + if (index == queue[1]) { + return -1; + } + queue[0] = index + 1; + return queue[index]; + } + + private void push(int[] queue, int val) { + int indexStart = queue[0]; + int indexEnd = queue[1]; + push(indexStart, indexEnd, queue, val); + } + + private void push(int indexStart, int indexEnd, int[] queue, int val) { + if (indexStart > 2) { + queue[0] = --indexStart; + queue[indexStart] = val; + } else { + queue[indexEnd] = val; + queue[0] = ++indexEnd; + } + } + + public Direction[] getDirections() { + return directions; + } + + public int getMaxBranch() { + return maxBranch; + } + + public int getMaxDepth() { + return maxDepth; + } + + public void apply(int x, int y, int z, int depth) { + for (int i = 0, j = 0; i < directions.length && j < maxBranch; i++) { + final Direction dir = directions[i]; + final int ty = y + dir.getBlockY(); + final int tx = x + dir.getBlockX(); + final int tz = z + dir.getBlockZ(); + + int index; + long[] visit; + int[] queue; + final int or = tx | ty | tz; + if (or > 15 || or < 0) { + visit = this.visit; + queue = this.queue; + index = tx + (tz << 4) + (ty << 8); + } else { + int nextX = tx >> 4; + int nextY = ty >> 4; + int nextZ = tz >> 4; + int sectionIndex = nextX + nextZ * 3 + nextZ * 9 + 13; + visit = visits[sectionIndex]; + queue = queues[sectionIndex]; + if (visit == null || queue == null) { + long pair = MathMan.pairInt(X + nextX, Z + nextZ); + int layer = Y + nextY; + if (layer < 0 || layer > 15) { + continue; + } + queues[sectionIndex] = queue = getOrCreateQueue(pair, layer); + } + index = (tx & 15) + ((tz & 15) << 4) + ((ty & 15) << 8); + } + if (!getAndSet(visit, index)) { + j++; + push(queue, index + (depth << 12)); + } + } + } + + public void set(long[] bits, int i) { + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + public final boolean getAndSet(long[] bits, int i) { + int index = i >> 6; + long offset = (1L << (i & 0x3F)); + long val = bits[index]; + if ((val & offset) != 0) { + return true; + } else { + bits[index] |= offset; + return false; + } + } + + public boolean get(long[] bits, final int i) { + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java index dbc45d124..bdc17bb47 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunk.java @@ -11,7 +11,6 @@ import javax.annotation.Nullable; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.function.Supplier; /** * Represents a chunk in the queue {@link IQueueExtent} @@ -72,7 +71,9 @@ public interface IChunk> extends Trimable, Callable { * @param unitialized a mutable block vector (buffer) * @param unitialized2 a mutable block vector (buffer) */ - void filter(Filter filter, FilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + void filter(Filter filter, ChunkFilterBlock block, @Nullable Region region, MutableBlockVector3 unitialized, MutableBlockVector3 unitialized2); + + void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block); /* set - queues a change */ boolean setBiome(int x, int y, int z, BiomeType biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java similarity index 77% rename from worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java index b865e1f91..62ec359a9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkGet.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.InputExtent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -8,11 +9,14 @@ import com.sk89q.worldedit.world.block.BlockState; /** * Interface for getting blocks */ -public interface IGetBlocks extends IBlocks, Trimable { +public interface IChunkGet extends IBlocks, Trimable, InputExtent { + @Override BaseBlock getFullBlock(int x, int y, int z); + @Override BiomeType getBiome(int x, int z); + @Override BlockState getBlock(int x, int y, int z); CompoundTag getTag(int x, int y, int z); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java similarity index 84% rename from worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java rename to worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java index 7ba1f664a..138efc6be 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/ISetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IChunkSet.java @@ -1,6 +1,7 @@ package com.boydti.fawe.beta; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -14,8 +15,8 @@ import java.util.UUID; /** * Interface for setting blocks */ -public interface ISetBlocks extends IBlocks { - boolean setBiome(int x, int y, int z, BiomeType biome); +public interface IChunkSet extends IBlocks, OutputExtent { + boolean setBiome(int x, int z, BiomeType biome); boolean setBlock(int x, int y, int z, BlockStateHolder holder); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java index 0a21e1c1a..9a5f4add1 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateChunk.java @@ -26,6 +26,11 @@ public interface IDelegateChunk extends IChunk { return root; } + @Override + default void flood(Flood flood, FilterBlockMask mask, FilterBlock block) { + getParent().flood(flood, mask, block); + } + @Override default boolean setBiome(final int x, final int y, final int z, final BiomeType biome) { return getParent().setBiome(x, y, z, biome); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java index c954b91d4..e85587e59 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IDelegateFilter.java @@ -39,7 +39,11 @@ public interface IDelegateFilter extends Filter { @Override default Filter fork() { - return newInstance(getParent().fork()); + Filter fork = getParent().fork(); + if (fork != getParent()) { + return newInstance(fork); + } + return this; } Filter newInstance(Filter other); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java index a19e7ea8c..633dad3a8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -1,7 +1,10 @@ package com.boydti.fawe.beta; import com.boydti.fawe.beta.implementation.WorldChunkCache; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -12,7 +15,7 @@ import java.util.concurrent.Future; * TODO: implement Extent (need to refactor Extent first) * Interface for a queue based extent which uses chunks */ -public interface IQueueExtent extends Flushable, Trimable { +public interface IQueueExtent extends Flushable, Trimable, Extent { void init(WorldChunkCache world); /** @@ -51,11 +54,26 @@ public interface IQueueExtent extends Flushable, Trimable { return chunk.getBlock(x & 15, y, z & 15); } + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + final IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getFullBlock(x & 15, y, z & 15); + } + default BiomeType getBiome(final int x, final int z) { final IChunk chunk = getCachedChunk(x >> 4, z >> 4); return chunk.getBiome(x & 15, z & 15); } + @Override + default BlockVector3 getMinimumPoint() { + return getCache().getWorld().getMinimumPoint(); + } + + @Override + default BlockVector3 getMaximumPoint() { + return getCache().getWorld().getMaximumPoint(); + } /** * Create a new root IChunk object
* - Full chunks will be reused, so a more optimized chunk can be returned in that case
@@ -81,5 +99,5 @@ public interface IQueueExtent extends Flushable, Trimable { @Override void flush(); - FilterBlock initFilterBlock(); + ChunkFilterBlock initFilterBlock(); } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java new file mode 100644 index 000000000..34da51861 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/SimpleFilterBlock.java @@ -0,0 +1,70 @@ +package com.boydti.fawe.beta; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; + +import javax.annotation.Nullable; + +public abstract class SimpleFilterBlock extends FilterBlock { + public SimpleFilterBlock(Extent extent) { + super(extent); + } + + private int x, y, z, ordinal; + private CompoundTag nbt; + + public void init(int x, int y, int z, int ordinal) { + this.x = x; + this.y = y; + this.z = z; + this.ordinal = ordinal; + } + + public void init(int x, int y, int z, int ordinal, CompoundTag nbt) { + this.x = x; + this.y = y; + this.z = z; + this.ordinal = ordinal; + this.nbt = nbt; + } + + @Override + public int getOrdinal() { + return ordinal; + } + + @Override + public BlockState getState() { + return BlockTypes.states[ordinal]; + } + + @Override + public BaseBlock getBaseBlock() { + return getState().toBaseBlock(nbt); + } + + @Override + public CompoundTag getTag() { + return nbt; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getZ() { + return z; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java new file mode 100644 index 000000000..41ceed910 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/filters/ArrayImageMask.java @@ -0,0 +1,26 @@ +package com.boydti.fawe.beta.filters; + +import com.boydti.fawe.beta.DelegateFilter; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; + +import java.awt.image.BufferedImage; +import java.util.concurrent.ThreadLocalRandom; + +public class ArrayImageMask implements FilterBlockMask { + private final ThreadLocalRandom r; + private final boolean white; + private final BufferedImage img; + + public ArrayImageMask(BufferedImage img, boolean white) { + this.img = img; + this.white = white; + this.r = ThreadLocalRandom.current(); + } + @Override + public boolean applyBlock(FilterBlock block) { + int height = img.getRGB(block.getX(), block.getZ()) & 0xFF; + return ((height == 255 || height > 0 && !white && r.nextInt(256) <= height)); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java index a3fbf1c04..666ededbf 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java @@ -2,6 +2,7 @@ package com.boydti.fawe.beta.implementation; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.beta.IChunk; @@ -163,7 +164,7 @@ public abstract class QueueHandler implements Trimable, Runnable { // Create a chunk that we will reuse/reset for each operation final IQueueExtent queue = getQueue(world); synchronized (queue) { - FilterBlock block = null; + ChunkFilterBlock block = null; while (true) { // Get the next chunk posWeakChunk diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java index af1bce4b1..80ce0d560 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SimpleCharQueueExtent.java @@ -6,8 +6,6 @@ import com.boydti.fawe.beta.FilterBlock; public abstract class SimpleCharQueueExtent extends SingleThreadQueueExtent { @Override public FilterBlock initFilterBlock() { - FilterBlock filter = new CharFilterBlock(); - filter = filter.init(this); - return filter; + return new CharFilterBlock(this); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java index 9e5d4461f..243bc23c5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/WorldChunkCache.java @@ -1,6 +1,6 @@ package com.boydti.fawe.beta.implementation; -import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.Trimable; import com.sk89q.worldedit.world.World; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; @@ -15,7 +15,7 @@ import java.util.function.Supplier; * - avoids conversion between palette and raw data on every block get */ public class WorldChunkCache implements Trimable { - protected final Long2ObjectLinkedOpenHashMap> getCache; + protected final Long2ObjectLinkedOpenHashMap> getCache; private final World world; protected WorldChunkCache(final World world) { @@ -37,13 +37,13 @@ public class WorldChunkCache implements Trimable { * @param provider used to create if it isn't already cached * @return cached IGetBlocks */ - public synchronized IGetBlocks get(final long index, final Supplier provider) { - final WeakReference ref = getCache.get(index); + public synchronized IChunkGet get(final long index, final Supplier provider) { + final WeakReference ref = getCache.get(index); if (ref != null) { - final IGetBlocks blocks = ref.get(); + final IChunkGet blocks = ref.get(); if (blocks != null) return blocks; } - final IGetBlocks blocks = provider.get(); + final IChunkGet blocks = provider.get(); getCache.put(index, new WeakReference<>(blocks)); return blocks; } @@ -52,11 +52,11 @@ public class WorldChunkCache implements Trimable { public synchronized boolean trim(final boolean aggressive) { boolean result = true; if (!getCache.isEmpty()) { - final ObjectIterator>> iter = getCache.long2ObjectEntrySet().fastIterator(); + final ObjectIterator>> iter = getCache.long2ObjectEntrySet().fastIterator(); while (iter.hasNext()) { - final Long2ObjectMap.Entry> entry = iter.next(); - final WeakReference value = entry.getValue(); - final IGetBlocks igb = value.get(); + final Long2ObjectMap.Entry> entry = iter.next(); + final WeakReference value = entry.getValue(); + final IChunkGet igb = value.get(); if (igb == null) iter.remove(); else { result = false; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index 5c92c09aa..467d78ee8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -1,11 +1,11 @@ package com.boydti.fawe.beta.implementation.blocks; -import com.boydti.fawe.beta.IGetBlocks; +import com.boydti.fawe.beta.IChunkGet; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; -public abstract class CharGetBlocks extends CharBlocks implements IGetBlocks { +public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { @Override public BaseBlock getFullBlock(final int x, final int y, final int z) { return BlockTypes.states[get(x, y, z)].toBaseBlock(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java index f132fe2da..883fe34a9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharSetBlocks.java @@ -1,6 +1,6 @@ package com.boydti.fawe.beta.implementation.blocks; -import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; @@ -14,7 +14,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; -public class CharSetBlocks extends CharBlocks implements ISetBlocks { +public class CharSetBlocks extends CharBlocks implements IChunkSet { public BiomeType[] biomes; public HashMap tiles; public HashSet entities; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index 3a8d1d561..dbf456a72 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -1,12 +1,15 @@ package com.boydti.fawe.beta.implementation.holder; +import com.boydti.fawe.beta.ChunkFilterBlock; import com.boydti.fawe.beta.Filter; import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks; import com.boydti.fawe.beta.IChunk; -import com.boydti.fawe.beta.IGetBlocks; -import com.boydti.fawe.beta.ISetBlocks; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.WorldChunkCache; import com.boydti.fawe.util.MathMan; @@ -23,9 +26,9 @@ import java.util.function.Supplier; /** * Abstract IChunk class that implements basic get/set blocks */ -public abstract class ChunkHolder implements IChunk, Supplier { - private IGetBlocks get; - private ISetBlocks set; +public abstract class ChunkHolder implements IChunk, Supplier { + private IChunkGet get; + private IChunkSet set; private IBlockDelegate delegate; private IQueueExtent extent; private int X,Z; @@ -39,9 +42,14 @@ public abstract class ChunkHolder implements IChunk, Supplier { } @Override - public void filter(final Filter filter, FilterBlock block, @Nullable Region region, final MutableBlockVector3 min, final MutableBlockVector3 max) { - final IGetBlocks get = getOrCreateGet(); - final ISetBlocks set = getOrCreateSet(); + public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) { +// block.flood(get, set, mask, block, ); + } + + @Override + public void filter(final Filter filter, ChunkFilterBlock block, @Nullable Region region, @Nullable final MutableBlockVector3 min, @Nullable final MutableBlockVector3 max) { + final IChunkGet get = getOrCreateGet(); + final IChunkSet set = getOrCreateSet(); try { if (region != null) { switch (region.getChunkBounds(X, Z, min, max)) { @@ -106,21 +114,21 @@ public abstract class ChunkHolder implements IChunk, Supplier { return set == null || set.isEmpty(); } - public final IGetBlocks getOrCreateGet() { + public final IChunkGet getOrCreateGet() { if (get == null) get = newGet(); return get; } - public final ISetBlocks getOrCreateSet() { + public final IChunkSet getOrCreateSet() { if (set == null) set = set(); return set; } - public ISetBlocks set() { + public IChunkSet set() { return new CharSetBlocks(); } - private IGetBlocks newGet() { + private IChunkGet newGet() { if (extent instanceof SingleThreadQueueExtent) { final WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); return cache.get(MathMan.pairInt(X, Z), this); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java index a41e8357e..91e28814f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/DelegateChunk.java @@ -1,5 +1,8 @@ package com.boydti.fawe.beta.implementation.holder; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.FilterBlockMask; +import com.boydti.fawe.beta.Flood; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IDelegateChunk; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index 5cce020b4..6debbbe3c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java @@ -2,6 +2,12 @@ package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.ArrayFilterBlock; +import com.boydti.fawe.beta.DelegateFilter; +import com.boydti.fawe.beta.Filter; +import com.boydti.fawe.beta.FilterBlock; +import com.boydti.fawe.beta.SimpleFilterBlock; +import com.boydti.fawe.beta.filters.ArrayImageMask; import com.boydti.fawe.example.SimpleIntFaweChunk; import com.boydti.fawe.jnbt.anvil.HeightMapMCADrawer; import com.boydti.fawe.jnbt.anvil.MCAChunk; @@ -1022,7 +1028,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr @Override public BlockState getBlock(BlockVector3 position) { - return getLazyBlock(position); + return getBlock(position.getX(), position.getY(), position.getZ()); } public BlockState getFloor(int x, int z) { @@ -1045,12 +1051,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr } @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { + public BlockState getBlock(int x, int y, int z) { return BlockState.getFromInternalId(getCombinedId4Data(x, y, z)); } @@ -1340,6 +1341,11 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr } } + public void test() { +// ArrayImageMask mask = new ArrayImageMask(img, white); +// filter = new ArrayFilterBlock(this, overlayArr, heights.get(), getWidth(), getLength(), 1); + } + public void setOverlay(BufferedImage img, Pattern pattern, boolean white) { if (pattern instanceof BlockStateHolder) { setOverlay(img, ((BlockStateHolder) pattern).getInternalId(), white); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java index 4e56a4977..484cd90e2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -72,7 +72,7 @@ public interface FaweQueue extends HasFaweQueue, Extent { } @Override - default BlockState getLazyBlock(int x, int y, int z) { + default BlockState getBlock(int x, int y, int z) { int combinedId4Data = getCachedCombinedId4Data(x, y, z, BlockTypes.AIR.getInternalId()); try { BlockState state = BlockState.getFromInternalId(combinedId4Data); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java index 3e6ea0c6b..d6c1c37f5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/SurfaceSpline.java @@ -50,6 +50,7 @@ public class SurfaceSpline implements Brush { n.setContinuity(continuity); nodes.add(n); } + MutableBlockVector3 mutable = MutableBlockVector3.at(0, 0, 0); interpol.setNodes(nodes); final double splinelength = interpol.arcLength(0, 1); for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) { @@ -60,7 +61,7 @@ public class SurfaceSpline implements Brush { tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY); if (tipy == -1) continue; if (radius == 0) { - BlockVector3 set = MutableBlockVector3.get(tipx, tipy, tipz); + BlockVector3 set = mutable.setComponents(tipx, tipy, tipz); try { pattern.apply(editSession, set, set); } catch (WorldEditException e) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java index 4eb958fcb..4a2009b58 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/VirtualWorld.java @@ -24,7 +24,12 @@ public interface VirtualWorld extends SimpleWorld, FaweQueue, Closeable { @Override default BaseBlock getFullBlock(BlockVector3 position) { - return getLazyBlock(position).toBaseBlock(); + return getBlock(position).toBaseBlock(); + } + + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + return getBlock(x, y, z).toBaseBlock(); } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java index a16f43a9d..2c32bb2a2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockVectorSet.java @@ -43,7 +43,7 @@ public class BlockVectorSet extends AbstractCollection implements int newSize = count + size; if (newSize > index) { int localIndex = index - count; - MutableBlockVector3 pos = new MutableBlockVector3(set.getIndex(localIndex)); + BlockVector3 pos = set.getIndex(localIndex); if (pos != null) { int pair = entry.getIntKey(); int cx = MathMan.unpairX(pair); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java index a8c399721..9141e7d6d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialArray.java @@ -244,9 +244,9 @@ public final class DifferentialArray implements DifferentialCollection { return dataBytes; } -// public char[] getCharArray() { -// return dataChars; -// } + public char[] getCharArray() { + return dataChars; + } public int[] getIntArray() { return dataInts; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java new file mode 100644 index 000000000..15a52d950 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/DifferentialCharBlockBuffer.java @@ -0,0 +1,213 @@ +package com.boydti.fawe.object.collection; + +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; + +import java.io.IOException; +import java.lang.reflect.Array; + +/** + * Records changes made through the {@link #set(int, int, int, char)} method
+ * Changes are not recorded if you edit the raw data + */ +public final class DifferentialCharBlockBuffer implements DifferentialCollection { + + private final int width, length; + private final int t1, t2; + private char[][][][][] data; + private char[][][][][] changes; + + public DifferentialCharBlockBuffer(int width, int length) { + this.width = width; + this.length = length; + this.t1 = (length + 15) >> 4; + this.t2 = (width + 15) >> 4; + } + + @Override + public char[][][][][] get() { + return data; + } + + @Override + public void flushChanges(FaweOutputStream out) throws IOException { + boolean modified = isModified(); + out.writeBoolean(modified); + + if (modified) { + writeArray(changes, 0, 0, out); + } + clearChanges(); + } + + private void writeArray(Object arr, int level, int index, FaweOutputStream out) throws IOException { + if (level == 4) { + if (arr != null) { + char[] level4 = (char[]) arr; + out.writeVarInt(level4.length); + for (char c : level4) { + out.writeChar(c); + } + } else { + out.writeVarInt(0); + } + } else { + int len = arr == null ? 0 : Array.getLength(arr); + out.writeVarInt(len); + for (int i = 0; i < len; i++) { + Object elem = Array.get(arr, i); + writeArray(elem, level + 1, i, out); + } + } + } + + @Override + public void undoChanges(FaweInputStream in) throws IOException { + if (changes != null && changes.length != 0) throw new IllegalStateException("There are uncommitted changes, please flush first"); + boolean modified = in.readBoolean(); + if (modified) { + int len = in.readVarInt(); + if (len == 0) { + data = null; + } else { + for (int i = 0; i < len; i++) { + readArray(data, i, 1, in); + } + } + } + + clearChanges(); + } + + @Override + public void redoChanges(FaweInputStream in) throws IOException { + clearChanges(); + throw new UnsupportedOperationException("Not implemented"); + } + + private void readArray(Object dataElem, int index, int level, FaweInputStream in) throws IOException { + int len = in.readVarInt(); + if (level == 4) { + char[][] castedElem = (char[][]) dataElem; + if (len == 0) { + castedElem[index] = null; + } else { + char[] current = castedElem[index]; + for (int i = 0; i < len; i++) { + current[i] = in.readChar(); + } + } + } else { + if (len == 0) { + Array.set(dataElem, index, null); + } else { + Object nextElem = Array.get(dataElem, index); + for (int i = 0; i < len; i++) { + readArray(nextElem, i, level + 1, in); + } + } + } + } + + public boolean isModified() { + return changes != null; + } + + public void clearChanges() { + changes = null; + } + + public void set(int x, int y, int z, char combined) { + if (combined == 0) combined = 1; + int localX = x & 15; + int localZ = z & 15; + int chunkX = x >> 4; + int chunkZ = z >> 4; + if (data == null) { + data = new char[t1][][][][]; + changes = new char[0][][][][]; + } + + char[][][][] arr = data[chunkZ]; + if (arr == null) { + arr = data[chunkZ] = new char[t2][][][]; + } + char[][][] arr2 = arr[chunkX]; + if (arr2 == null) { + arr2 = arr[chunkX] = new char[256][][]; + } + + char[][] yMap = arr2[y]; + if (yMap == null) { + arr2[y] = yMap = new char[16][]; + } + boolean newSection; + char current; + char[] zMap = yMap[localZ]; + if (zMap == null) { + yMap[localZ] = zMap = new char[16]; + + if (changes == null) { + changes = new char[t1][][][][]; + } else if (changes != null && changes.length != 0) { + initialChange(changes, chunkX, chunkZ, localX, localZ, y, (char) -combined); + } + + } else { + if (changes == null || changes.length == 0) changes = new char[t1][][][][]; + appendChange(changes, chunkX, chunkZ, localX, localZ, y, (char) (zMap[localX] - combined)); + } + + zMap[localX] = combined; + } + + private void initialChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) { + char[][][][] arr = src[chunkZ]; + if (arr == null) { + src[chunkZ] = new char[0][][][]; + return; + } else if (arr.length == 0) return; + + char[][][] arr2 = arr[chunkX]; + if (arr2 == null) { + arr[chunkX] = new char[0][][]; + return; + } else if (arr2.length == 0) return; + + char[][] yMap = arr2[y]; + if (yMap == null) { + arr2[y] = new char[0][]; + return; + } else if (yMap.length == 0) return; + + char[] zMap = yMap[localZ]; + if (zMap == null) { + yMap[localZ] = new char[0]; + return; + } else if (zMap.length == 0) return; + + char current = zMap[localX]; + zMap[localX] = combined; + } + + private void appendChange(char[][][][][] src, int chunkX, int chunkZ, int localX, int localZ, int y, char combined) { + char[][][][] arr = src[chunkZ]; + if (arr == null || arr.length == 0) { + arr = src[chunkZ] = new char[t2][][][]; + } + char[][][] arr2 = arr[chunkX]; + if (arr2 == null || arr2.length == 0) { + arr2 = arr[chunkX] = new char[256][][]; + } + + char[][] yMap = arr2[y]; + if (yMap == null || yMap.length == 0) { + arr2[y] = yMap = new char[16][]; + } + char[] zMap = yMap[localZ]; + if (zMap == null || zMap.length == 0) { + yMap[localZ] = zMap = new char[16]; + } + zMap[localX] = combined; + } +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java index 863de2781..14b532bba 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/LocalBlockVectorSet.java @@ -100,7 +100,7 @@ public class LocalBlockVectorSet implements Set { this.offsetZ = z; } - public BlockVector3 getIndex(int getIndex) { + protected BlockVector3 getIndex(int getIndex) { int size = size(); if (getIndex > size) { return null; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java index f11fc4896..64e3ee009 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/AngleColorPattern.java @@ -2,8 +2,10 @@ package com.boydti.fawe.object.pattern; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.DataAnglePattern; import com.boydti.fawe.util.TextureHolder; +import com.boydti.fawe.util.TextureUtil; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -15,11 +17,11 @@ import com.sk89q.worldedit.world.block.BlockType; import java.io.IOException; public class AngleColorPattern extends DataAnglePattern { - protected transient TextureHolder util; + protected transient TextureUtil util; - public AngleColorPattern(Extent extent, TextureHolder util, int distance) { + public AngleColorPattern(Extent extent, TextureHolder holder, int distance) { super(extent, distance); - this.util = util; + this.util = holder.getTextureUtil(); } public int getColor(int color, int slope) { @@ -31,15 +33,28 @@ public class AngleColorPattern extends DataAnglePattern { return (((color >> 24) & 0xFF) << 24) + (newRed << 16) + (newGreen << 8) + (newBlue << 0); } + @Override + public void apply(FilterBlock block) { + BlockState state = block.getState(); + int slope = getSlope(state, block); + if (slope == -1) return; + int color = util.getColor(state.getBlockType()); + if (color == 0) return; + int newColor = getColor(color, slope); + BlockType newBlock = util.getNearestBlock(newColor); + if (newBlock == null) return; + newBlock.apply(block); + } + @Override public BaseBlock apply(BlockVector3 position) { BaseBlock block = extent.getFullBlock(position); int slope = getSlope(block, position); if (slope == -1) return block; - int color = util.getTextureUtil().getColor(block.getBlockType()); + int color = util.getColor(block.getBlockType()); if (color == 0) return block; int newColor = getColor(color, slope); - return util.getTextureUtil().getNearestBlock(newColor).getDefaultState().toBaseBlock(); + return util.getNearestBlock(newColor).getDefaultState().toBaseBlock(); } @Override @@ -51,7 +66,7 @@ public class AngleColorPattern extends DataAnglePattern { int z = vector.getBlockZ(); int height = extent.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY); if (height > 0) { - BlockStateHolder below = extent.getLazyBlock(x, height - 1, z); + BlockStateHolder below = extent.getBlock(x, height - 1, z); if (!below.getBlockType().getMaterial().isMovementBlocker()) { return Integer.MAX_VALUE; } @@ -65,16 +80,11 @@ public class AngleColorPattern extends DataAnglePattern { BlockStateHolder block = extent.getBlock(getPosition); int slope = getSlope(block, getPosition); if (slope == -1) return false; - int color = util.getTextureUtil().getColor(block.getBlockType()); + int color = util.getColor(block.getBlockType()); if (color == 0) return false; int newColor = getColor(color, slope); - BlockType newBlock = util.getTextureUtil().getNearestBlock(newColor); + BlockType newBlock = util.getNearestBlock(newColor); if (newBlock == null) return false; return extent.setBlock(setPosition, newBlock.getDefaultState()); } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - util = Fawe.get().getCachedTextureUtil(true, 0, 100); - } } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java index 36c3eb08c..82863af97 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/pattern/RandomFullClipboardPattern.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.object.PseudoRandom; import com.boydti.fawe.object.schematic.Schematic; import com.sk89q.worldedit.WorldEditException; @@ -25,14 +26,15 @@ public class RandomFullClipboardPattern extends AbstractPattern { private final Extent extent; private final MutableBlockVector3 mutable = new MutableBlockVector3(); private final List clipboards; - private boolean randomRotate; - private boolean randomFlip; + private final boolean randomRotate; + private final boolean randomFlip; public RandomFullClipboardPattern(Extent extent, List clipboards, boolean randomRotate, boolean randomFlip) { checkNotNull(clipboards); this.clipboards = clipboards; this.extent = extent; this.randomRotate = randomRotate; + this.randomFlip = randomFlip; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java index 0eed3a025..f2f67ab60 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/queue/FaweQueueDelegateExtent.java @@ -86,16 +86,4 @@ public class FaweQueueDelegateExtent extends DelegateFaweQueue { public boolean setBlock(int x, int y, int z, BlockStateHolder block) throws WorldEditException { return parentExtent.setBlock(x, y, z, block); } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return parentExtent.getLazyBlock(position); - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return parentExtent.getLazyBlock(x, y, z); - } - - } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java index b6e3de434..81e11ddc5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java @@ -2,14 +2,36 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.anvil.MCAQueue; +import com.boydti.fawe.jnbt.anvil.MCAWorld; +import com.boydti.fawe.logging.LoggingChangeSet; import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory; import com.boydti.fawe.object.*; +import com.boydti.fawe.object.brush.visualization.VirtualWorld; +import com.boydti.fawe.object.changeset.BlockBagChangeSet; +import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.MemoryOptimizedHistory; +import com.boydti.fawe.object.exception.FaweException; +import com.boydti.fawe.object.extent.FastWorldEditExtent; +import com.boydti.fawe.object.extent.HeightBoundExtent; +import com.boydti.fawe.object.extent.MultiRegionExtent; +import com.boydti.fawe.object.extent.NullExtent; +import com.boydti.fawe.object.extent.ProcessedWEExtent; +import com.boydti.fawe.object.extent.SingleRegionExtent; +import com.boydti.fawe.object.extent.SlowExtent; +import com.boydti.fawe.object.extent.StripNBTExtent; +import com.boydti.fawe.object.progress.ChatProgressTracker; +import com.boydti.fawe.object.progress.DefaultProgressTracker; +import com.boydti.fawe.wrappers.WorldWrapper; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.eventbus.EventBus; @@ -190,7 +212,214 @@ public class EditSessionBuilder { return this; } + private boolean wrapped; + + private AbstractDelegateExtent wrapExtent(final AbstractDelegateExtent extent, final EventBus eventBus, EditSessionEvent event, final EditSession.Stage stage) { + event = event.clone(stage); + event.setExtent(extent); + eventBus.post(event); + if (event.isCancelled()) { + return new NullExtent(extent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL); + } + final Extent toReturn = event.getExtent(); + if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) { + return new NullExtent(toReturn, null); + } + if (!(toReturn instanceof AbstractDelegateExtent)) { + Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent"); + return extent; + } + if (toReturn != extent) { + String className = toReturn.getClass().getName().toLowerCase(); + for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) { + if (className.contains(allowed.toLowerCase())) { + this.wrapped = true; + return (AbstractDelegateExtent) toReturn; + } + } + if (Settings.IMP.EXTENT.DEBUG) { + Fawe.debug("&cPotentially unsafe extent blocked: " + toReturn.getClass().getName()); + Fawe.debug("&8 - &7For area restrictions, it is recommended to use the FaweAPI"); + Fawe.debug("&8 - &7For block logging, it is recommended to use use BlocksHub"); + Fawe.debug("&8 - &7To allow this plugin add it to the FAWE `allowed-plugins` list"); + Fawe.debug("&8 - &7To hide this message set `debug` to false in the FAWE config.yml"); + if (toReturn.getClass().getName().contains("CoreProtect")) { + Fawe.debug("Note on CoreProtect: "); + Fawe.debug(" - If you disable CP's WE logger (CP config) and this still shows, please update CP"); + Fawe.debug(" - Use BlocksHub and set `debug` false in the FAWE config"); + } + } + } + return extent; + } + + public EditSessionBuilder commit() { + // reset + wrapped = false; + // + if (worldName == null) { + if (world == null) { + if (queue == null) { + worldName = ""; + } else { + worldName = queue.getWorldName(); + } + } else { + worldName = Fawe.imp().getWorldName(world); + } + } + if (world == null && !this.worldName.isEmpty()) { + world = FaweAPI.getWorld(this.worldName); + } + if (eventBus == null) { + eventBus = WorldEdit.getInstance().getEventBus(); + } + if (event == null) { + event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); + } + if (player == null && event.getActor() != null) { + player = FawePlayer.wrap(event.getActor()); + } + if (limit == null) { + if (player == null) { + limit = FaweLimit.MAX; + } else { + limit = player.getLimit(); + } + } + if (autoQueue == null) { + autoQueue = true; + } + if (fastmode == null) { + if (player == null) { + fastmode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE; + } else { + fastmode = player.getSession().hasFastMode(); + } + } + if (checkMemory == null) { + checkMemory = player != null && !this.fastmode; + } + if (checkMemory) { + if (MemUtil.isMemoryLimitedSlow()) { + if (Perm.hasPermission(player, "worldedit.fast")) { + BBC.WORLDEDIT_OOM_ADMIN.send(player); + } + throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY); + } + } +// this.originalLimit = limit; + this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null; +// this.limit = limit.copy(); + + if (queue == null) { + boolean placeChunks = this.fastmode || this.limit.FAST_PLACEMENT; + World unwrapped = WorldWrapper.unwrap(world); + if (unwrapped instanceof FaweQueue) { + queue = (FaweQueue) unwrapped; + } else if (unwrapped instanceof MCAWorld) { + queue = ((MCAWorld) unwrapped).getQueue(); + } else if (player != null && world.equals(player.getWorld())) { + queue = player.getFaweQueue(placeChunks, autoQueue); + } else { + queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue); + } + } + if (combineStages == null) { + combineStages = + // If it's enabled in the settings + Settings.IMP.HISTORY.COMBINE_STAGES + // If fast placement is disabled, it's slower to perform a copy on each chunk + && this.limit.FAST_PLACEMENT + // If the specific queue doesn't support it + && queue.supports(FaweQueue.Capability.CHANGE_TASKS) + // If the edit uses items from the inventory we can't use a delayed task + && this.blockBag == null; + } +// if (Settings.IMP.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) { +// queue = new MCAQueue(queue); +// } + if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) { + switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) { + case "chat": + this.queue.setProgressTask(new ChatProgressTracker(player)); + break; + case "title": + case "true": + default: + this.queue.setProgressTask(new DefaultProgressTracker(player)); + } + } +// this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE); +// this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER)); +// if (!this.fastMode || changeSet != null) { +// if (changeSet == null) { +// if (Settings.IMP.HISTORY.USE_DISK) { +// UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID(); +// if (Settings.IMP.HISTORY.USE_DATABASE) { +// changeSet = new RollbackOptimizedHistory(world, uuid); +// } else { +// changeSet = new DiskStorageHistory(world, uuid); +// } +// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) { +// changeSet = new CPUOptimizedChangeSet(world); +// } else { +// changeSet = new MemoryOptimizedHistory(world); +// } +// } +// if (this.limit.SPEED_REDUCTION > 0) { +// this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION); +// } +// if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) { +// changeSet = LoggingChangeSet.wrap(player, changeSet); +// } +// if (!(changeSet instanceof NullChangeSet)) { +// if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) { +// changeSet = LoggingChangeSet.wrap(player, changeSet); +// } +// if (this.blockBag != null) { +// changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1); +// } +// if (combineStages) { +// changeTask = changeSet; +// changeSet.addChangeTask(queue); +// } else { +// this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue)); +//// if (this.blockBag != null) { +//// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1); +//// } +// } +// } +// } +// if (allowedRegions == null) { +// if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) { +// allowedRegions = player.getCurrentRegions(); +// } +// } +// this.maxY = getWorld() == null ? 255 : world.getMaxY(); +// if (allowedRegions != null) { +// if (allowedRegions.length == 0) { +// this.extent = new NullExtent(this.extent, BBC.WORLDEDIT_CANCEL_REASON_NO_REGION); +// } else { +// this.extent = new ProcessedWEExtent(this.extent, this.limit); +// if (allowedRegions.length == 1) { +// Region region = allowedRegions[0]; +// this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]); +// } else { +// this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions); +// } +// } +// } else { +// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY); +// } +// if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) { +// this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); +// } +// this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); + return this; + } + public EditSession build() { - return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); + return new EditSession(worldName, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, eventBus, event); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 84d3af4ad..ae0989472 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -486,7 +486,7 @@ public class TextureUtil implements TextureHolder { BlockType block = getNearestBlock(color); TextureUtil.BiomeColor biome = getNearestBiome(color); int blockColor = getColor(block); - blockAndBiomeIdOutput[0] = block.getInternalId(); + blockAndBiomeIdOutput[0] = block.getDefaultState().getOrdinalChar(); blockAndBiomeIdOutput[1] = biome.id; if (colorDistance(biome.grassCombined, color) - biomePriority > colorDistance(blockColor, color)) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java index 4f111f826..476483d99 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java @@ -235,11 +235,6 @@ public class WorldWrapper extends AbstractWorld { return parent.getBlock(position); } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return parent.getLazyBlock(position); - } - @Override public BaseBlock getFullBlock(BlockVector3 position) { return parent.getFullBlock(position); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 880427593..1f9aaf8ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -42,7 +42,6 @@ import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet; import com.boydti.fawe.object.changeset.DiskStorageHistory; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.MemoryOptimizedHistory; -import com.boydti.fawe.object.collection.BlockVectorSet; import com.boydti.fawe.object.collection.LocalBlockVectorSet; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.extent.FastWorldEditExtent; @@ -61,6 +60,7 @@ import com.boydti.fawe.object.mask.ResettableMask; import com.boydti.fawe.object.pattern.ExistingPattern; import com.boydti.fawe.object.progress.ChatProgressTracker; import com.boydti.fawe.object.progress.DefaultProgressTracker; +import com.boydti.fawe.util.EditSessionBuilder; import com.boydti.fawe.util.ExtentTraverser; import com.boydti.fawe.util.MaskTraverser; import com.boydti.fawe.util.MathMan; @@ -79,28 +79,18 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.MaskingExtent; -import com.sk89q.worldedit.extent.cache.LastAccessExtentCache; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBagExtent; -import com.sk89q.worldedit.extent.reorder.ChunkBatchingExtent; -import com.sk89q.worldedit.extent.reorder.MultiStageReorder; -import com.sk89q.worldedit.extent.validation.BlockChangeLimiter; -import com.sk89q.worldedit.extent.validation.DataValidatorExtent; -import com.sk89q.worldedit.extent.world.BlockQuirkExtent; -import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; -import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.extent.world.SurvivalModeExtent; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; -import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.Naturalizer; import com.sk89q.worldedit.function.generator.ForestGenerator; import com.sk89q.worldedit.function.generator.GardenPatchGenerator; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockMaskBuilder; -import com.sk89q.worldedit.function.mask.BlockStateMask; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.BoundedHeightMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -116,7 +106,6 @@ import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.function.pattern.WaterloggedRemover; import com.sk89q.worldedit.function.util.RegionOffset; import com.sk89q.worldedit.function.visitor.DirectionalVisitor; import com.sk89q.worldedit.function.visitor.DownwardVisitor; @@ -127,12 +116,10 @@ import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.history.UndoContext; import com.sk89q.worldedit.history.change.BlockChange; -import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; -import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.math.BlockVector2; @@ -142,7 +129,6 @@ import com.sk89q.worldedit.math.MutableBlockVector2; import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector2; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.interpolation.Interpolation; import com.sk89q.worldedit.math.interpolation.KochanekBartelsInterpolation; import com.sk89q.worldedit.math.interpolation.Node; import com.sk89q.worldedit.math.noise.RandomNoise; @@ -159,21 +145,30 @@ import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.collection.DoubleArrayList; import com.sk89q.worldedit.util.eventbus.EventBus; -import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.SimpleWorld; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.*; -import com.sk89q.worldedit.world.registry.LegacyMapper; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockID; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.weather.WeatherType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import static com.google.common.base.Preconditions.checkArgument; @@ -204,19 +199,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, BEFORE_CHANGE } - private World world; - private String worldName; - private FaweQueue queue; - private boolean wrapped; - private boolean fastMode; - private AbstractDelegateExtent extent; - private HistoryExtent history; - private AbstractDelegateExtent bypassHistory; - private AbstractDelegateExtent bypassAll; - private FaweLimit originalLimit; - private FaweLimit limit; - private FawePlayer player; - private FaweChangeSet changeTask; + private final World world; + private final String worldName; + private final FaweQueue queue; + private final boolean wrapped; + private final boolean fastMode; + private final AbstractDelegateExtent extent; + private final HistoryExtent history; + private final AbstractDelegateExtent bypassHistory; + private final AbstractDelegateExtent bypassAll; + private final FaweLimit originalLimit; + private final FaweLimit limit; + private final FawePlayer player; + private final FaweChangeSet changeTask; private MutableBlockVector3 mutablebv = new MutableBlockVector3(); @@ -249,7 +244,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, if (event == null) { event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null); } - event.setEditSession(this); if (player == null && event.getActor() != null) { player = FawePlayer.wrap(event.getActor()); } @@ -393,7 +387,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT); } this.extent = wrapExtent(this.extent, bus, event, Stage.BEFORE_HISTORY); - setExtent(this.extent); + } + + public EditSession(EditSessionBuilder builder) { + super(builder.) } /** @@ -496,15 +493,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return bypassHistory; } - public Extent getExtent() { - return extent; - } - - public void setExtent(AbstractDelegateExtent extent) { - this.extent = extent; - new ExtentTraverser(this).setNext(extent); - } - /** * Get the FawePlayer or null * @@ -1057,17 +1045,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return queue.getOpacity(x, y, z); } - @Override - public BlockState getLazyBlock(final BlockVector3 position) { - return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - } - - public BlockState getLazyBlock(int x, int y, int z) { - return extent.getLazyBlock(x, y, z); - } - public BlockState getBlock(int x, int y, int z) { - return getLazyBlock(x, y, z); + return extent.getBlock(x, y, z); } @Override @@ -1085,7 +1064,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * * @param position the position * @return the block type - * @deprecated Use {@link #getLazyBlock(BlockVector3)} or {@link #getBlock(BlockVector3)} + * @deprecated Use {@link #getBlock(BlockVector3)} or {@link #getBlock(BlockVector3)} */ @Deprecated public BlockType getBlockType(final BlockVector3 position) { @@ -1099,7 +1078,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @param z the Z coordinate * @param minY minimal height * @param maxY maximal height - * @param filter a mask of blocks to consider, or null to consider any solid (movement-blocking) block * @return height of highest block found or 'minY' */ public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { @@ -2918,11 +2896,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * Generate a shape for the given expression. * * @param region the region to generate the shape in - * @param zero the coordinate origin for x/y/z variables - * @param unit the scale of the x/y/z/ variables - * @param pattern the default material to make the shape from - * @param expressionString the expression defining the shape - * @param hollow whether the shape should be hollow * @return number of blocks changed * @throws ExpressionException * @throws MaxChangedBlocksException @@ -3433,8 +3406,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, CompoundTag nbt = block.getNbtData(); if (nbt != null) { if (nbt.containsKey("items")) { - block.setNbtData(null); - return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block); + return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block.toBlockState().toBaseBlock()); } } return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index aa18e499f..97abe6b0a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -49,7 +49,7 @@ public class AreaPickaxe implements BlockTool { for (int x = ox - range; x <= ox + range; ++x) { for (int z = oz - range; z <= oz + range; ++z) { for (int y = oy + range; y >= oy - range; --y) { - if (initialType.equals(editSession.getLazyBlock(x, y, z))) { + if (initialType.equals(editSession.getBlock(x, y, z))) { continue; } editSession.setBlock(x, y, z, BlockTypes.AIR.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 646915f30..6578beb99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -49,7 +49,7 @@ public class GravityBrush implements Brush { for (int z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) { int freeSpot = startCheckY; for (int y = startCheckY; y <= endY; y++) { - BlockStateHolder block = editSession.getLazyBlock(x, y, z); + BlockStateHolder block = editSession.getBlock(x, y, z); if (!block.getBlockType().getMaterial().isAir()) { if (y != freeSpot) { editSession.setBlock(x, y, z, EditSession.nullBlock); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java index c94ba677a..fe1e845c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/extent/EditSessionEvent.java @@ -66,7 +66,6 @@ public class EditSessionEvent extends Event implements Cancellable { private final int maxBlocks; private final Stage stage; private Extent extent; - private EditSession session; private boolean cancelled; /** @@ -84,14 +83,6 @@ public class EditSessionEvent extends Event implements Cancellable { this.stage = stage; } - public void setEditSession(EditSession session) { - this.session = session; - } - - public EditSession getEditSession() { - return session; - } - /** * Get the actor for this event. * @@ -169,9 +160,7 @@ public class EditSessionEvent extends Event implements Cancellable { * @return a new event */ public EditSessionEvent clone(Stage stage) { - EditSessionEvent clone = new EditSessionEvent(world, actor, maxBlocks, stage); - clone.setEditSession(session); - return clone; + return new EditSessionEvent(world, actor, maxBlocks, stage); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java index d3021c391..93b541b2f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractDelegateExtent.java @@ -22,8 +22,6 @@ package com.sk89q.worldedit.extent; import com.boydti.fawe.jnbt.anvil.generator.GenBase; import com.boydti.fawe.jnbt.anvil.generator.Resource; import com.boydti.fawe.object.extent.LightingExtent; -import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -41,29 +39,40 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.registry.BundledBlockData; -import java.util.List; + import javax.annotation.Nullable; +import java.util.List; -public class AbstractDelegateExtent implements LightingExtent { - private transient final Extent extent; - protected MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0); +import static com.google.common.base.Preconditions.checkNotNull; - /** - * Create a new instance. - * - * @param extent the extent - */ - public AbstractDelegateExtent(Extent extent) { - checkNotNull(extent); - this.extent = extent; +public class AbstractDelegateExtent implements Extent, LightingExtent { + private final Extent extent; + + public AbstractDelegateExtent(Extent parent) { + this.extent = parent; } - public int getSkyLight(int x, int y, int z) { - if (extent instanceof LightingExtent) { - return ((LightingExtent) extent).getSkyLight(x, y, z); - } - return 0; + /** + * Get the extent. + * + * @return the extent + */ + public final Extent getExtent() { + return extent; + } + + /* + Bounds + */ + + @Override + public BlockVector3 getMinimumPoint() { + return extent.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return extent.getMaximumPoint(); } @Override @@ -71,11 +80,40 @@ public class AbstractDelegateExtent implements LightingExtent { return extent.getMaxY(); } + /* + Input + Output + */ + @Override - public BlockType getBlockType(BlockVector3 position) { - return extent.getBlockType(position); + public BlockState getBlock(int x, int y, int z) { + return extent.getBlock(x, y, z); } + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return extent.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiome(int x, int z) { + return extent.getBiome(x, z); + } + + @Override + public boolean setBiome(int x, int z, BiomeType biome) { + return extent.setBiome(x, z, biome); + } + + /* + Light + */ + + public int getSkyLight(int x, int y, int z) { + if (extent instanceof LightingExtent) { + return ((LightingExtent) extent).getSkyLight(x, y, z); + } + return 0; + } public int getBlockLight(int x, int y, int z) { if (extent instanceof LightingExtent) { @@ -88,7 +126,7 @@ public class AbstractDelegateExtent implements LightingExtent { if (extent instanceof LightingExtent) { return ((LightingExtent) extent).getOpacity(x, y, z); } - return getLazyBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightOpacity(); } @Override @@ -103,164 +141,20 @@ public class AbstractDelegateExtent implements LightingExtent { if (extent instanceof LightingExtent) { return ((LightingExtent) extent).getBrightness(x, y, z); } - return getLazyBlock(x, y, z).getBlockType().getMaterial().getLightValue(); + return getBlock(x, y, z).getBlockType().getMaterial().getLightValue(); } - /** - * Get the extent. - * - * @return the extent + /* + Generic */ - public Extent getExtent() { - return extent; - } - - @Override - public BlockState getLazyBlock(int x, int y, int z) { - return extent.getLazyBlock(mutable.setComponents(x, y, z)); - } - - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return extent.getLazyBlock(position); - } - - @Override - public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { - return setBlock(mutable.setComponents(x, y, z), block); - } - - public BlockState getBlock(BlockVector3 position) { - return extent.getBlock(position); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - return extent.getFullBlock(position); - } - - @Override - public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - return extent.setBlock(location, block); - } - - @Override - @Nullable - public Entity createEntity(Location location, BaseEntity entity) { - return extent.createEntity(location, entity); - } - - @Override - public List getEntities() { - return extent.getEntities(); - } - - @Override - public List getEntities(Region region) { - return extent.getEntities(region); - } - - @Override - public BiomeType getBiome(BlockVector2 position) { - return extent.getBiome(position); - } - - @Override - public boolean setBiome(BlockVector2 position, BiomeType biome) { - return extent.setBiome(position, biome); - } - - @Override - public boolean setBiome(int x, int y, int z, BiomeType biome) { - return extent.setBiome(x, y, z, biome); - } - - @Override - public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { - return extent.getHighestTerrainBlock(x, z, minY, maxY); - } - - @Override - public BlockVector3 getMinimumPoint() { - return extent.getMinimumPoint(); - } - - @Override - public BlockVector3 getMaximumPoint() { - return extent.getMaximumPoint(); - } - - protected Operation commitBefore() { - return null; - } @Override public String toString() { return super.toString() + ":" + extent.toString(); } - @Override - public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { - return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); - } - - @Override - public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { - return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); - } - - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); - } - - @Override - public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { - return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); - } - - @Override - public void addCaves(Region region) throws WorldEditException { - extent.addCaves(region); - } - - @Override - public void generate(Region region, GenBase gen) throws WorldEditException { - extent.generate(region, gen); - } - - @Override - public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { - extent.spawnResource(region, gen, rarity, frequency); - } - - @Override - public boolean contains(BlockVector3 pt) { - return extent.contains(pt); - } - - @Override - public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { - extent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); - } - - @Override - public void addOres(Region region, Mask mask) throws WorldEditException { - extent.addOres(region, mask); + protected Operation commitBefore() { + return null; } @Override @@ -279,6 +173,4 @@ public class AbstractDelegateExtent implements LightingExtent { return null; } } - - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 9c2416eb0..3f41ba3cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -117,33 +117,11 @@ public interface Extent extends InputExtent, OutputExtent { return null; } - @Override - default BlockState getBlock(BlockVector3 position) { - return getFullBlock(position).toImmutableState(); - } - - @Override - default BlockState getLazyBlock(BlockVector3 position) { - return getFullBlock(position).toImmutableState(); - } - - default BlockState getLazyBlock(int x, int y, int z) { - return getLazyBlock(BlockVector3.at(x, y, z)); - } - - default > boolean setBlock(int x, int y, int z, T state) throws WorldEditException { - return setBlock(BlockVector3.at(x, y, z), state); - } - - default boolean setBiome(int x, int y, int z, BiomeType biome) { - return setBiome(BlockVector2.at(x, z), biome); - } - default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) { maxY = Math.min(maxY, Math.max(0, maxY)); minY = Math.max(0, minY); for (int y = maxY; y >= minY; --y) { - BlockState block = getLazyBlock(x, y, z); + BlockState block = getBlock(x, y, z); if (block.getBlockType().getMaterial().isMovementBlocker()) { return y; } @@ -167,20 +145,20 @@ public interface Extent extends InputExtent, OutputExtent { int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); - BlockState block = getLazyBlock(x, y, z); + BlockState block = getBlock(x, y, z); boolean state = !block.getBlockType().getMaterial().isMovementBlocker(); int data1 = PropertyGroup.LEVEL.get(block); int data2 = data1; int offset = state ? 0 : 1; for (int d = 0; d <= clearance; d++) { int y1 = y + d; - block = getLazyBlock(x, y1, z); + block = getBlock(x, y1, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { return ((y1 - offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data1)); } data1 = PropertyGroup.LEVEL.get(block); int y2 = y - d; - block = getLazyBlock(x, y2, z); + block = getBlock(x, y2, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { return ((y2 + offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data2)); } @@ -189,7 +167,7 @@ public interface Extent extends InputExtent, OutputExtent { if (clearanceAbove != clearanceBelow) { if (clearanceAbove < clearanceBelow) { for (int layer = y - clearance - 1; layer >= minY; layer--) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { int data = (state ? PropertyGroup.LEVEL.get(block) : data1); return ((layer + offset) << 4) + 0; @@ -198,7 +176,7 @@ public interface Extent extends InputExtent, OutputExtent { } } else { for (int layer = y + clearance + 1; layer <= maxY; layer++) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getBlockType().getMaterial().isMovementBlocker() != state) { return ((layer - offset) << 4) - (15 - (state ? PropertyGroup.LEVEL.get(block) : data2)); } @@ -254,33 +232,33 @@ public interface Extent extends InputExtent, OutputExtent { int clearanceAbove = maxY - y; int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); - BlockStateHolder block = getLazyBlock(x, y, z); + BlockStateHolder block = getBlock(x, y, z); boolean state = !block.getBlockType().getMaterial().isMovementBlocker(); int offset = state ? 0 : 1; for (int d = 0; d <= clearance; d++) { int y1 = y + d; - block = getLazyBlock(x, y1, z); + block = getBlock(x, y1, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return y1 - offset; int y2 = y - d; - block = getLazyBlock(x, y2, z); + block = getBlock(x, y2, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return y2 + offset; } if (clearanceAbove != clearanceBelow) { if (clearanceAbove < clearanceBelow) { for (int layer = y - clearance - 1; layer >= minY; layer--) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return layer + offset; } } else { for (int layer = y + clearance + 1; layer <= maxY; layer++) { - block = getLazyBlock(x, layer, z); + block = getBlock(x, layer, z); if (!block.getMaterial().isMovementBlocker() != state && block.getBlockType() != BlockTypes.__RESERVED__) return layer - offset; } } } int result = state ? failedMin : failedMax; if(result > 0 && !ignoreAir) { - block = getLazyBlock(x, result, z); + block = getBlock(x, result, z); return block.getBlockType().getMaterial().isAir() ? -1 : result; } return result; @@ -296,7 +274,7 @@ public interface Extent extends InputExtent, OutputExtent { } } - default public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + default void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1); } @@ -320,11 +298,11 @@ public interface Extent extends InputExtent, OutputExtent { return (pt.containedWithin(min, max)); } - default public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + default void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { spawnResource(region, new OreGen(this, mask, material, size, minY, maxY), rarity, frequency); } - default public void addOres(Region region, Mask mask) throws WorldEditException { + default void addOres(Region region, Mask mask) throws WorldEditException { addOre(region, mask, BlockTypes.DIRT.getDefaultState(), 33, 10, 100, 0, 255); addOre(region, mask, BlockTypes.GRAVEL.getDefaultState(), 33, 8, 100, 0, 255); addOre(region, mask, BlockTypes.ANDESITE.getDefaultState(), 33, 10, 100, 0, 79); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java index 3edcccb43..1f4342518 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/InputExtent.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit.extent; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -46,42 +48,31 @@ public interface InputExtent { * @param position position of the block * @return the block */ - BlockState getBlock(BlockVector3 position); + default BlockState getBlock(BlockVector3 position) { + return getBlock(position.getX(), position.getY(), position.getZ()); + } + + default BlockState getBlock(int x, int y, int z) { + return getBlock(MutableBlockVector3.get(x, y, z)); + } default BlockType getBlockType(BlockVector3 position) { return getBlock(position).getBlockType(); } - /** - * Get a lazy, immutable snapshot of the block at the given location that only - * immediately contains information about the block's type (and metadata). - * - *

Further information (such as NBT data) will be available by the - * time of access. Therefore, it is not recommended that - * this method is used if the world is being simulated at the time of - * call. If the block needs to be stored for future use, then this method should - * definitely not be used. Moreover, the block that is returned is immutable (or - * should be), and therefore modifications should not be attempted on it. If a - * modifiable copy is required, then the block should be cloned.

- * - *

This method exists because it is sometimes important to inspect the block - * at a given location, but {@link #getBlock(Vector)} may be too expensive in - * the underlying implementation. It is also not possible to implement - * caching if the returned object is mutable, so this methods allows caching - * implementations to be used.

- * - * @param position position of the block - * @return the block - */ - BlockState getLazyBlock(BlockVector3 position); - /** * Get a immutable snapshot of the block at the given location. * * @param position position of the block * @return the block */ - BaseBlock getFullBlock(BlockVector3 position); + default BaseBlock getFullBlock(BlockVector3 position) { + return getFullBlock(position.getX(), position.getY(), position.getZ()); + } + + default BaseBlock getFullBlock(int x, int y, int z) { + return getFullBlock(MutableBlockVector3.get(x, y, z)); + } /** * Get the biome at the given location. @@ -92,6 +83,11 @@ public interface InputExtent { * @param position the (x, z) location to check the biome at * @return the biome at the location */ - BiomeType getBiome(BlockVector2 position); + default BiomeType getBiome(BlockVector2 position) { + return getBiome(position.getX(), position.getZ()); + } + default BiomeType getBiome(int x, int z) { + return getBiome(MutableBlockVector2.get(x, z)); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java index 53351e0b0..a7e73c1bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/OutputExtent.java @@ -23,6 +23,8 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -50,7 +52,13 @@ public interface OutputExtent { * @return true if the block was successfully set (return value may not be accurate) * @throws WorldEditException thrown on an error */ - > boolean setBlock(BlockVector3 position, T block) throws WorldEditException; + default > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return setBlock(position.getX(), position.getY(), position.getZ(), block); + } + + default > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return setBlock(MutableBlockVector3.get(x, y, z), block); + } /** * Set the biome. @@ -59,7 +67,13 @@ public interface OutputExtent { * @param biome the biome to set to * @return true if the biome was successfully set (return value may not be accurate) */ - boolean setBiome(BlockVector2 position, BiomeType biome); + default boolean setBiome(BlockVector2 position, BiomeType biome) { + return setBiome(position.getX(), 0, position.getBlockZ(), biome); + } + + default boolean setBiome(int x, int y, int z, BiomeType biome) { + return setBiome(MutableBlockVector2.get(x, z), biome); + } /** * Return an {@link Operation} that should be called to tie up loose ends diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java new file mode 100644 index 000000000..c8df9204e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/PassthroughExtent.java @@ -0,0 +1,177 @@ +package com.sk89q.worldedit.extent; + +import com.boydti.fawe.jnbt.anvil.generator.GenBase; +import com.boydti.fawe.jnbt.anvil.generator.Resource; +import com.boydti.fawe.object.extent.LightingExtent; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.OperationQueue; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; + +import javax.annotation.Nullable; +import java.util.List; + +public class PassthroughExtent extends AbstractDelegateExtent { + private final Extent extent; + + public PassthroughExtent(Extent parent) { + super(parent); + this.extent = parent; + } + + @Override + public List getEntities(Region region) { + return extent.getEntities(region); + } + + @Override + public List getEntities() { + return extent.getEntities(); + } + + @Override + @Nullable + public Entity createEntity(Location location, BaseEntity entity) { + return extent.createEntity(location, entity); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY) { + return extent.getHighestTerrainBlock(x, z, minY, maxY); + } + + @Override + public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) { + return extent.getHighestTerrainBlock(x, z, minY, maxY, filter); + } + + @Override + public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + return extent.getNearestSurfaceLayer(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask); + } + + @Override + public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) { + return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir); + } + + @Override + public void addCaves(Region region) throws WorldEditException { + extent.addCaves(region); + } + + @Override + public void generate(Region region, GenBase gen) throws WorldEditException { + extent.generate(region, gen); + } + + @Override + public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { + extent.addSchems(region, mask, clipboards, rarity, rotate); + } + + @Override + public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { + extent.spawnResource(region, gen, rarity, frequency); + } + + @Override + public boolean contains(BlockVector3 pt) { + return extent.contains(pt); + } + + @Override + public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { + extent.addOre(region, mask, material, size, frequency, rarity, minY, maxY); + } + + @Override + public void addOres(Region region, Mask mask) throws WorldEditException { + extent.addOres(region, mask); + } + + @Override + public List> getBlockDistribution(Region region) { + return extent.getBlockDistribution(region); + } + + @Override + public List> getBlockDistributionWithData(Region region) { + return extent.getBlockDistributionWithData(region); + } + + @Override + public BlockArrayClipboard lazyCopy(Region region) { + return extent.lazyCopy(region); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return extent.getBlock(position); + } + + @Override + public BlockType getBlockType(BlockVector3 position) { + return extent.getBlockType(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return extent.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + return extent.getBiome(position); + } + + @Override + public > boolean setBlock(BlockVector3 position, T block) throws WorldEditException { + return extent.setBlock(position, block); + } + + @Override + public > boolean setBlock(int x, int y, int z, T block) throws WorldEditException { + return extent.setBlock(x, y, z, block); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + return extent.setBiome(position, biome); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java index 38b3783b1..05e22d9d2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/Mask.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.mask; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.minecraft.util.commands.Link; import com.sk89q.worldedit.command.UtilityCommands; import com.sk89q.worldedit.math.BlockVector3; @@ -42,6 +43,8 @@ public interface Mask { */ boolean test(BlockVector3 vector); +// boolean test(FilterBlock block); + /** * Get the 2D version of this mask if one exists. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java index 8a797f5cd..a45ac9168 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/FawePattern.java @@ -16,17 +16,17 @@ import com.sk89q.worldedit.world.block.BlockState; */ @Link(clazz = UtilityCommands.class, value = "patterns") public interface FawePattern extends Pattern { - - @Deprecated - default BaseBlock apply(BlockVector3 position) { - throw new UnsupportedOperationException("Please use apply(extent, get, set)"); - } - - /** - * Return a {@link BlockStateHolder} for the given position. - * - * @return a block - */ - @Override - boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException; +// +// @Deprecated +// default BaseBlock apply(BlockVector3 position) { +// throw new UnsupportedOperationException("Please use apply(extent, get, set)"); +// } +// +// /** +// * Return a {@link BlockStateHolder} for the given position. +// * +// * @return a block +// */ +// @Override +// boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException; } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java index 290240c2c..93eeb07a5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/Pattern.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.function.pattern; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.minecraft.util.commands.Link; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.UtilityCommands; @@ -26,23 +27,12 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockState; /** * Returns a {@link BlockStateHolder} for a given position. */ @Link(clazz = UtilityCommands.class, value = "patterns") -public interface Pattern{ - -// @Override -// default BaseBlock next(BlockVector3 position) { -// return new BaseBlock(apply(position)); -// } -// -// @Override -// default BaseBlock next(int x, int y, int z) { -// return new BaseBlock(apply(BlockVector3.at(x, y, z))); -// } +public interface Pattern { /** * Return a {@link BlockStateHolder} for the given position. @@ -55,4 +45,10 @@ public interface Pattern{ default boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException { return extent.setBlock(set, apply(get)); } + +// void apply(FilterBlock block); + + default void apply(FilterBlock block) { + apply((BlockVector3) block).apply(block); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java index cfef60a74..96ce3ca37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java @@ -1,23 +1,19 @@ package com.sk89q.worldedit.function.visitor; -import com.boydti.fawe.example.MappedFaweQueue; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.HasFaweQueue; -import com.boydti.fawe.object.collection.BlockVectorSet; +import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.math.BlockVector3; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArraySet; -import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.objects.ObjectIterator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Map; +import java.util.concurrent.ConcurrentLinkedQueue; /** * A chunk based search algorithm @@ -58,15 +54,15 @@ public class ScanChunk { private final RegionFunction function; private final BlockVector3[] directions; - private final Long2ObjectOpenHashMap visited; - private final Long2ObjectOpenHashMap queues; + private final Long2ObjectOpenHashMap visits; + private final Long2ObjectOpenHashMap queues; public ScanChunk(final RegionFunction function) { this.function = function; this.directions = DEFAULT_DIRECTIONS; this.queues = new Long2ObjectOpenHashMap<>(); - this.visited = new Long2ObjectOpenHashMap<>(); + this.visits = new Long2ObjectOpenHashMap<>(); } public static final long pairInt(int x, int y) { @@ -77,7 +73,7 @@ public class ScanChunk { int X = x >> 4; int Z = z >> 4; long pair = pairInt(X, Z); - long[][] chunk = visited.get(pair); + long[][] chunk = visits.get(pair); if (chunk == null) return false; int layer = y >> 4; long[] section = chunk[layer]; @@ -87,7 +83,7 @@ public class ScanChunk { public void start(int x, int y, int z) { if (!isVisited(x, y, z)) { - queue(x, y, z); + push(x, y, z); visit(x, y, z); } } @@ -96,45 +92,240 @@ public class ScanChunk { int X = x >> 4; int Z = z >> 4; long pair = pairInt(X, Z); - long[][] chunk = visited.get(pair); - if (chunk == null) { - visited.put(pair, chunk = new long[16][]); + long[][] arrs = visits.get(pair); + if (arrs == null) { + visits.put(pair, arrs = new long[16][]); } int layer = y >> 4; - long[] section = chunk[layer]; + long[] section = arrs[layer]; if (section == null) { - chunk[layer] = section = new long[64]; + arrs[layer] = section = new long[64]; } set(section, getLocalIndex(x & 15, y & 15, z & 15)); } - public void queue(int x, int y, int z) { + private char[] getOrCreateQueue(long pair, int layer) { + char[][] arrs = queues.get(pair); + if (arrs == null) { + queues.put(pair, arrs = new char[16][]); + } + + char[] section = arrs[layer]; + if (section == null) { + arrs[layer] = section = newQueue(); + } + return section; + } + + private void push(int x, int y, int z) { int X = x >> 4; int Z = z >> 4; long pair = pairInt(X, Z); - char[] queue = queues.get(pair); - if (queue == null) { - queue = queues.put(pair, queue = new char[MAX_QUEUE + 2]); - queue[0] = 2; - queue[1] = 2; + int layer = y >> 4; + char[] section = getOrCreateQueue(pair, layer); + push(section, x & 15, y & 15, z & 15); + } + + private void push(char[] queue, int x, int y, int z) { + char indexStart = queue[0]; + char indexEnd = queue[1]; + push(indexStart, indexEnd, queue, x, y, z); + } + + private void push(char indexStart, char indexEnd, char[] queue, int x, int y, int z) { + char index = getLocalIndex(x, y, z); + if (indexStart > 2) { + queue[0] = --indexStart; + queue[indexStart] = index; + } else { + queue[indexEnd] = index; + queue[0] = ++indexEnd; } - if (queue[1] >= queue.length) { - queue[1] = 2; - } - queue[queue[1]++] = getLocalIndex(x & 15, y, z & 15); } public void process() { LongArraySet set = new LongArraySet(); while (!queues.isEmpty()) { - ObjectIterator> iter = queues.long2ObjectEntrySet().fastIterator(); - Long2ObjectMap.Entry entry = iter.next(); - long index = entry.getLongKey(); - int X = MathMan.unpairIntX(index); - int Z = MathMan.unpairIntY(index); +// ObjectIterator> iter = queues.long2ObjectEntrySet().fastIterator(); +// Long2ObjectMap.Entry entry = iter.next(); +// long index = entry.getLongKey(); +// int X = MathMan.unpairIntX(index); +// int Z = MathMan.unpairIntY(index); +// // check that adjacent chunks aren;t being processed +// +// char[] queue = entry.getValue(); +// long[][] visit = visits.get(index); +// if (visit == null) { +// visits.put(index, visit = new long[16][]); +// } } } + private ConcurrentLinkedQueue queuePool = new ConcurrentLinkedQueue<>(); + + private char[] newQueue() { + char[] arr = queuePool.poll(); + if (arr != null) { + arr[0] = 2; + arr[1] = 2; + return arr; + } + return new char[4096]; + } + + public void process4(int xx, int yy, int zz, char[] queue, long[] visit) { + char index; + while ((index = queue[0]) != queue[1]) { + queue[0]++; + + char triple = queue[index]; + int x = index & 15; + int z = (index >> 4) & 15; + int y = index >> 8; + + int absX = xx + x; + int absY = yy + y; + int absZ = zz + z; + + apply(xx + x, yy + y, zz + z); + + int x1 = x, x2 = x; + + // find start of scan-line + int i1 = index; + while (true) { + if (x1 < 0) { + // queue in west chunk + break; + } + if (get(visit, i1)) break; + // visit + set(visit, i1); + + i1--; + x1--; + } + i1++; + x1++; + + // find end of scan-line + int i2 = index; + while (true) { + if (x2 > 15) { + // queue in east chunk + break; + } + if (get(visit, i2)) break; + set(visit, i2); + i2++; + x2++; + } + i2--; + x2--; + + // find start + } + } + + public void apply(int x, int y, int z) { + + } + + public void process4(int X, int Z, char[][] queues, long[][] visit) { + int xx = X << 4; + int zz = Z << 4; + + // TODO fetch instead of create + final BlockVector3[] dirs = directions; + char[][] dirQueues = new char[directions.length][]; + while (true) { + boolean empty = true; + for (int layer = 0; layer < 16; layer++) { + char[] queue = queues[layer]; + if (queue == null) continue; + char index; + while ((index = queue[0]) != queue[1]) { + queue[0]++; + + char triple = queue[index]; + int x = index & 15; + int z = (index >> 4) & 15; + int y = index >> 8; + } + queuePool.add(queue); + queues[layer] = null; + continue; + } + + if (empty) break; + } + // empty queues + +// while (indexStart != indexEnd) { +// char index = queue[indexStart++]; +// byte dirs = 0xF; +// int x = index & 15; +// int z = (index >> 4) & 15; +// int y = index >> 8; +// +// int layer = y >> 4; +// long[] visitBits = visit[layer]; +// +// int x1 = x; +// int x2 = x; +// +// // find start of scan-line +// int i1 = index; +// while (true) { +// if (x1 < 0) { +// // queue in adjacent chunk +// break; +// } +// if (get(visitBits, i1--)) break; +// x1--; +// } +// i1++; +// x1++; +// +// // find end of scan-line +// int i2 = index; +// while (true) { +// if (x2 > 15) { +// // queue in adjacent chunk +// break; +// } +// if (get(visitBits, i2++)) break; +// x2++; +// } +// i2--; +// x2--; +// +// boolean scanUp = false; +// boolean scanDown = false; +// boolean scanLeft = false; +// boolean scanRight = false; +// +// for (int i = i1; i <= i2; i++) { +// if (!scanDown && y > 0 && ) +// } +// +// for (int i=x1; i<=x2; i++) { // find scan-lines above this one +// if (!inScanLine && y>0 && ip.getPixel(i,y-1)==color) +// {push(i, y-1); inScanLine = true;} +// else if (inScanLine && y>0 && ip.getPixel(i,y-1)!=color) +// inScanLine = false; +// } +// +// inScanLine = false; +// for (int i=x1; i<=x2; i++) { // find scan-lines below this one +// if (!inScanLine && y> 6] |= (1L << (i & 0x3F)); } @@ -144,7 +335,7 @@ public class ScanChunk { } public char getLocalIndex(int x, int y, int z) { - return (char) (y + (x << 8) + (z << 12)); + return (char) (x + (z << 4) + (y << 8)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index f465f4142..bb4d0dc3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -29,58 +29,36 @@ import java.util.Comparator; /** * An immutable 3-dimensional vector. */ -public class BlockVector3 { +public abstract class BlockVector3 { - public static final BlockVector3 ZERO = new BlockVector3(0, 0, 0); - public static final BlockVector3 UNIT_X = new BlockVector3(1, 0, 0); - public static final BlockVector3 UNIT_Y = new BlockVector3(0, 1, 0); - public static final BlockVector3 UNIT_Z = new BlockVector3(0, 0, 1); - public static final BlockVector3 ONE = new BlockVector3(1, 1, 1); + public static final BlockVector3 ZERO = new BlockVector3Imp(0, 0, 0); + public static final BlockVector3 UNIT_X = new BlockVector3Imp(1, 0, 0); + public static final BlockVector3 UNIT_Y = new BlockVector3Imp(0, 1, 0); + public static final BlockVector3 UNIT_Z = new BlockVector3Imp(0, 0, 1); + public static final BlockVector3 ONE = new BlockVector3Imp(1, 1, 1); public static BlockVector3 at(double x, double y, double z) { return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); } public static BlockVector3 at(int x, int y, int z) { - return new BlockVector3(x, y, z); + return new BlockVector3Imp(x, y, z); } - // thread-safe initialization idiom - private static final class YzxOrderComparator { - private static final Comparator YZX_ORDER = (a, b) -> { - return ComparisonChain.start() - .compare(a.y, b.y) - .compare(a.z, b.z) - .compare(a.x, b.x) - .result(); - }; - } + static final Comparator YZX_ORDER = (a, b) -> ComparisonChain.start() + .compare(a.getY(), b.getY()) + .compare(a.getZ(), b.getZ()) + .compare(a.getX(), b.getX()) + .result(); /** * Returns a comparator that sorts vectors first by Y, then Z, then X. - * + * *

* Useful for sorting by chunk block storage order. */ public static Comparator sortByCoordsYzx() { - return YzxOrderComparator.YZX_ORDER; - } - - protected int x, y, z; - - protected BlockVector3(){} - - /** - * Construct an instance. - * - * @param x the X coordinate - * @param y the Y coordinate - * @param z the Z coordinate - */ - protected BlockVector3(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; + return YZX_ORDER; } public MutableBlockVector3 setComponents(double x, double y, double z) { @@ -92,27 +70,27 @@ public class BlockVector3 { } public MutableBlockVector3 mutX(double x) { - return new MutableBlockVector3((int) x, y, z); + return new MutableBlockVector3((int) x, getY(), getZ()); } public MutableBlockVector3 mutY(double y) { - return new MutableBlockVector3(x, (int) y, z); + return new MutableBlockVector3(getX(), (int) y, getZ()); } public MutableBlockVector3 mutZ(double z) { - return new MutableBlockVector3(x, y, (int) z); + return new MutableBlockVector3(getX(), getY(), (int) z); } public MutableBlockVector3 mutX(int x) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(x, getY(), getZ()); } public MutableBlockVector3 mutY(int y) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(getX(), y, getZ()); } public MutableBlockVector3 mutZ(int z) { - return new MutableBlockVector3(x, y, z); + return new MutableBlockVector3(getX(), getY(), z); } /** @@ -120,9 +98,7 @@ public class BlockVector3 { * * @return the x coordinate */ - public int getX() { - return x; - } + public abstract int getX(); /** * Get the X coordinate. @@ -130,7 +106,7 @@ public class BlockVector3 { * @return the x coordinate */ public int getBlockX() { - return x; + return getX(); } /** @@ -140,7 +116,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withX(int x) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(x, getY(), getZ()); } /** @@ -148,9 +124,7 @@ public class BlockVector3 { * * @return the y coordinate */ - public int getY() { - return y; - } + public abstract int getY(); /** * Get the Y coordinate. @@ -158,7 +132,7 @@ public class BlockVector3 { * @return the y coordinate */ public int getBlockY() { - return y; + return getY(); } /** @@ -168,7 +142,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withY(int y) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(getX(), y, getZ()); } /** @@ -176,9 +150,7 @@ public class BlockVector3 { * * @return the z coordinate */ - public int getZ() { - return z; - } + public abstract int getZ(); /** * Get the Z coordinate. @@ -186,7 +158,7 @@ public class BlockVector3 { * @return the z coordinate */ public int getBlockZ() { - return z; + return getZ(); } /** @@ -196,7 +168,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 withZ(int z) { - return BlockVector3.at(x, y, z); + return BlockVector3.at(getX(), getY(), z); } /** @@ -206,7 +178,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(BlockVector3 other) { - return add(other.x, other.y, other.z); + return add(other.getX(), other.getY(), other.getZ()); } /** @@ -218,7 +190,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(int x, int y, int z) { - return BlockVector3.at(this.x + x, this.y + y, this.z + z); + return BlockVector3.at(this.getX() + x, this.getY() + y, this.getZ() + z); } /** @@ -229,12 +201,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 add(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX += other.x; - newY += other.y; - newZ += other.z; + newX += other.getX(); + newY += other.getY(); + newZ += other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -248,7 +220,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(BlockVector3 other) { - return subtract(other.x, other.y, other.z); + return subtract(other.getX(), other.getY(), other.getZ()); } /** @@ -261,7 +233,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(int x, int y, int z) { - return BlockVector3.at(this.x - x, this.y - y, this.z - z); + return BlockVector3.at(this.getX() - x, this.getY() - y, this.getZ() - z); } /** @@ -272,12 +244,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 subtract(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX -= other.x; - newY -= other.y; - newZ -= other.z; + newX -= other.getX(); + newY -= other.getY(); + newZ -= other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -290,7 +262,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(BlockVector3 other) { - return multiply(other.x, other.y, other.z); + return multiply(other.getX(), other.getY(), other.getZ()); } /** @@ -302,7 +274,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(int x, int y, int z) { - return BlockVector3.at(this.x * x, this.y * y, this.z * z); + return BlockVector3.at(this.getX() * x, this.getY() * y, this.getZ() * z); } /** @@ -312,12 +284,12 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 multiply(BlockVector3... others) { - int newX = x, newY = y, newZ = z; + int newX = getX(), newY = getY(), newZ = getZ(); for (BlockVector3 other : others) { - newX *= other.x; - newY *= other.y; - newZ *= other.z; + newX *= other.getX(); + newY *= other.getY(); + newZ *= other.getZ(); } return BlockVector3.at(newX, newY, newZ); @@ -340,7 +312,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 divide(BlockVector3 other) { - return divide(other.x, other.y, other.z); + return divide(other.getX(), other.getY(), other.getZ()); } /** @@ -352,7 +324,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 divide(int x, int y, int z) { - return BlockVector3.at(this.x / x, this.y / y, this.z / z); + return BlockVector3.at(this.getX() / x, this.getY() / y, this.getZ() / z); } /** @@ -380,7 +352,7 @@ public class BlockVector3 { * @return length, squared */ public int lengthSq() { - return x * x + y * y + z * z; + return getX() * getX() + getY() * getY() + getZ() * getZ(); } /** @@ -400,9 +372,9 @@ public class BlockVector3 { * @return distance */ public int distanceSq(BlockVector3 other) { - int dx = other.x - x; - int dy = other.y - y; - int dz = other.z - z; + int dx = other.getX() - getX(); + int dy = other.getY() - getY(); + int dz = other.getZ() - getZ(); return dx * dx + dy * dy + dz * dz; } @@ -414,9 +386,9 @@ public class BlockVector3 { */ public BlockVector3 normalize() { double len = length(); - double x = this.x / len; - double y = this.y / len; - double z = this.z / len; + double x = this.getX() / len; + double y = this.getY() / len; + double z = this.getZ() / len; return BlockVector3.at(x, y, z); } @@ -427,7 +399,7 @@ public class BlockVector3 { * @return the dot product of this and the other vector */ public double dot(BlockVector3 other) { - return x * other.x + y * other.y + z * other.z; + return getX() * other.getX() + getY() * other.getY() + getZ() * other.getZ(); } /** @@ -437,10 +409,10 @@ public class BlockVector3 { * @return the cross product of this and the other vector */ public BlockVector3 cross(BlockVector3 other) { - return new BlockVector3( - y * other.z - z * other.y, - z * other.x - x * other.z, - x * other.y - y * other.x + return new BlockVector3Imp( + getY() * other.getZ() - getZ() * other.getY(), + getZ() * other.getX() - getX() * other.getZ(), + getX() * other.getY() - getY() * other.getX() ); } @@ -452,7 +424,7 @@ public class BlockVector3 { * @return true if the vector is contained */ public boolean containedWithin(BlockVector3 min, BlockVector3 max) { - return x >= min.x && x <= max.x && y >= min.y && y <= max.y && z >= min.z && z <= max.z; + return getX() >= min.getX() && getX() <= max.getX() && getY() >= min.getY() && getY() <= max.getY() && getZ() >= min.getZ() && getZ() <= max.getZ(); } /** @@ -464,11 +436,11 @@ public class BlockVector3 { */ public BlockVector3 clampY(int min, int max) { checkArgument(min <= max, "minimum cannot be greater than maximum"); - if (y < min) { - return BlockVector3.at(x, min, z); + if (getY() < min) { + return BlockVector3.at(getX(), min, getZ()); } - if (y > max) { - return BlockVector3.at(x, max, z); + if (getY() > max) { + return BlockVector3.at(getX(), max, getZ()); } return this; } @@ -512,7 +484,7 @@ public class BlockVector3 { * @return a new vector */ public BlockVector3 abs() { - return BlockVector3.at(Math.abs(x), Math.abs(y), Math.abs(z)); + return BlockVector3.at(Math.abs(getX()), Math.abs(getY()), Math.abs(getZ())); } /** @@ -528,8 +500,8 @@ public class BlockVector3 { */ public BlockVector3 transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { angle = Math.toRadians(angle); - double x = this.x - aboutX; - double z = this.z - aboutZ; + double x = this.getX() - aboutX; + double z = this.getZ() - aboutZ; double cos = Math.cos(angle); double sin = Math.sin(angle); double x2 = x * cos - z * sin; @@ -537,7 +509,7 @@ public class BlockVector3 { return BlockVector3.at( x2 + aboutX + translateX, - y, + getY(), z2 + aboutZ + translateZ ); } @@ -583,10 +555,10 @@ public class BlockVector3 { * @return minimum */ public BlockVector3 getMinimum(BlockVector3 v2) { - return new BlockVector3( - Math.min(x, v2.x), - Math.min(y, v2.y), - Math.min(z, v2.z) + return new BlockVector3Imp( + Math.min(getX(), v2.getX()), + Math.min(getY(), v2.getY()), + Math.min(getZ(), v2.getZ()) ); } @@ -597,10 +569,10 @@ public class BlockVector3 { * @return maximum */ public BlockVector3 getMaximum(BlockVector3 v2) { - return new BlockVector3( - Math.max(x, v2.x), - Math.max(y, v2.y), - Math.max(z, v2.z) + return new BlockVector3Imp( + Math.max(getX(), v2.getX()), + Math.max(getY(), v2.getY()), + Math.max(getZ(), v2.getZ()) ); } @@ -610,31 +582,34 @@ public class BlockVector3 { * @return a new {@link BlockVector2} */ public BlockVector2 toBlockVector2() { - return BlockVector2.at(x, z); + return BlockVector2.at(getX(), getZ()); } public Vector3 toVector3() { - return Vector3.at(x, y, z); + return Vector3.at(getX(), getY(), getZ()); } @Override - public boolean equals(Object obj) { + public final boolean equals(Object obj) { if (!(obj instanceof BlockVector3)) { return false; } - BlockVector3 other = (BlockVector3) obj; - return other.x == this.x && other.y == this.y && other.z == this.z; + return equals((BlockVector3) obj); + } + + public final boolean equals(BlockVector3 other) { + return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); } @Override public int hashCode() { - return (x ^ (z << 12)) ^ (y << 24); + return (getX() ^ (getZ() << 12)) ^ (getY() << 24); } @Override public String toString() { - return "(" + x + ", " + y + ", " + z + ")"; + return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java new file mode 100644 index 000000000..69a148401 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3Imp.java @@ -0,0 +1,87 @@ +/* + * 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.math; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ComparisonChain; +import com.sk89q.worldedit.math.transform.AffineTransform; + +import java.util.Comparator; + +/** + * An immutable 3-dimensional vector. + */ +public class BlockVector3Imp extends BlockVector3 { + + public static final BlockVector3Imp ZERO = new BlockVector3Imp(0, 0, 0); + public static final BlockVector3Imp UNIT_X = new BlockVector3Imp(1, 0, 0); + public static final BlockVector3Imp UNIT_Y = new BlockVector3Imp(0, 1, 0); + public static final BlockVector3Imp UNIT_Z = new BlockVector3Imp(0, 0, 1); + public static final BlockVector3Imp ONE = new BlockVector3Imp(1, 1, 1); + + public static BlockVector3Imp at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static BlockVector3Imp at(int x, int y, int z) { + return new BlockVector3Imp(x, y, z); + } + + private final int x, y, z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param z the Z coordinate + */ + protected BlockVector3Imp(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public final int getZ() { + return z; + } + + @Override + public int hashCode() { + return (getX() ^ (getZ() << 12)) ^ (getY() << 24); + } + + @Override + public String toString() { + return "(" + getX() + ", " + getY() + ", " + getZ() + ")"; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java index 89ee154f5..f065b905b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MutableBlockVector3.java @@ -9,6 +9,14 @@ public class MutableBlockVector3 extends BlockVector3 { } }; + public static MutableBlockVector3 at(double x, double y, double z) { + return at((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z)); + } + + public static MutableBlockVector3 at(int x, int y, int z) { + return new MutableBlockVector3(x, y, z); + } + public static MutableBlockVector3 get(int x, int y, int z) { return MUTABLE_CACHE.get().setComponents(x, y, z); } @@ -16,15 +24,19 @@ public class MutableBlockVector3 extends BlockVector3 { public MutableBlockVector3() {} public MutableBlockVector3(BlockVector3 other) { - super(other.getX(), other.getY(), other.getZ()); + this(other.getX(), other.getY(), other.getZ()); } public MutableBlockVector3 setComponents(BlockVector3 other) { return setComponents(other.getBlockX(), other.getBlockY(), other.getBlockZ()); } + private int x,y,z; + public MutableBlockVector3(int x, int y, int z) { - super(x, y, z); + this.x = x; + this.y = y; + this.z = z; } @Override @@ -35,6 +47,21 @@ public class MutableBlockVector3 extends BlockVector3 { return this; } + @Override + public final int getX() { + return x; + } + + @Override + public final int getY() { + return y; + } + + @Override + public final int getZ() { + return z; + } + @Override public MutableBlockVector3 mutX(double x) { this.x = (int) x; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index cc5b4be68..cbfb6be0e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -91,11 +91,6 @@ public abstract class AbstractWorld implements World { return false; } - @Override - public BlockState getLazyBlock(BlockVector3 position) { - return getBlock(position); - } - @Override public boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority) { if (taskId == -1) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 886dee7cc..18ca8fbdf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.boydti.fawe.beta.FilterBlock; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; @@ -47,9 +48,7 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class BaseBlock implements BlockStateHolder { private final BlockState blockState; - - @Nullable - protected CompoundTag nbtData; + private final CompoundTag nbtData; @Deprecated public BaseBlock() { @@ -83,6 +82,7 @@ public class BaseBlock implements BlockStateHolder { public BaseBlock(BlockState blockState) { this.blockState = blockState; + nbtData = null; } /** @@ -157,7 +157,7 @@ public class BaseBlock implements BlockStateHolder { @Override public void setNbtData(@Nullable CompoundTag nbtData) { - this.nbtData = nbtData; + throw new UnsupportedOperationException("Immutable"); } /** @@ -202,7 +202,7 @@ public class BaseBlock implements BlockStateHolder { } @Override - public int getOrdinal() { + public final int getOrdinal() { return blockState.getOrdinal(); } @@ -227,6 +227,10 @@ public class BaseBlock implements BlockStateHolder { } } + public BlockState toBlockState() { + return blockState; + } + @Override public int hashCode() { return getOrdinal(); @@ -246,7 +250,12 @@ public class BaseBlock implements BlockStateHolder { return extent.setBlock(set, this); } - @Override + @Override + public void apply(FilterBlock block) { + block.setFullBlock(this); + } + + @Override public boolean hasNbtData() { return this.nbtData != null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 3aef40e27..041faa865 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.world.block; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.command.SuggestInputParseException; import com.boydti.fawe.object.string.MutableCharSequence; import com.boydti.fawe.util.StringMan; @@ -62,7 +63,7 @@ public class BlockState implements BlockStateHolder, FawePattern { this.internalId = internalId; this.ordinal = ordinal; this.ordinalChar = (char) ordinal; - this.emptyBaseBlock = new BaseBlock(this); + this.emptyBaseBlock = new ImmutableBaseBlock(this); } /** @@ -218,6 +219,11 @@ public class BlockState implements BlockStateHolder, FawePattern { return extent.setBlock(set, this); } + @Override + public final void apply(FilterBlock block) { + block.setOrdinal(ordinal); + } + @Override public BaseBlock apply(BlockVector3 position) { return this.toBaseBlock(); @@ -333,7 +339,7 @@ public class BlockState implements BlockStateHolder, FawePattern { } @Override - public int getOrdinal() { + public final int getOrdinal() { return this.ordinal; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java index 7a5f89f73..de459a6db 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.world.block; import static com.google.common.base.Preconditions.checkArgument; +import com.boydti.fawe.beta.FilterBlock; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; @@ -45,7 +46,7 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; -public class BlockType implements FawePattern { +public final class BlockType implements FawePattern { private final String id; private final BlockTypes.Settings settings; @@ -179,7 +180,7 @@ public class BlockType implements FawePattern { * * @return The default state */ - public BlockState getDefaultState() { + public final BlockState getDefaultState() { return this.settings.defaultState; } @@ -306,6 +307,11 @@ public class BlockType implements FawePattern { return this.getDefaultState().toBaseBlock(); } + @Override + public final void apply(FilterBlock block) { + block.setOrdinal(getDefaultState().getOrdinal()); + } + public Mask toMask(Extent extent) { return new SingleBlockTypeMask(extent, this); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java new file mode 100644 index 000000000..f738aa6f7 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/ImmutableBaseBlock.java @@ -0,0 +1,28 @@ +package com.sk89q.worldedit.world.block; + +import com.boydti.fawe.beta.FilterBlock; +import com.sk89q.jnbt.CompoundTag; + +import javax.annotation.Nullable; + +public final class ImmutableBaseBlock extends BaseBlock { + public ImmutableBaseBlock(BlockState blockState) { + super(blockState); + } + + @Nullable + @Override + public CompoundTag getNbtData() { + return null; + } + + @Override + public boolean hasNbtData() { + return false; + } + + @Override + public final void apply(FilterBlock block) { + block.setOrdinal(getOrdinal()); + } +}