diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index fd9b780c7..603600ffd 100644 Binary files a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar and b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar differ diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java index 1119ed431..c42d51677 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightmapProcessor.java @@ -61,8 +61,9 @@ public class HeightmapProcessor implements IBatchProcessor { if (!(hasSectionSet || hasSectionGet)) { continue; } - char[] setSection = hasSectionSet ? set.load(layer) : null; - if (Arrays.equals(setSection, FaweCache.IMP.EMPTY_CHAR_4096) || Arrays.equals(setSection, AIR_LAYER)) { + char[] setSection = hasSectionSet ? set.loadIfPresent(layer) : null; + if (setSection == null || Arrays.equals(setSection, FaweCache.IMP.EMPTY_CHAR_4096) || + Arrays.equals(setSection, AIR_LAYER)) { hasSectionSet = false; } if (!hasSectionSet && !hasSectionGet) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 76a9052bc..98928dcc6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.world.block.BlockState; import java.io.IOException; import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.Future; @@ -170,7 +171,8 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { System.arraycopy(tmp, 0, (blocksGet = new char[4096]), 0, 4096); } char[] blocksSet; - System.arraycopy(set.load(layer), 0, (blocksSet = new char[4096]), 0, 4096); + // loadIfPresent shouldn't be null if set.hasSection(layer) is true + System.arraycopy(Objects.requireNonNull(set.loadIfPresent(layer)), 0, (blocksSet = new char[4096]), 0, 4096); // Account for negative layers int by = layer << 4; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index 218ecc203..6770c706c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -44,10 +44,14 @@ public interface IBatchProcessor { for (int layer = set.getMinSectionPosition(); layer <= minLayer; layer++) { if (set.hasSection(layer)) { if (layer == minLayer) { - char[] arr = set.load(layer); - int index = (minY & 15) << 8; - for (int i = 0; i < index; i++) { - arr[i] = 0; + char[] arr = set.loadIfPresent(layer); + if (arr != null) { + int index = (minY & 15) << 8; + for (int i = 0; i < index; i++) { + arr[i] = 0; + } + } else { + arr = new char[4096]; } set.setBlocks(layer, arr); } else { @@ -59,10 +63,14 @@ public interface IBatchProcessor { for (int layer = maxLayer; layer < set.getMaxSectionPosition(); layer++) { if (set.hasSection(layer)) { if (layer == minLayer) { - char[] arr = set.load(layer); - int index = ((maxY + 1) & 15) << 8; - for (int i = index; i < arr.length; i++) { - arr[i] = 0; + char[] arr = set.loadIfPresent(layer); + if (arr != null) { + int index = ((maxY + 1) & 15) << 8; + for (int i = index; i < arr.length; i++) { + arr[i] = 0; + } + } else { + arr = new char[4096]; } set.setBlocks(layer, arr); } else { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java index a482af14f..2b4eb84f1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java @@ -12,6 +12,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.registry.BlockRegistry; +import javax.annotation.Nullable; import java.io.IOException; import java.util.Map; import java.util.Set; @@ -31,8 +32,26 @@ public interface IBlocks extends Trimable { */ boolean hasSection(int layer); + /** + * Obtain the specified chunk section stored as an array of ordinals. Uses normal minecraft chunk-section position indices + * (length 4096). Operations synchronises on the section and will load the section into memory if not present. For chunk + * GET operations, this will load the data from the world. For chunk SET, this will create a new empty array. + * + * @param layer chunk section layer (may be negative) + * @return char array of ordinals of the chunk section + */ char[] load(int layer); + /** + * Obtain the specified chunk section stored as an array of ordinals if present or null. Uses normal minecraft chunk-section + * position indices (length 4096). Does not synchronise to the section layer as it will not attempt to load into memory. + * + * @param layer chunk section layer (may be negative) + * @return char array of ordinals of the chunk section if present + */ + @Nullable + char[] loadIfPresent(int layer); + BlockState getBlock(int x, int y, int z); Map getTiles(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java index 872317de3..efa635626 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java @@ -10,6 +10,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collections; import java.util.Map; @@ -38,7 +39,6 @@ public class BitSetBlocks implements IChunkSet { return row.rows[layer] != MemBlockSet.NULL_ROW_Y; } - @Override public boolean setBiome(int x, int y, int z, BiomeType biome) { return false; @@ -153,6 +153,13 @@ public class BitSetBlocks implements IChunkSet { return arr; } + // No need to do anything different + @Nullable + @Override + public char[] loadIfPresent(final int layer) { + return load(layer); + } + @Override public BiomeType[] getBiomes() { return null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java index 952a2fb3a..8bcd9d484 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java @@ -147,6 +147,16 @@ public abstract class CharBlocks implements IBlocks { } } + @Nullable + @Override + public char[] loadIfPresent(int layer) { + if (layer < minSectionPosition || layer > maxSectionPosition) { + return null; + } + layer -= minSectionPosition; + return sections[layer].isFull() ? blocks[layer] : null; + } + @Override public BlockState getBlock(int x, int y, int z) { return BlockTypesCache.states[get(x, y, z)]; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java index 22f101a82..eea966ebc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/NullChunkGet.java @@ -127,6 +127,12 @@ public final class NullChunkGet implements IChunkGet { return FaweCache.IMP.EMPTY_CHAR_4096; } + @Nullable + @Override + public char[] loadIfPresent(final int layer) { + return null; + } + public boolean hasSection(int layer) { return false; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java index 04f5e657e..4496a9aa0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java @@ -121,6 +121,12 @@ public class ChunkHolder> implements IQueueChunk { return getOrCreateGet().load(layer); } + @Nullable + @Override + public char[] loadIfPresent(final int layer) { + return getOrCreateGet().loadIfPresent(layer); + } + @Override public boolean isFastMode() { return fastmode; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java index 4f1b826f3..9b6d72b95 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java @@ -172,6 +172,12 @@ public final class NullChunk implements IQueueChunk { return null; } + @Nullable + @Override + public char[] loadIfPresent(final int layer) { + return null; + } + @Nullable public CompoundTag getEntity(@Nonnull UUID uuid) { return null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index 28228589f..fb4c816cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -37,6 +37,7 @@ import javax.annotation.Nonnull; import java.util.AbstractSet; import java.util.Iterator; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; @@ -769,7 +770,7 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { for (int layer = get.getMinSectionPosition(); layer < get.getMaxSectionPosition(); layer++) { if (set.hasSection(layer)) { - char[] arr = set.load(layer); + char[] arr = Objects.requireNonNull(set.loadIfPresent(layer)); // This shouldn't be null if above is true if (trimX || trimZ) { int indexY = 0; for (int y = 0; y < 16; y++, indexY += 256) { // For each y layer within a chunk section