From 274c52163b1fc09adf9064403f60dd4dda0fb92e Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 17 Apr 2019 01:12:09 +1000 Subject: [PATCH] Fix setting the same block multiple times sequencially --- .../adapter/v1_13_1/Spigot_v1_13_R2.java | 1 + .../fawe/bukkit/v0/BukkitChunk_All.java | 4 +- .../v0/BukkitChunk_All_ReadonlySnapshot.java | 4 +- .../fawe/bukkit/v1_13/BukkitChunk_1_13.java | 62 ++++- .../bukkit/v1_13/BukkitChunk_1_13_Copy.java | 90 ------- .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 6 +- .../com/boydti/fawe/example/IntFaweChunk.java | 49 ++-- .../fawe/example/NullQueueIntFaweChunk.java | 4 +- .../fawe/example/SimpleIntFaweChunk.java | 4 +- .../fawe/object/changeset/FaweChangeSet.java | 12 +- .../fawe/object/collection/ObjObjMap.java | 233 ++++++++++++++++++ .../java/com/sk89q/worldedit/EditSession.java | 63 +++-- 12 files changed, 382 insertions(+), 150 deletions(-) delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13_Copy.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/ObjObjMap.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java index 876e79521..1d3b5fb53 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/v1_13_1/Spigot_v1_13_R2.java @@ -20,6 +20,7 @@ package com.boydti.fawe.bukkit.adapter.v1_13_1; import com.boydti.fawe.Fawe; +import com.boydti.fawe.object.collection.ObjObjMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.sk89q.jnbt.Tag; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java index ee803e4ca..f9cc87dc6 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java @@ -65,10 +65,10 @@ public class BukkitChunk_All extends IntFaweChunk { public IntFaweChunk copy(boolean shallow) { BukkitChunk_All copy; if (shallow) { - copy = new BukkitChunk_All(getParent(), getX(), getZ(), ids, count, air); + copy = new BukkitChunk_All(getParent(), getX(), getZ(), setBlocks, count, air); copy.biomes = biomes; } else { - copy = new BukkitChunk_All(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); + copy = new BukkitChunk_All(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); copy.biomes = biomes != null ? biomes.clone() : null; } copy.chunk = chunk; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java index e00bb7ca7..4ed7a4e9a 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All_ReadonlySnapshot.java @@ -1,6 +1,5 @@ package com.boydti.fawe.bukkit.v0; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; @@ -10,7 +9,6 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import java.util.*; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockTypes; import org.bukkit.ChunkSnapshot; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -75,7 +73,7 @@ public class BukkitChunk_All_ReadonlySnapshot extends FaweChunk { @Nullable @Override public int[] getIdArray(int layer) { - int[] nextLayer = next.ids[layer]; + int[] nextLayer = next.setBlocks[layer]; if (nextLayer == null) return null; int[] ids = Arrays.copyOf(nextLayer, nextLayer.length); int index = 0; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java index 30ab4e66b..6940f06ee 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13.java @@ -6,6 +6,7 @@ import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.config.Settings; import com.boydti.fawe.example.IntFaweChunk; +import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MainUtil; @@ -60,6 +61,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter; import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryb; import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryc; import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryd; @@ -69,6 +71,7 @@ import static com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13.fieldRegistryf; public class BukkitChunk_1_13 extends IntFaweChunk { public ChunkSection[] sectionPalettes; + private static final IBlockData AIR = ((BlockMaterial_1_13) BlockTypes.AIR.getMaterial()).getState(); /** @@ -97,6 +100,52 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } } + @Override + public int[][] getCombinedIdArrays() { + if (this.sectionPalettes != null) { + for (int i = 0; i < setBlocks.length; i++) { + getIdArray(i); + } + } + return this.setBlocks; + } + + @Override + public int[] getIdArray(int layer) { + if (this.setBlocks[layer] == null && this.sectionPalettes != null) { + ChunkSection section = this.sectionPalettes[layer]; + int[] idsArray = this.setBlocks[layer]; + if (section != null && idsArray == null) { + this.setBlocks[layer] = idsArray = new int[4096]; + if (!section.a()) { + try { + DataPaletteBlock blocks = section.getBlocks(); + DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); + DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); + + long[] raw = bits.a(); + int bitsPerEntry = bits.c(); + + new BitArray4096(raw, bitsPerEntry).toRaw(idsArray); + IBlockData defaultBlock = (IBlockData) BukkitQueue_1_13.fieldDefaultBlock.get(blocks); + // TODO optimize away palette.a + for (int i = 0; i < 4096; i++) { + IBlockData ibd = palette.a(idsArray[i]); + if (ibd == null) { + ibd = defaultBlock; + } + int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); + idsArray[i] = BlockTypes.states[ordinal].getInternalId(); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } + return this.setBlocks[layer]; + } + public boolean storeTile(TileEntity tile, BlockPosition pos) { CompoundTag nativeTag = getParent().getTag(tile); setTile(pos.getX() & 15, pos.getY(), pos.getZ() & 15, nativeTag); @@ -216,11 +265,11 @@ public class BukkitChunk_1_13 extends IntFaweChunk { public IntFaweChunk copy(boolean shallow) { BukkitChunk_1_13 copy; if (shallow) { - copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), ids, count, air); + copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), setBlocks, count, air); copy.biomes = biomes; copy.chunk = chunk; } else { - copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); + copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); copy.biomes = biomes != null ? biomes.clone() : null; copy.chunk = chunk; } @@ -281,7 +330,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { public FaweChunk call() { Spigot_v1_13_R2 adapter = (Spigot_v1_13_R2) BukkitQueue_0.getAdapter(); try { - BukkitChunk_1_13_Copy copy = getParent().getChangeTask() != null ? new BukkitChunk_1_13_Copy(getParent(), getX(), getZ()) : null; + BukkitChunk_1_13 copy = getParent().getChangeTask() != null ? new BukkitChunk_1_13(getParent(), getX(), getZ()) : null; final Chunk chunk = this.getChunk(); final World world = chunk.getWorld(); Settings settings = getParent().getSettings(); @@ -439,7 +488,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { section = sections[j] = getParent().newChunkSection(j, flag, array); continue; } - } else if (count >= 4096) { + } else if (count >= 4096 && false) { if (countAir >= 4096) { sections[j] = null; continue; @@ -452,6 +501,11 @@ public class BukkitChunk_1_13 extends IntFaweChunk { continue; } } + if (count >= 4096) { + for (int i = 0; i < 4096; i++) { + if (array[i] == 0) System.out.println("Invalid "); + } + } int by = j << 4; DataPaletteBlock nibble = section.getBlocks(); int nonEmptyBlockCount = 0; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13_Copy.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13_Copy.java deleted file mode 100644 index afc4faaff..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13_Copy.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13; - -import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2; -import com.boydti.fawe.jnbt.anvil.BitArray4096; -import com.boydti.fawe.object.FaweQueue; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataBits; -import net.minecraft.server.v1_13_R2.DataPalette; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.IBlockData; - -import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter; - -public class BukkitChunk_1_13_Copy extends BukkitChunk_1_13 { - public BukkitChunk_1_13_Copy(FaweQueue parent, int x, int z) { - super(parent, x, z); - } - - @Override - public int[][] getCombinedIdArrays() { - if (this.sectionPalettes == null) { - return this.ids; - } - for (int i = 0; i < ids.length; i++) { - getIdArray(i); - } - return super.getCombinedIdArrays(); - } - - @Override - public int[] getIdArray(int layer) { - if (this.sectionPalettes != null) { - ChunkSection section = this.sectionPalettes[layer]; - int[] idsArray = this.ids[layer]; - if (section != null && idsArray == null) { - idsArray = new int[4096]; - if (!section.a()) { - try { - DataPaletteBlock blocks = section.getBlocks(); - DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks); - DataPalette palette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(blocks); - - long[] raw = bits.a(); - int bitsPerEntry = bits.c(); - - new BitArray4096(raw, bitsPerEntry).toRaw(idsArray); - IBlockData defaultBlock = (IBlockData) BukkitQueue_1_13.fieldDefaultBlock.get(blocks); - // TODO optimize away palette.a - for (int i = 0; i < 4096; i++) { - IBlockData ibd = palette.a(idsArray[i]); - if (ibd == null) { - ibd = defaultBlock; - } - int ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); - idsArray[i] = BlockTypes.states[ordinal].getInternalId(); - } - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - return idsArray; - } - return null; - } - - @Override - public > void setBlock(int x, int y, int z, B block) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public void setBiome(BiomeType biome) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public void setBiome(int x, int z, BiomeType biome) { - throw new UnsupportedOperationException("Read only"); - } - - @Override - public void setBlock(int x, int y, int z, int combinedId) { - throw new UnsupportedOperationException("Read only"); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java index 6c5e712f1..3cc50d56e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -879,7 +879,11 @@ public class BukkitQueue_1_13 extends BukkitQueue_0> 6; if (num_palette == 1) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java index d435f4aa8..cb4b27644 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/example/IntFaweChunk.java @@ -1,19 +1,17 @@ package com.boydti.fawe.example; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockTypes; import java.util.*; public abstract class IntFaweChunk extends FaweChunk { - public final int[][] ids; + public final int[][] setBlocks; public final short[] count; public final short[] air; @@ -24,9 +22,9 @@ public abstract class IntFaweChunk extends FaweChunk public T chunk; - public IntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { + public IntFaweChunk(FaweQueue parent, int x, int z, int[][] setBlocks, short[] count, short[] air) { super(parent, x, z); - this.ids = ids; + this.setBlocks = setBlocks; this.count = count; this.air = air; } @@ -40,7 +38,7 @@ public abstract class IntFaweChunk extends FaweChunk */ public IntFaweChunk(FaweQueue parent, int x, int z) { super(parent, x, z); - this.ids = new int[HEIGHT >> 4][]; + this.setBlocks = new int[HEIGHT >> 4][]; this.count = new short[HEIGHT >> 4]; this.air = new short[HEIGHT >> 4]; } @@ -103,8 +101,8 @@ public abstract class IntFaweChunk extends FaweChunk @Override public int getBitMask() { int bitMask = 0; - for (int section = 0; section < ids.length; section++) { - if (ids[section] != null) { + for (int section = 0; section < setBlocks.length; section++) { + if (setBlocks[section] != null) { bitMask += 1 << section; } } @@ -119,12 +117,12 @@ public abstract class IntFaweChunk extends FaweChunk */ @Override public int[] getIdArray(final int i) { - return this.ids[i]; + return this.setBlocks[i]; } @Override public int[][] getCombinedIdArrays() { - return this.ids; + return this.setBlocks; } @Override @@ -193,18 +191,37 @@ public abstract class IntFaweChunk extends FaweChunk @Override public void setBlock(int x, int y, int z, int combinedId) { final int i = y >> 4; - int[] vs = this.ids[i]; + int[] vs = this.setBlocks[i]; if (vs == null) { - vs = this.ids[i] = new int[4096]; + vs = this.setBlocks[i] = new int[4096]; } - vs[(((y & 15) << 8) | (z << 4) | x)] = combinedId; - this.count[i]++; - switch (combinedId) { + int index = (((y & 15) << 8) | (z << 4) | x); + int existing = vs[index]; + vs[index] = combinedId; + switch (existing) { case 0: + this.count[i]++; + switch (combinedId) { + case 0: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + this.air[i]++; + } + break; case BlockID.AIR: case BlockID.CAVE_AIR: case BlockID.VOID_AIR: - this.air[i]++; + switch (combinedId) { + case 0: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + break; + default: + this.air[i]--; + + } } return; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java index d86146b33..f1c31df3f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/example/NullQueueIntFaweChunk.java @@ -21,9 +21,9 @@ public class NullQueueIntFaweChunk extends IntFaweChunk { @Override public IntFaweChunk copy(boolean shallow) { if (shallow) { - return new NullQueueIntFaweChunk(getX(), getZ(), ids, count, air); + return new NullQueueIntFaweChunk(getX(), getZ(), setBlocks, count, air); } else { - return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); + return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java index 1abe2429e..6012e9782 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/example/SimpleIntFaweChunk.java @@ -23,10 +23,10 @@ public class SimpleIntFaweChunk extends IntFaweChunk { public IntFaweChunk copy(boolean shallow) { SimpleIntFaweChunk copy; if (shallow) { - copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), ids, count, air); + copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), setBlocks, count, air); copy.biomes = biomes; } else { - copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); + copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(setBlocks), count.clone(), air.clone()); copy.biomes = biomes != null ? biomes.clone() : null; } return copy; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java index 8600e4bba..75161e5f4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java @@ -302,10 +302,16 @@ public abstract class FaweChangeSet implements ChangeSet { switch (combinedIdCurrent) { case 0: continue; - case 1: - combinedIdCurrent = 0; default: - int combinedIdPrevious = previousLayer != null ? previousLayer[index] : BlockID.AIR; + int combinedIdPrevious; + if (previousLayer != null) { + combinedIdPrevious = previousLayer[index]; + if (combinedIdPrevious == 0) { + combinedIdPrevious = BlockID.AIR; + } + } else { + combinedIdPrevious = BlockID.AIR; + } if (combinedIdCurrent != combinedIdPrevious) { add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ObjObjMap.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ObjObjMap.java new file mode 100644 index 000000000..6e97f7a7c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ObjObjMap.java @@ -0,0 +1,233 @@ +package com.boydti.fawe.object.collection; + +import javax.annotation.Nonnull; +import java.util.Arrays; + +import static it.unimi.dsi.fastutil.HashCommon.arraySize; + +public class ObjObjMap +{ + private static final Object FREE_KEY = new Object(); + private static final Object REMOVED_KEY = new Object(); + + /** Keys and values */ + private Object[] m_data; + + /** Value for the null key (if inserted into a map) */ + private Object m_nullValue; + private boolean m_hasNull; + + /** Fill factor, must be between (0 and 1) */ + private final float m_fillFactor; + /** We will resize a map once it reaches this size */ + private int m_threshold; + /** Current map size */ + private int m_size; + /** Mask to calculate the original position */ + private int m_mask; + /** Mask to wrap the actual array pointer */ + private int m_mask2; + + public ObjObjMap( final int size, final float fillFactor ) + { + if ( fillFactor <= 0 || fillFactor >= 1 ) + throw new IllegalArgumentException( "FillFactor must be in (0, 1)" ); + if ( size <= 0 ) + throw new IllegalArgumentException( "Size must be positive!" ); + final int capacity = arraySize(size, fillFactor); + m_mask = capacity - 1; + m_mask2 = capacity * 2 - 1; + m_fillFactor = fillFactor; + + m_data = new Object[capacity * 2]; + Arrays.fill( m_data, FREE_KEY ); + + m_threshold = (int) (capacity * fillFactor); + } + + public V get( @Nonnull final K key ) + { +// if ( key == null ) +// return (V) m_nullValue; //we null it on remove, so safe not to check a flag here + + int ptr = (key.hashCode() & m_mask) << 1; + Object k = m_data[ ptr ]; + +// if ( k == FREE_KEY ) +// return null; //end of chain already + if ( k == ( key ) ) //we check FREE and REMOVED prior to this call + return (V) m_data[ ptr + 1 ]; + while ( true ) + { + ptr = (ptr + 2) & m_mask2; //that's next index + k = m_data[ ptr ]; +// if ( k == FREE_KEY ) +// return null; + if ( k == ( key ) ) + return (V) m_data[ ptr + 1 ]; + } + } + + public V put( final K key, final V value ) + { + if ( key == null ) + return insertNullKey(value); + + int ptr = getStartIndex(key) << 1; + Object k = m_data[ptr]; + + if ( k == FREE_KEY ) //end of chain already + { + m_data[ ptr ] = key; + m_data[ ptr + 1 ] = value; + if ( m_size >= m_threshold ) + rehash( m_data.length * 2 ); //size is set inside + else + ++m_size; + return null; + } + else if ( k == ( key ) ) //we check FREE and REMOVED prior to this call + { + final Object ret = m_data[ ptr + 1 ]; + m_data[ ptr + 1 ] = value; + return (V) ret; + } + + int firstRemoved = -1; + if ( k == REMOVED_KEY ) + firstRemoved = ptr; //we may find a key later + + while ( true ) + { + ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation + k = m_data[ ptr ]; + if ( k == FREE_KEY ) + { + if ( firstRemoved != -1 ) + ptr = firstRemoved; + m_data[ ptr ] = key; + m_data[ ptr + 1 ] = value; + if ( m_size >= m_threshold ) + rehash( m_data.length * 2 ); //size is set inside + else + ++m_size; + return null; + } + else if ( k == ( key ) ) + { + final Object ret = m_data[ ptr + 1 ]; + m_data[ ptr + 1 ] = value; + return (V) ret; + } + else if ( k == REMOVED_KEY ) + { + if ( firstRemoved == -1 ) + firstRemoved = ptr; + } + } + } + + public V remove( final K key ) + { + if ( key == null ) + return removeNullKey(); + + int ptr = getStartIndex(key) << 1; + Object k = m_data[ ptr ]; + if ( k == FREE_KEY ) + return null; //end of chain already + else if ( k == ( key ) ) //we check FREE and REMOVED prior to this call + { + --m_size; + if ( m_data[ ( ptr + 2 ) & m_mask2 ] == FREE_KEY ) + m_data[ ptr ] = FREE_KEY; + else + m_data[ ptr ] = REMOVED_KEY; + final V ret = (V) m_data[ ptr + 1 ]; + m_data[ ptr + 1 ] = null; + return ret; + } + while ( true ) + { + ptr = ( ptr + 2 ) & m_mask2; //that's next index calculation + k = m_data[ ptr ]; + if ( k == FREE_KEY ) + return null; + else if ( k == ( key ) ) + { + --m_size; + if ( m_data[ ( ptr + 2 ) & m_mask2 ] == FREE_KEY ) + m_data[ ptr ] = FREE_KEY; + else + m_data[ ptr ] = REMOVED_KEY; + final V ret = (V) m_data[ ptr + 1 ]; + m_data[ ptr + 1 ] = null; + return ret; + } + } + } + + private V insertNullKey(final V value) + { + if ( m_hasNull ) + { + final Object ret = m_nullValue; + m_nullValue = value; + return (V) ret; + } + else + { + m_nullValue = value; + ++m_size; + return null; + } + } + + private V removeNullKey() + { + if ( m_hasNull ) + { + final Object ret = m_nullValue; + m_nullValue = null; + m_hasNull = false; + --m_size; + return (V) ret; + } + else + { + return null; + } + } + + public int size() + { + return m_size; + } + + private void rehash( final int newCapacity ) + { + m_threshold = (int) (newCapacity/2 * m_fillFactor); + m_mask = newCapacity/2 - 1; + m_mask2 = newCapacity - 1; + + final int oldCapacity = m_data.length; + final Object[] oldData = m_data; + + m_data = new Object[ newCapacity ]; + Arrays.fill( m_data, FREE_KEY ); + + m_size = m_hasNull ? 1 : 0; + + for ( int i = 0; i < oldCapacity; i += 2 ) { + final Object oldKey = oldData[ i ]; + if( oldKey != FREE_KEY && oldKey != REMOVED_KEY ) + put( (K)oldKey, (V)oldData[ i + 1 ]); + } + } + + public int getStartIndex( final Object key ) + { + //key is not null here + return key.hashCode() & m_mask; + } +} \ No newline at end of file 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 9514d18c6..508c0dd8a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -2484,6 +2484,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int makeSphere(final BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, final boolean filled) { + System.out.println("Make sphere"); radiusX += 0.5; radiusY += 0.5; radiusZ += 0.5; @@ -2500,35 +2501,37 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, final int ceilRadiusY = (int) Math.ceil(radiusY); final int ceilRadiusZ = (int) Math.ceil(radiusZ); - double nextXn = 0; - double dx, dy, dz, dxy, dxyz; + double nextXn = invRadiusX; + double dx, dy, dz, dxz, dxyz; forX: for (int x = 0; x <= ceilRadiusX; ++x) { final double xn = nextXn; dx = xn * xn; nextXn = (x + 1) * invRadiusX; - double nextYn = 0; - forY: - for (int y = 0; y <= ceilRadiusY; ++y) { - final double yn = nextYn; - dy = yn * yn; - dxy = dx + dy; - nextYn = (y + 1) * invRadiusY; - double nextZn = 0; - forZ: - for (int z = 0; z <= ceilRadiusZ; ++z) { - final double zn = nextZn; - dz = zn * zn; - dxyz = dxy + dz; - nextZn = (z + 1) * invRadiusZ; + double nextZn = invRadiusZ; + forZ: + for (int z = 0; z <= ceilRadiusZ; ++z) { + final double zn = nextZn; + dz = zn * zn; + dxz = dx + dz; + nextZn = (z + 1) * invRadiusZ; + double nextYn = invRadiusY; + + forY: + for (int y = 0; y <= ceilRadiusY; ++y) { + final double yn = nextYn; + dy = yn * yn; + dxyz = dxz + dy; + nextYn = (y + 1) * invRadiusY; + if (dxyz > 1) { - if (z == 0) { - if (y == 0) { + if (y == 0) { + if (z == 0) { break forX; } - break forY; + break forZ; } - break forZ; + break forY; } if (!filled) { @@ -2538,13 +2541,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } this.setBlock(px + x, py + y, pz + z, block); - this.setBlock(px - x, py + y, pz + z, block); - this.setBlock(px + x, py - y, pz + z, block); - this.setBlock(px + x, py + y, pz - z, block); - this.setBlock(px - x, py - y, pz + z, block); - this.setBlock(px + x, py - y, pz - z, block); - this.setBlock(px - x, py + y, pz - z, block); - this.setBlock(px - x, py - y, pz - z, block); + if (x != 0) this.setBlock(px - x, py + y, pz + z, block); + if (z != 0) { + this.setBlock(px + x, py + y, pz - z, block); + if (x != 0) this.setBlock(px - x, py + y, pz - z, block); + } + if (y != 0) { + this.setBlock(px + x, py - y, pz + z, block); + if (x != 0) this.setBlock(px - x, py - y, pz + z, block); + if (z != 0) { + this.setBlock(px + x, py - y, pz - z, block); + if (x != 0) this.setBlock(px - x, py - y, pz - z, block); + } + } } } }