From 1e16095cba377b09cb60611eb2f457fc29b58627 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Mon, 4 Nov 2019 07:47:31 +0000 Subject: [PATCH] Fix palette / region iteration --- .../adapter/mc1_14/BukkitAdapter_1_14.java | 10 ++- .../adapter/mc1_14/BukkitGetBlocks_1_14.java | 12 +++ .../adapter/mc1_14/MapChunkUtil_1_14.java | 17 +++- .../main/java/com/boydti/fawe/FaweCache.java | 10 ++- .../java/com/boydti/fawe/beta/IBlocks.java | 51 ++++++----- .../filter/block/CharFilterBlock.java | 2 +- .../implementation/packet/ChunkPacket.java | 3 +- .../processors/ChunkSendProcessor.java | 5 +- .../sk89q/worldedit/regions/CuboidRegion.java | 84 +++++++++++++------ 9 files changed, 138 insertions(+), 56 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java index c38f130dd..ffa77ee9d 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitAdapter_1_14.java @@ -249,6 +249,13 @@ public final class BukkitAdapter_1_14 { case 0: ordinal = getArr[i]; set[i] = ordinal; + switch (ordinal) { + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + air++; + } + break; case BlockID.AIR: case BlockID.CAVE_AIR: case BlockID.VOID_AIR: @@ -270,12 +277,11 @@ public final class BukkitAdapter_1_14 { private static int createPalette(int[] blockToPalette, int[] paletteToBlock, int[] blocksCopy, int[] num_palette_buffer, char[] set) { int air = 0; int num_palette = 0; - char airOrdinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); for (int i = 0; i < 4096; i++) { char ordinal = set[i]; switch (ordinal) { case 0: - ordinal = airOrdinal; + ordinal = BlockID.AIR; case BlockID.AIR: case BlockID.CAVE_AIR: case BlockID.VOID_AIR: diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java index e4dd1e5f6..34effff64 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import net.minecraft.server.v1_14_R1.BiomeBase; import net.minecraft.server.v1_14_R1.BlockPosition; import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; import net.minecraft.server.v1_14_R1.ChunkSection; import net.minecraft.server.v1_14_R1.DataBits; import net.minecraft.server.v1_14_R1.DataPalette; @@ -35,8 +36,11 @@ import net.minecraft.server.v1_14_R1.DataPaletteLinear; import net.minecraft.server.v1_14_R1.Entity; import net.minecraft.server.v1_14_R1.EntityTypes; import net.minecraft.server.v1_14_R1.IBlockData; +import net.minecraft.server.v1_14_R1.LightEngineThreaded; import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_14_R1.NBTTagInt; +import net.minecraft.server.v1_14_R1.SectionPosition; +import net.minecraft.server.v1_14_R1.SystemUtils; import net.minecraft.server.v1_14_R1.TileEntity; import net.minecraft.server.v1_14_R1.WorldServer; import org.bukkit.World; @@ -47,6 +51,7 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; +import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.Future; @@ -439,6 +444,13 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { }; } +// {//Lighting +// for (int layer = 0; layer < 16; layer++) { +// if (!set.hasSection(layer)) continue; +// //TODO lighting +// } +// } + Runnable callback; if (bitMask == 0) { callback = null; diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java index ce5559f6c..cdd03c251 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/MapChunkUtil_1_14.java @@ -1,16 +1,28 @@ package com.boydti.fawe.bukkit.adapter.mc1_14; import com.boydti.fawe.beta.implementation.packet.ChunkPacket; +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; +import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTInputStream; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.math.BlockVector3; +import net.minecraft.server.v1_14_R1.Chunk; +import net.minecraft.server.v1_14_R1.ChunkSection; import net.minecraft.server.v1_14_R1.NBTBase; import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Map; +import java.util.function.Supplier; public class MapChunkUtil_1_14 { private static final Field fieldX; @@ -42,6 +54,7 @@ public class MapChunkUtil_1_14 { fieldZ.setAccessible(true); fieldBitMask.setAccessible(true); fieldHeightMap.setAccessible(true); + fieldChunkData.setAccessible(true); fieldBlockEntities.setAccessible(true); fieldFull.setAccessible(true); } catch (Throwable e) { @@ -60,7 +73,8 @@ public class MapChunkUtil_1_14 { fieldBitMask.set(nmsPacket, packet.getChunk().getBitMask()); NBTBase heightMap = adapter.fromNative(packet.getHeightMap()); fieldHeightMap.set(nmsPacket, heightMap); - fieldChunkData.set(nmsPacket, packet.get()); + + fieldChunkData.set(nmsPacket, packet.getSectionBytes()); Map tiles = packet.getChunk().getTiles(); ArrayList nmsTiles = new ArrayList<>(tiles.size()); @@ -72,6 +86,7 @@ public class MapChunkUtil_1_14 { fieldFull.set(nmsPacket, packet.isFull()); } catch (IllegalAccessException e) { e.printStackTrace(); + return null; } return nmsPacket; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java index f59f22d1b..fb0d6924e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -297,7 +297,6 @@ public enum FaweCache implements Trimable { int ordinal = blocksChars[i]; int palette = blockToPalette[ordinal]; if (palette == Integer.MAX_VALUE) { -// BlockState state = BlockTypesCache.states[ordinal]; blockToPalette[ordinal] = palette = num_palette; paletteToBlock[num_palette] = ordinal; num_palette++; @@ -309,7 +308,7 @@ public enum FaweCache implements Trimable { int ordinal = blocksInts[i]; int palette = blockToPalette[ordinal]; if (palette == Integer.MAX_VALUE) { - BlockState state = BlockTypesCache.states[ordinal]; +// BlockState state = BlockTypesCache.states[ordinal]; blockToPalette[ordinal] = palette = num_palette; paletteToBlock[num_palette] = ordinal; num_palette++; @@ -326,6 +325,11 @@ public enum FaweCache implements Trimable { // BlockStates int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) { + bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry + } else { + bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries + } int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; if (num_palette == 1) { // Set a value, because minecraft needs it for some reason @@ -347,8 +351,8 @@ public enum FaweCache implements Trimable { return palette; } catch (Throwable e) { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); e.printStackTrace(); + Arrays.fill(blockToPalette, Integer.MAX_VALUE); throw e; } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java index 1edbdf2a1..e0a5519b3 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java @@ -14,6 +14,7 @@ import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.registry.BlockRegistry; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Map; import java.util.Set; @@ -66,28 +67,36 @@ public interface IBlocks extends Trimable { char[] ids = this.getArray(layer); int nonEmpty = 0; // TODO optimize into same loop as toPalette - for (char id : ids) { - if (id != 0) nonEmpty++; + for (int i = 0; i < ids.length; i++) { + char ordinal = ids[i]; + switch (ordinal) { + case BlockID.__RESERVED__: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + ids[i] = BlockID.AIR; + case BlockID.AIR: + continue; + default: + nonEmpty++; + } } sectionWriter.writeShort(nonEmpty); // non empty - sectionWriter.writeByte(14); // globalPaletteBitsPerBlock - - if (true) { - BitArray4096 bits = new BitArray4096(14); // globalPaletteBitsPerBlock - bits.setAt(0, 0); - for (int i = 0; i < 4096; i++) { - int ordinal = ids[i]; - BlockState state = BlockState.getFromOrdinal(ordinal); - if (!state.getMaterial().isAir()) { - int mcId = registry.getInternalBlockStateId(state).getAsInt(); - bits.setAt(i, mcId); - } - } - sectionWriter.write(bits.getData()); - } else { - +// if (false) { +// sectionWriter.writeByte(14); // globalPaletteBitsPerBlock +// BitArray4096 bits = new BitArray4096(14); // globalPaletteBitsPerBlock +// bits.setAt(0, 0); +// for (int i = 0; i < 4096; i++) { +// int ordinal = ids[i]; +// BlockState state = BlockState.getFromOrdinal(ordinal); +// if (!state.getMaterial().isAir()) { +// int mcId = registry.getInternalBlockStateId(state).getAsInt(); +// bits.setAt(i, mcId); +// } +// } +// sectionWriter.write(bits.getData()); +// } else { FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids); sectionWriter.writeByte(palette.bitsPerEntry); // bits per block @@ -95,11 +104,11 @@ public interface IBlocks extends Trimable { for (int i = 0; i < palette.paletteToBlockLength; i++) { int ordinal = palette.paletteToBlock[i]; switch (ordinal) { + case BlockID.__RESERVED__: case BlockID.CAVE_AIR: case BlockID.VOID_AIR: case BlockID.AIR: - case BlockID.__RESERVED__: - sectionWriter.writeVarInt(0); + sectionWriter.write(0); break; default: BlockState state = BlockState.getFromOrdinal(ordinal); @@ -112,7 +121,7 @@ public interface IBlocks extends Trimable { for (int i = 0; i < palette.blockStatesLength; i++) { sectionWriter.writeLong(palette.blockStates[i]); } - } +// } } // if (writeBiomes) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/filter/block/CharFilterBlock.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/filter/block/CharFilterBlock.java index 2dbd271c5..f1048fd94 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/filter/block/CharFilterBlock.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/filter/block/CharFilterBlock.java @@ -115,7 +115,7 @@ public class CharFilterBlock extends ChunkFilterBlock { @Override public void filter(Filter filter, int yStart, int yEnd) { - for (y = yStart, index = yStart << 8; y < yEnd; y++) { + for (y = yStart, index = yStart << 8; y <= yEnd; y++) { for (z = 0; z < 16; z++) { for (x = 0; x < 16; x++, index++) { filter.applyBlock(this); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/packet/ChunkPacket.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/packet/ChunkPacket.java index 822b18a84..bc412cb1c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/packet/ChunkPacket.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/packet/ChunkPacket.java @@ -57,7 +57,7 @@ public class ChunkPacket implements Function, Supplier { return chunk; } - private byte[] getSectionBytes() { + public byte[] getSectionBytes() { byte[] tmp = this.sectionBytes; if (tmp == null) { synchronized (this) { @@ -107,7 +107,6 @@ public class ChunkPacket implements Function, Supplier { fos.writeVarInt(getChunk().getBitMask()); - fos.writeNBT("", getHeightMap()); fos.writeVarInt(sectionBytes.length); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/ChunkSendProcessor.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/ChunkSendProcessor.java index 3aac986cb..5528300fc 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/ChunkSendProcessor.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/ChunkSendProcessor.java @@ -8,6 +8,7 @@ import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; import java.util.function.Supplier; import java.util.stream.Stream; @@ -25,7 +26,7 @@ public class ChunkSendProcessor implements IBatchProcessor { public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { int chunkX = chunk.getX(); int chunkZ = chunk.getZ(); - boolean replaceAll = true; + boolean replaceAll = set.getBiomeType(0, 0) != null; ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, () -> set, replaceAll); Stream stream = this.players.get(); if (stream == null) { @@ -41,4 +42,4 @@ public class ChunkSendProcessor implements IBatchProcessor { public Extent construct(Extent child) { return null; } -} +} \ No newline at end of file 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 29fbc01b5..5084e9643 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 @@ -328,31 +328,67 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { @NotNull @Override public Iterator iterator() { return new Iterator() { - private MutableBlockVector2 pos = new MutableBlockVector2().setComponents(maxX + 1, maxZ); + final MutableBlockVector2 mutable = new MutableBlockVector2(0, 0); + + int bx = minX; + int bz = minZ; + + int tx = maxX; + int tz = maxZ; + + private int x = minX; + private int z = minZ; + + int regionX = x >> 5; + int regionZ = z >> 5; + int rbx = Math.max(bx, regionX << 5); + int rbz = Math.max(bz, regionZ << 5); + int rtx = Math.min(tx, 31 + (regionX << 5)); + int rtz = Math.min(tz, 31 + (regionZ << 5)); + + boolean hasNext = true; + @Override public boolean hasNext() { - return pos != null; + return hasNext; } @Override public BlockVector2 next() { - MutableBlockVector2 result = pos; - // calc next - pos.setComponents(pos.getX() - 1, pos.getZ()); - if (pos.getX() <= minX) { - if (pos.getZ() == minZ) { - pos = null; - } else if (pos.getX() < minX) { - pos.setComponents(maxX, pos.getZ() - 1); + mutable.mutX(x); + mutable.mutZ(z); + if (++x > rtx) { + if (++z > rtz) { + if (x > tx) { + x = bx; + if (z > tz) { + if (!hasNext) { + throw new NoSuchElementException("End of iterator") { + @Override + public Throwable fillInStackTrace() { + return this; + } + }; + } + x = tx; + hasNext = false; + return mutable; + } + } else { + z = rbz; + } + regionX = x >> 5; + regionZ = z >> 5; + rbx = Math.max(bx, regionX << 5); + rbz = Math.max(bz, regionZ << 5); + rtx = Math.min(tx, 31 + (regionX << 5)); + rtz = Math.min(tz, 31 + (regionZ << 5)); + } else { + x = rbx; } } - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException("This set is immutable."); + return mutable; } }; } @@ -628,19 +664,19 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { @Override public void filter(final IChunk chunk, final Filter filter, ChunkFilterBlock block, final IChunkGet get, final IChunkSet set) { - int x = chunk.getX(); - int z = chunk.getZ(); - block = block.init(x, z, get); + int chunkX = chunk.getX(); + int chunkZ = chunk.getZ(); + block = block.init(chunkX, chunkZ, get); - if ((minX + 15) >> 4 <= x && (maxX - 15) >> 4 >= x && (minZ + 15) >> 4 <= z && (maxZ - 15) >> 4 >= z) { + if ((minX + 15) >> 4 <= chunkX && (maxX - 15) >> 4 >= chunkX && (minZ + 15) >> 4 <= chunkZ && (maxZ - 15) >> 4 >= chunkZ) { filter(chunk, filter, block, get, set, minY, maxY); return; } - int localMinX = Math.max(minX, x << 4) & 15; - int localMaxX = Math.min(maxX, 15 + (x << 4)) & 15; - int localMinZ = Math.max(minZ, z << 4) & 15; - int localMaxZ = Math.min(maxZ, 15 + (z << 4)) & 15; + int localMinX = Math.max(minX, chunkX << 4) & 15; + int localMaxX = Math.min(maxX, 15 + (chunkX << 4)) & 15; + int localMinZ = Math.max(minZ, chunkZ << 4) & 15; + int localMaxZ = Math.min(maxZ, 15 + (chunkZ << 4)) & 15; int yStart = (minY & 15); int yEnd = (maxY & 15);