From f9f6aead0fe7e91cf343d15eafde092cc7c15ec2 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 13 Apr 2019 16:44:23 +1000 Subject: [PATCH] Some optimizations for 1.13 --- v1_13/BukkitChunk_1_13_Copy.java | 81 -- v1_13/BukkitQueue_1_13.java | 855 ---------------- .../com/boydti/fawe/bukkit/FaweBukkit.java | 27 +- .../adapter/v1_13_1/Spigot_v1_13_R2.java | 18 +- .../fawe/bukkit/v0/BukkitChunk_All.java | 153 ++- .../fawe/bukkit/v0/BukkitQueue_All.java | 5 - .../fawe/bukkit/v1_13}/BukkitChunk_1_13.java | 247 +++-- .../bukkit/v1_13/BukkitChunk_1_13_Copy.java | 89 ++ .../fawe/bukkit/v1_13/BukkitQueue_1_13.java | 918 ++++++++++++++++++ .../worldedit/bukkit/WorldEditListener.java | 14 +- .../main/java/com/boydti/fawe/FaweCache.java | 73 +- .../com/boydti/fawe/example/IntFaweChunk.java | 26 +- .../fawe/example/NMSMappedFaweQueue.java | 10 +- .../com/boydti/fawe/example/NMSRelighter.java | 104 +- .../fawe/example/NullQueueIntFaweChunk.java | 8 +- .../fawe/example/SimpleIntFaweChunk.java | 10 +- .../boydti/fawe/jnbt/anvil/BitArray4096.java | 11 +- .../com/boydti/fawe/jnbt/anvil/MCAChunk.java | 18 +- .../com/boydti/fawe/jnbt/anvil/MCAQueue.java | 15 - .../fawe/jnbt/anvil/WritableMCAChunk.java | 19 +- .../object/change/MutableChunkChange.java | 2 +- 21 files changed, 1395 insertions(+), 1308 deletions(-) delete mode 100644 v1_13/BukkitChunk_1_13_Copy.java delete mode 100644 v1_13/BukkitQueue_1_13.java rename {v1_13 => worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13}/BukkitChunk_1_13.java (69%) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13_Copy.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java diff --git a/v1_13/BukkitChunk_1_13_Copy.java b/v1_13/BukkitChunk_1_13_Copy.java deleted file mode 100644 index 73b7f3c36..000000000 --- a/v1_13/BukkitChunk_1_13_Copy.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13; - -import com.boydti.fawe.object.FaweQueue; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.NibbleArray; - -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); - } - - public void set(int i, byte[] ids, byte[] data) { - this.dataInts[i] = data; - } - - public boolean storeSection(ChunkSection section, int layer) throws IllegalAccessException { - if (section == null) { - return false; - } - DataPaletteBlock blocks = section.getBlocks(); - NibbleArray data = new NibbleArray(); - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - IBlockData block = blocks.a(x, y, z); - } - } - } - blocks.set(ids, data); - set(layer, ids, data.asBytes()); - short solid = (short) getParent().fieldNonEmptyBlockCount.getInt(section); - count[layer] = solid; - air[layer] = (short) (4096 - solid); - return true; - } - - @Override - public int[][] getCombinedIdArrays() { - for (int i = 0; i < ids.length; i++) { - getIdArray(i); - } - return super.getCombinedIdArrays(); - } - - @Override - public int[] getIdArray(int i) { - int[] combined = this.ids[i]; - if (combined != null) { - return combined; - } - byte[] idsBytesArray = idsBytes[i]; - if (idsBytesArray == null) { - return null; - } - byte[] datasBytesArray = datasBytes[i]; - - idsBytes[i] = null; - datasBytes[i] = null; - - this.ids[i] = combined = new char[4096]; - for (int j = 0, k = 0; j < 2048; j++, k += 2) { - combined[k] = (char) (((idsBytesArray[k] & 0xFF) << 4) + (datasBytesArray[j] & 15)); - } - for (int j = 0, k = 1; j < 2048; j++, k += 2) { - combined[k] = (char) (((idsBytesArray[k] & 0xFF) << 4) + ((datasBytesArray[j] >> 4) & 15)); - } - return combined; - } - - @Override - public void setBlock(int x, int y, int z, int id) { - throw new UnsupportedOperationException("This chunk is an immutable copy"); - } - - @Override - public void setBlock(int x, int y, int z, int id, int data) { - throw new UnsupportedOperationException("This chunk is an immutable copy"); - } -} diff --git a/v1_13/BukkitQueue_1_13.java b/v1_13/BukkitQueue_1_13.java deleted file mode 100644 index 52bb00bd5..000000000 --- a/v1_13/BukkitQueue_1_13.java +++ /dev/null @@ -1,855 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.bukkit.BukkitPlayer; -import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.bukkit.v1_13.packet.FaweChunkPacket; -import com.boydti.fawe.bukkit.v1_13.packet.MCAChunkPacket; -import com.boydti.fawe.example.IntFaweChunk; -import com.boydti.fawe.jnbt.anvil.MCAChunk; -import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.object.RegionWrapper; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.object.brush.visualization.VisualChunk; -import com.boydti.fawe.object.queue.LazyFaweChunk; -import com.boydti.fawe.object.visitor.FaweChunkVisitor; -import com.boydti.fawe.util.*; -import com.comphenix.protocol.PacketType; -import com.comphenix.protocol.ProtocolLibrary; -import com.comphenix.protocol.ProtocolManager; -import com.comphenix.protocol.injector.netty.WirePacket; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.world.biome.BaseBiome; -import com.sk89q.worldedit.world.block.BlockTypes; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import net.minecraft.server.v1_13_R2.BiomeBase; -import net.minecraft.server.v1_13_R2.BiomeCache; -import net.minecraft.server.v1_13_R2.Block; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.ChunkProviderGenerate; -import net.minecraft.server.v1_13_R2.ChunkProviderServer; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.DataPaletteBlock; -import net.minecraft.server.v1_13_R2.Entity; -import net.minecraft.server.v1_13_R2.EntityPlayer; -import net.minecraft.server.v1_13_R2.EntityTracker; -import net.minecraft.server.v1_13_R2.EntityTypes; -import net.minecraft.server.v1_13_R2.EnumDifficulty; -import net.minecraft.server.v1_13_R2.EnumGamemode; -import net.minecraft.server.v1_13_R2.EnumSkyBlock; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.IDataManager; -import net.minecraft.server.v1_13_R2.MinecraftServer; -import net.minecraft.server.v1_13_R2.NBTTagCompound; -import net.minecraft.server.v1_13_R2.NibbleArray; -import net.minecraft.server.v1_13_R2.PacketDataSerializer; -import net.minecraft.server.v1_13_R2.PacketPlayOutMapChunk; -import net.minecraft.server.v1_13_R2.PacketPlayOutMultiBlockChange; -import net.minecraft.server.v1_13_R2.PlayerChunk; -import net.minecraft.server.v1_13_R2.PlayerChunkMap; -import net.minecraft.server.v1_13_R2.RegionFile; -import net.minecraft.server.v1_13_R2.RegionFileCache; -import net.minecraft.server.v1_13_R2.ServerNBTManager; -import net.minecraft.server.v1_13_R2.TileEntity; -import net.minecraft.server.v1_13_R2.WorldChunkManager; -import net.minecraft.server.v1_13_R2.WorldData; -import net.minecraft.server.v1_13_R2.WorldManager; -import net.minecraft.server.v1_13_R2.WorldServer; -import net.minecraft.server.v1_13_R2.WorldSettings; -import net.minecraft.server.v1_13_R2.WorldType; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.WorldCreator; -import org.bukkit.block.Biome; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.CraftServer; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; -import org.bukkit.event.world.WorldInitEvent; -import org.bukkit.event.world.WorldLoadEvent; -import org.bukkit.generator.ChunkGenerator; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.atomic.LongAdder; - -public class BukkitQueue_1_13 extends BukkitQueue_0 { - - protected final static Field fieldBits; - protected final static Field fieldPalette; - protected final static Field fieldSize; - protected final static Field fieldTickingBlockCount; - protected final static Field fieldNonEmptyBlockCount; - protected final static Field fieldSection; - protected final static Field fieldBiomes; - protected final static Field fieldChunkGenerator; - protected final static Field fieldSeed; - protected final static Field fieldBiomeCache; - protected final static Field fieldBiomes2; - protected final static Field fieldGenLayer1; - protected final static Field fieldGenLayer2; - protected final static Field fieldSave; -// protected final static MutableGenLayer genLayer; - protected final static ChunkSection emptySection; - protected final static Field fieldRegistry; - protected final static Field fieldNbtMap; - protected final static Field fieldIbdMap; - - protected static final Method methodResize; - - static { - try { - emptySection = new ChunkSection(0, true); - Arrays.fill(emptySection.getSkyLightArray().asBytes(), (byte) 255); - fieldSection = ChunkSection.class.getDeclaredField("blockIds"); - fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); - fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); - fieldSection.setAccessible(true); - fieldTickingBlockCount.setAccessible(true); - fieldNonEmptyBlockCount.setAccessible(true); - - fieldBiomes = ChunkProviderGenerate.class.getDeclaredField("D"); // * - fieldBiomes.setAccessible(true); - fieldChunkGenerator = ChunkProviderServer.class.getDeclaredField("chunkGenerator"); - fieldChunkGenerator.setAccessible(true); - fieldSeed = WorldData.class.getDeclaredField("e"); - fieldSeed.setAccessible(true); - fieldBiomeCache = WorldChunkManager.class.getDeclaredField("d"); // * - fieldBiomeCache.setAccessible(true); - fieldBiomes2 = WorldChunkManager.class.getDeclaredField("e"); // * - fieldBiomes2.setAccessible(true); - fieldGenLayer1 = WorldChunkManager.class.getDeclaredField("b") ; - fieldGenLayer2 = WorldChunkManager.class.getDeclaredField("c") ; - fieldGenLayer1.setAccessible(true); - fieldGenLayer2.setAccessible(true); - - fieldSave = ReflectionUtils.setAccessible(net.minecraft.server.v1_13_R2.Chunk.class.getDeclaredField("s")); //* - - fieldPalette = DataPaletteBlock.class.getDeclaredField("c"); - fieldPalette.setAccessible(true); - - methodResize = DataPaletteBlock.class.getDeclaredMethod("b", int.class); - methodResize.setAccessible(true); - - /// - - fieldRegistry = DataPaletteBlock.class.getDeclaredField("d"); - fieldRegistry.setAccessible(true); - - fieldNbtMap = DataPaletteBlock.class.getDeclaredField("e"); - fieldNbtMap.setAccessible(true); - - fieldIbdMap = DataPaletteBlock.class.getDeclaredField("f"); - fieldIbdMap.setAccessible(true); - - fieldSize = DataPaletteBlock.class.getDeclaredField("i"); - fieldSize.setAccessible(true); - - fieldBits = DataPaletteBlock.class.getDeclaredField("a"); - fieldBits.setAccessible(true); - - Fawe.debug("Using adapter: " + getAdapter()); - Fawe.debug("========================================="); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - public BukkitQueue_1_13(final com.sk89q.worldedit.world.World world) { - super(world); - getImpWorld(); - } - - public BukkitQueue_1_13(final String world) { - super(world); - getImpWorld(); - } - - private boolean save(net.minecraft.server.v1_13_R2.Chunk chunk, ChunkProviderServer cps) { - cps.saveChunk(chunk, false); - chunk.a(false); - return true; - } - - @Override - public ChunkSection[] getSections(net.minecraft.server.v1_13_R2.Chunk chunk) { - return chunk.getSections(); - } - - @Override - public net.minecraft.server.v1_13_R2.Chunk loadChunk(World world, int x, int z, boolean generate) { - ChunkProviderServer provider = ((CraftWorld) world).getHandle().getChunkProvider(); - if (generate) { - return provider.getChunkAt(x, z, true, true); - } else { - return provider.getChunkAt(x, z, true, false); - } - } - - @Override - public ChunkSection[] getCachedSections(World world, int cx, int cz) { - net.minecraft.server.v1_13_R2.Chunk chunk = ((CraftWorld) world).getHandle().getChunkProvider().getChunkAt(cx, cz, false, false); - if (chunk != null) { - return chunk.getSections(); - } - return null; - } - - @Override - public net.minecraft.server.v1_13_R2.Chunk getCachedChunk(World world, int cx, int cz) { - return ((CraftWorld) world).getHandle().getChunkProvider().getChunkAt(cx, cz, false, false); - } - - @Override - public ChunkSection getCachedSection(ChunkSection[] chunkSections, int cy) { - return chunkSections[cy]; - } - - @Override - public void saveChunk(net.minecraft.server.v1_13_R2.Chunk chunk) { - chunk.f(true); // Set Modified - chunk.mustSave = true; - } - - @Override - public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) { - if (biome != null) { - try { - if (seed == null) { - seed = world.getSeed(); - } - nmsWorld.worldData.getSeed(); - boolean result; - ChunkProviderGenerate generator = new ChunkProviderGenerate(nmsWorld, seed, false, ""); - Biome bukkitBiome = getAdapter().getBiome(biome.getId()); - BiomeBase base = BiomeBase.getBiome(biome.getId()); - fieldBiomes.set(generator, new BiomeBase[]{base}); - boolean cold = base.getTemperature() <= 1; - net.minecraft.server.v1_13_R2.ChunkGenerator existingGenerator = nmsWorld.getChunkProvider().chunkGenerator; - long existingSeed = world.getSeed(); - { - if (genLayer == null) genLayer = new MutableGenLayer(seed); - genLayer.set(biome.getId()); - Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager()); - Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager()); - fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer); - fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer); - - fieldSeed.set(nmsWorld.worldData, seed); - - ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new BiomeCache(this.nmsWorld.getWorldChunkManager())); - - ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProvider(), generator); - - keepLoaded.remove(MathMan.pairInt(x, z)); - result = getWorld().regenerateChunk(x, z); - net.minecraft.server.v1_13_R2.Chunk nmsChunk = getCachedChunk(world, x, z); - if (nmsChunk != null) { - nmsChunk.f(true); // Set Modified - nmsChunk.mustSave = true; - } - - ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProvider(), existingGenerator); - - fieldSeed.set(nmsWorld.worldData, existingSeed); - - fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1); - fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2); - } - return result; - } catch (Throwable e) { - e.printStackTrace(); - } - } - return super.regenerateChunk(world, x, z, biome, seed); - } - - @Override - public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) { - TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Boolean value) { - long start = System.currentTimeMillis(); - long last = start; - synchronized (RegionFileCache.class) { - World world = getWorld(); - if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false); - ChunkProviderServer provider = nmsWorld.getChunkProvider(); - - boolean mustSave = false; - boolean[][] chunksUnloaded = null; - { // Unload chunks - Iterator iter = provider.a().iterator(); - while (iter.hasNext()) { - net.minecraft.server.v1_13_R2.Chunk chunk = iter.next(); - if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) { - boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ); - if (isIn) { - if (!load) { - mustSave |= saveChunks && save(chunk, provider); - continue; - } - iter.remove(); - boolean save = saveChunks && chunk.a(false); - mustSave |= save; - provider.unloadChunk(chunk, save); - if (chunksUnloaded == null) { - chunksUnloaded = new boolean[32][]; - } - int relX = chunk.locX & 31; - boolean[] arr = chunksUnloaded[relX]; - if (arr == null) { - arr = chunksUnloaded[relX] = new boolean[32]; - } - arr[chunk.locZ & 31] = true; - } - } - } - } - if (mustSave) { - provider.c(); // TODO only the necessary chunks - } - - File unloadedRegion = null; - if (load && !RegionFileCache.a.isEmpty()) { - Map map = RegionFileCache.a; - Iterator> iter = map.entrySet().iterator(); - String requiredPath = world.getName() + File.separator + "region"; - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - File file = entry.getKey(); - int[] regPos = MainUtil.regionNameToCoords(file.getPath()); - if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) { - if (file.exists()) { - unloadedRegion = file; - RegionFile regionFile = entry.getValue(); - iter.remove(); - try { - regionFile.c(); - } catch (IOException e) { - e.printStackTrace(); - } - } - break; - } - } - } - - long now = System.currentTimeMillis(); - if (whileLocked != null) whileLocked.run(); - if (!load) return; - - { // Load the region again - if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) { - final boolean[][] finalChunksUnloaded = chunksUnloaded; - TaskManager.IMP.async(() -> { - int bx = mcaX << 5; - int bz = mcaZ << 5; - for (int x = 0; x < finalChunksUnloaded.length; x++) { - boolean[] arr = finalChunksUnloaded[x]; - if (arr != null) { - for (int z = 0; z < arr.length; z++) { - if (arr[z]) { - int cx = bx + x; - int cz = bz + z; - SetQueue.IMP.addTask(new Runnable() { - @Override - public void run() { - net.minecraft.server.v1_13_R2.Chunk chunk = provider.getChunkAt(cx, cz, null, false); - if (chunk != null) { - PlayerChunk pc = getPlayerChunk(nmsWorld, cx, cz); - if (pc != null) { - sendChunk(pc, chunk, 0); - } - } - } - }); - } - } - } - } - }); - } - } - } - } - }); - return true; - } - - @Override - public void setHeightMap(FaweChunk chunk, byte[] heightMap) { - CraftChunk craftChunk = (CraftChunk) chunk.getChunk(); - if (craftChunk != null) { - int[] otherMap = craftChunk.getHandle().heightMap; - for (int i = 0; i < heightMap.length; i++) { - int newHeight = heightMap[i] & 0xFF; - int currentHeight = otherMap[i]; - if (newHeight > currentHeight) { - otherMap[i] = newHeight; - } - } - } - } - - @Override - public boolean next(int amount, long time) { - return super.next(amount, time); - } - - @Override - public void setSkyLight(ChunkSection section, int x, int y, int z, int value) { - section.getSkyLightArray().a(x & 15, y & 15, z & 15, value); - } - - @Override - public void setBlockLight(ChunkSection section, int x, int y, int z, int value) { - section.getEmittedLightArray().a(x & 15, y & 15, z & 15, value); - } - - @Override - public World createWorld(final WorldCreator creator) { - final String name = creator.name(); - ChunkGenerator generator = creator.generator(); - final CraftServer server = (CraftServer) Bukkit.getServer(); - final MinecraftServer console = server.getServer(); - final File folder = new File(server.getWorldContainer(), name); - final World world = server.getWorld(name); - final WorldType type = WorldType.getType(creator.type().getName()); - final boolean generateStructures = creator.generateStructures(); - if (world != null) { - return world; - } - if (folder.exists() && !folder.isDirectory()) { - throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder"); - } - TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Object value) { - try { - Field field = CraftServer.class.getDeclaredField("worlds"); - field.setAccessible(true); - Map existing = (Map) field.get(server); - if (!existing.getClass().getName().contains("SynchronizedMap")) { - field.set(server, Collections.synchronizedMap(existing)); - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - }); - if (generator == null) { - generator = server.getGenerator(name); - } - int dimension = 10 + console.worlds.size(); - boolean used = false; - do { - for (final WorldServer ws : console.worlds) { - used = (ws.dimension == dimension); - if (used) { - ++dimension; - break; - } - } - } while (used); - final boolean hardcore = false; - final IDataManager sdm = new ServerNBTManager(server.getWorldContainer(), name, true, server.getHandle().getServer().dataConverterManager); - WorldData worlddata = sdm.getWorldData(); - final WorldSettings worldSettings; - if (worlddata == null) { - worldSettings = new WorldSettings(creator.seed(), EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type); - worldSettings.setGeneratorSettings(creator.generatorSettings()); - worlddata = new WorldData(worldSettings, name); - } else { - worldSettings = null; - } - worlddata.checkName(name); - final WorldServer internal = (WorldServer)new WorldServer(console, sdm, worlddata, dimension, console.methodProfiler, creator.environment(), generator).b(); - startSet(true); // Temporarily allow async chunk load since the world isn't added yet - if (worldSettings != null) { - internal.a(worldSettings); - } - endSet(true); - internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle(); - internal.tracker = new EntityTracker(internal); - internal.addIWorldAccess(new WorldManager(console, internal)); - internal.worldData.setDifficulty(EnumDifficulty.EASY); - internal.setSpawnFlags(true, true); - if (generator != null) { - internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld())); - } - // Add the world - return TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(World value) { - console.worlds.add(internal); - server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld())); - server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld())); - this.value = internal.getWorld(); - } - }); - } - - @Override - public int getCombinedId4Data(ChunkSection lastSection, int x, int y, int z) { - DataPaletteBlock dataPalette = lastSection.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - int id = Block.REGISTRY_ID.getId(ibd); - return BlockTypes.states[idbToStateOrdinal[id]]; - } - - @Override - public int getBiome(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int z) { - return chunk.getBiomeIndex()[((z & 15) << 4) + (x & 15)]; - } - - @Override - public int getOpacity(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - return ibd.c(); - } - - @Override - public int getBrightness(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - return ibd.d(); - } - - @Override - public int getOpacityBrightnessPair(ChunkSection section, int x, int y, int z) { - DataPaletteBlock dataPalette = section.getBlocks(); - IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); - return MathMan.pair16(ibd.c(), ibd.d()); - } - - @Override - public void sendChunk(int x, int z, int bitMask) { - net.minecraft.server.v1_13_R2.Chunk chunk = getCachedChunk(getWorld(), x, z); - if (chunk != null) { - sendChunk(getPlayerChunk((WorldServer) chunk.getWorld(), chunk.locX, chunk.locZ), chunk, bitMask); - } - } - - @Override - public void sendChunkUpdatePLIB(FaweChunk chunk, FawePlayer... players) { - PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); - ProtocolManager manager = ProtocolLibrary.getProtocolManager(); - WirePacket packet = null; - try { - for (int i = 0; i < players.length; i++) { - CraftPlayer bukkitPlayer = ((CraftPlayer) ((BukkitPlayer) players[i]).parent); - EntityPlayer player = bukkitPlayer.getHandle(); - - if (playerManager.a(player, chunk.getX(), chunk.getZ())) { - if (packet == null) { - byte[] data; - byte[] buffer = new byte[8192]; - if (chunk instanceof LazyFaweChunk) { - chunk = (FaweChunk) chunk.getChunk(); - } - if (chunk instanceof MCAChunk) { - data = new MCAChunkPacket((MCAChunk) chunk, true, true, hasSky()).apply(buffer); - } else { - data = new FaweChunkPacket(chunk, true, true, hasSky()).apply(buffer); - } - packet = new WirePacket(PacketType.Play.Server.MAP_CHUNK, data); - } - manager.sendWirePacket(bukkitPlayer, packet); - } - } - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - - @Override - public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) { - try { - PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); - boolean watching = false; - boolean[] watchingArr = new boolean[players.length]; - for (int i = 0; i < players.length; i++) { - EntityPlayer player = ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle(); - if (playerManager.a(player, chunk.getX(), chunk.getZ())) { - watchingArr[i] = true; - watching = true; - } - } - if (!watching) return; - final LongAdder size = new LongAdder(); - if (chunk instanceof VisualChunk) { - size.add(((VisualChunk) chunk).size()); - } else if (chunk instanceof IntFaweChunk) { - size.add(((IntFaweChunk) chunk).getTotalCount()); - } else { - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - size.add(1); - } - }); - } - if (size.intValue() == 0) return; - PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); - ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(); - final PacketDataSerializer buffer = new PacketDataSerializer(byteBuf); - buffer.writeInt(chunk.getX()); - buffer.writeInt(chunk.getZ()); - buffer.d(size.intValue()); - chunk.forEachQueuedBlock(new FaweChunkVisitor() { - @Override - public void run(int localX, int y, int localZ, int combined) { - short index = (short) (localX << 12 | localZ << 8 | y); - if (combined < 16) combined = 0; - buffer.writeShort(index); - buffer.d(combined); - } - }); - packet.a(buffer); - for (int i = 0; i < players.length; i++) { - if (watchingArr[i]) ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle().playerConnection.sendPacket(packet); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void refreshChunk(FaweChunk fc) { - sendChunk(fc.getX(), fc.getZ(), fc.getBitMask()); - } - - public void sendPacket(int cx, int cz, Packet packet) { - PlayerChunk chunk = getPlayerChunk(nmsWorld, cx, cz); - if (chunk != null) { - for (EntityPlayer player : chunk.c) { - player.playerConnection.sendPacket(packet); - } - } - } - - private PlayerChunk getPlayerChunk(WorldServer w, int cx, int cz) { - PlayerChunkMap chunkMap = w.getPlayerChunkMap(); - PlayerChunk playerChunk = chunkMap.getChunk(cx, cz); - if (playerChunk == null) { - return null; - } - if (playerChunk.c.isEmpty()) { - return null; - } - return playerChunk; - } - - public boolean sendChunk(PlayerChunk playerChunk, net.minecraft.server.v1_13_R2.Chunk nmsChunk, int mask) { - WorldServer w = (WorldServer) nmsChunk.getWorld(); - if (playerChunk == null) { - return false; - } - if (mask == 0) { - PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535); - for (EntityPlayer player : playerChunk.c) { - player.playerConnection.sendPacket(packet); - } - return true; - } - // Send chunks - boolean empty = false; - ChunkSection[] sections = nmsChunk.getSections(); - for (int i = 0; i < sections.length; i++) { - if (sections[i] == null) { - sections[i] = emptySection; - empty = true; - } - } - if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { - PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280); - for (EntityPlayer player : playerChunk.c) { - player.playerConnection.sendPacket(packet); - } - mask = 255; - } - PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, mask); - for (EntityPlayer player : playerChunk.c) { - player.playerConnection.sendPacket(packet); - } - if (empty) { - for (int i = 0; i < sections.length; i++) { - if (sections[i] == emptySection) { - sections[i] = null; - } - } - } - return true; - } - - public boolean hasEntities(net.minecraft.server.v1_13_R2.Chunk nmsChunk) { - try { - final Collection[] entities = (Collection[]) getEntitySlices.invoke(nmsChunk); - for (int i = 0; i < entities.length; i++) { - Collection slice = entities[i]; - if (slice != null && !slice.isEmpty()) { - return true; - } - } - } catch (Throwable ignore) {} - return false; - } - - @Override - public boolean removeSectionLighting(ChunkSection section, int layer, boolean sky) { - if (section != null) { - Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); - if (sky) { - byte[] light = section.getSkyLightArray().asBytes(); - if (light != null) { - Arrays.fill(light, (byte) 0); - } - } - return true; - } - return false; - } - - @Override - public void setFullbright(ChunkSection[] sections) { - for (int i = 0; i < sections.length; i++) { - ChunkSection section = sections[i]; - if (section != null) { - byte[] bytes = section.getSkyLightArray().asBytes(); - Arrays.fill(bytes, (byte) 255); - } - } - } - - @Override - public int getSkyLight(ChunkSection section, int x, int y, int z) { - return section.b(x & 15, y & 15, z & 15); - } - - @Override - public int getEmmittedLight(ChunkSection section, int x, int y, int z) { - return section.c(x & 15, y & 15, z & 15); - } - - @Override - public void relightBlock(int x, int y, int z) { - pos.c(x, y, z); - nmsWorld.c(EnumSkyBlock.BLOCK, pos); - } - - @Override - public void relightSky(int x, int y, int z) { - pos.c(x, y, z); - nmsWorld.c(EnumSkyBlock.SKY, pos); - } - - @Override - public void relight(int x, int y, int z) { - pos.c(x, y, z); - nmsWorld.w(pos); - } - - protected WorldServer nmsWorld; - - @Override - public World getImpWorld() { - World world = super.getImpWorld(); - if (world != null) { - this.nmsWorld = ((CraftWorld) world).getHandle(); - return super.getImpWorld(); - } else { - return null; - } - } - - public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException { - fieldTickingBlockCount.set(section, tickingBlockCount); - fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); - } - - public int getNonEmptyBlockCount(ChunkSection section) throws IllegalAccessException { - return (int) fieldNonEmptyBlockCount.get(section); - } - - public void setPalette(ChunkSection section, DataPaletteBlock palette) throws NoSuchFieldException, IllegalAccessException { - fieldSection.set(section, palette); - Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); - } - - public ChunkSection newChunkSection(int y2, boolean flag, int[] array) { - try { - if (array == null) { - return new ChunkSection(y2, flag); - } else { - ChunkSection section = new ChunkSection(y2, flag); - for (int x = 0; x < 16; x++) { - - } - array; // set array - } - } catch (Throwable e) { - try { - if (array == null) { - Constructor constructor = ChunkSection.class.getDeclaredConstructor(int.class, boolean.class, IBlockData[].class); - return constructor.newInstance(y2, flag, (IBlockData[]) null); - } else { - Constructor constructor = ChunkSection.class.getDeclaredConstructor(int.class, boolean.class, char[].class, IBlockData[].class); - return constructor.newInstance(y2, flag, array, (IBlockData[]) null); - } - } catch (Throwable e2) { - throw new RuntimeException(e2); - } - } - } - - protected BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0); - - @Override - public CompoundTag getTileEntity(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int y, int z) { - Map tiles = chunk.getTileEntities(); - pos.c(x, y, z); - TileEntity tile = tiles.get(pos); - return tile != null ? getTag(tile) : null; - } - - public CompoundTag getTag(TileEntity tile) { - try { - NBTTagCompound tag = new NBTTagCompound(); - tile.save(tag); // readTagIntoEntity - return (CompoundTag) toNative(tag); - } catch (Exception e) { - MainUtil.handleError(e); - return null; - } - } - - @Deprecated - public boolean unloadChunk(final String world, final Chunk chunk) { - net.minecraft.server.v1_13_R2.Chunk c = ((CraftChunk) chunk).getHandle(); - c.mustSave = false; - if (chunk.isLoaded()) { - chunk.unload(false, false); - } - return true; - } - - @Override - public BukkitChunk_1_13 getFaweChunk(int x, int z) { - return new BukkitChunk_1_13(this, x, z); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index 68d21ade2..656946d09 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -31,6 +31,7 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.bukkit.v0.BukkitQueue_All; import com.boydti.fawe.bukkit.v0.ChunkListener_8; import com.boydti.fawe.bukkit.v0.ChunkListener_9; +import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweCommand; @@ -588,16 +589,6 @@ public class FaweBukkit implements IFawe, Listener { try { BukkitQueue_0.checkVersion(v.name()); this.version = tmp = v; - if (tmp == Version.v1_13_R1) { - try { - Fawe.debug("Running 1.13 registry dumper!"); - // TODO FIXME -// NMSRegistryDumper dumper = new NMSRegistryDumper(MainUtil.getFile(plugin.getDataFolder(), "extrablocks.json")); -// dumper.run(); - } catch (Throwable e) { - e.printStackTrace(); - } - } break; } catch (IllegalStateException e) {} } @@ -606,20 +597,14 @@ public class FaweBukkit implements IFawe, Listener { } public enum Version { -// v1_7_R4, -// v1_8_R3, -// v1_9_R2, -// v1_10_R1, -// v1_11_R1, -// v1_12_R2, - v1_13_R1, + v1_13_R2, NONE, } private FaweQueue getQueue(World world) { switch (getVersion()) { - case v1_13_R1: -// return new BukkitQueue_1_13(world); + case v1_13_R2: + return new BukkitQueue_1_13(world); default: case NONE: return new BukkitQueue_All(world); @@ -628,8 +613,8 @@ public class FaweBukkit implements IFawe, Listener { private FaweQueue getQueue(String world) { switch (getVersion()) { - case v1_13_R1: -// return new BukkitQueue_1_13(world); + case v1_13_R2: + return new BukkitQueue_1_13(world); default: case NONE: return new BukkitQueue_All(world); 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 fbd7940f3..69ef73ba6 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 @@ -88,7 +88,7 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit nbtCreateTagMethod.setAccessible(true); } - private int[] idbToStateOrdinal; + public int[] idbToStateOrdinal; private boolean init() { if (idbToStateOrdinal != null) return false; @@ -502,13 +502,21 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit @Override public BlockState adapt(BlockData blockData) { + CraftBlockData cbd = ((CraftBlockData) blockData); + IBlockData ibd = cbd.getState(); + return adapt(ibd); + } + + public BlockState adapt(IBlockData ibd) { + return BlockTypes.states[adaptToInt(ibd)]; + } + + public int adaptToInt(IBlockData ibd) { try { - CraftBlockData cbd = ((CraftBlockData) blockData); - IBlockData ibd = cbd.getState(); int id = Block.REGISTRY_ID.getId(ibd); - return BlockTypes.states[idbToStateOrdinal[id]]; + return idbToStateOrdinal[id]; } catch (NullPointerException e) { - if (init()) return adapt(blockData); + if (init()) return adaptToInt(ibd); throw e; } } 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 a179d8fe2..ee803e4ca 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 @@ -1,7 +1,6 @@ package com.boydti.fawe.bukkit.v0; import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.Settings; import com.boydti.fawe.example.IntFaweChunk; import com.boydti.fawe.object.FaweChunk; @@ -16,16 +15,9 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; -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.entity.EntityTypes; @@ -39,8 +31,17 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + public class BukkitChunk_All extends IntFaweChunk { + private int layer = -1; + private int index; + private boolean place = true; + /** * A FaweSections object represents a chunk and the blocks that you wish to change in it. * @@ -52,18 +53,22 @@ public class BukkitChunk_All extends IntFaweChunk { super(parent, x, z); } - public BukkitChunk_All(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air, byte[] heightMap) { - super(parent, x, z, ids, count, air, heightMap); + public BukkitChunk_All(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { + super(parent, x, z, ids, count, air); + } + + private static boolean canTick(BlockType type) { + return type.getMaterial().isTicksRandomly(); } @Override public IntFaweChunk copy(boolean shallow) { BukkitChunk_All copy; if (shallow) { - copy = new BukkitChunk_All(getParent(), getX(), getZ(), ids, count, air, heightMap); + copy = new BukkitChunk_All(getParent(), getX(), getZ(), ids, count, air); copy.biomes = biomes; } else { - copy = new BukkitChunk_All(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone(), heightMap.clone()); + copy = new BukkitChunk_All(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); copy.biomes = biomes != null ? biomes.clone() : null; } copy.chunk = chunk; @@ -75,21 +80,12 @@ public class BukkitChunk_All extends IntFaweChunk { return Bukkit.getWorld(getParent().getWorldName()).getChunkAt(getX(), getZ()); } - private int layer = -1; - private int index; - private boolean place = true; - @Override public void start() { getChunk().load(true); } - private static boolean canTick(BlockType type) { - return type.getMaterial().isTicksRandomly(); - } - /** - * * @return */ @Override @@ -214,9 +210,9 @@ public class BukkitChunk_All extends IntFaweChunk { if (newArray == null) { continue; } - final byte[] cacheX = FaweCache.CACHE_X[layer]; - final short[] cacheY = FaweCache.CACHE_Y[layer]; - final byte[] cacheZ = FaweCache.CACHE_Z[layer]; +// final byte[] cacheX = FaweCache.CACHE_X[layer]; +// final short[] cacheY = FaweCache.CACHE_Y[layer]; +// final byte[] cacheZ = FaweCache.CACHE_Z[layer]; boolean checkTime = !((getAir(layer) == 4096 || (getCount(layer) == 4096 && getAir(layer) == 0) || (getCount(layer) == getAir(layer)))); Location mutableLoc = new Location(world, 0, 0, 0); @@ -270,85 +266,86 @@ public class BukkitChunk_All extends IntFaweChunk { } } } else { + int yStart = layer << 4; for (; index < 4096; index++) { int j = place ? index : 4095 - index; int combined = newArray[j]; + if (combined == 0) continue; BlockType type = BlockTypes.getFromStateId(combined); - if (type == BlockTypes.__RESERVED__) continue; if (type.getMaterial().isAir()) { if (!place) { - int x = cacheX[j]; - int z = cacheZ[j]; - int y = cacheY[j]; - mutableLoc.setX(bx + x); - mutableLoc.setY(y); - mutableLoc.setZ(bz + z); - setBlock(adapter, chunk, mutableLoc, combined, update); - } - continue; - } else { - boolean light = type.getMaterial().getLightValue() > 0; - if (light) { - if (place) { - continue; - } - light = light && getParent().getSettings().LIGHTING.MODE != 0; - if (light) { - parent.enableLighting(disableResult); - } - } else if (!place) { + int x = j & 15; + int y = yStart + (j >> 8); + int z = (j >> 4) & 15; + mutableLoc.setX(bx + x); + mutableLoc.setY(y); + mutableLoc.setZ(bz + z); + setBlock(adapter, chunk, mutableLoc, combined, update); + } + continue; + } else { + boolean light = type.getMaterial().getLightValue() > 0; + if (light) { + if (place) { continue; } - int x = cacheX[j]; - int z = cacheZ[j]; - int y = cacheY[j]; - if (type.getMaterial().hasContainer() && adapter != null) { - CompoundTag tile = getTile(x, y, z); - if (tile != null) { - synchronized (BukkitChunk_All.this) { - BaseBlock state = BaseBlock.getFromInternalId(combined, tile); - adapter.setBlock(chunk, bx + x, y, bz + z, state, update); - } - continue; - } + light = light && getParent().getSettings().LIGHTING.MODE != 0; + if (light) { + parent.enableLighting(disableResult); } - if (type.getMaterial().isTicksRandomly()) { + } else if (!place) { + continue; + } + int x = j & 15; + int y = yStart + (j >> 8); + int z = (j >> 4) & 15; + if (type.getMaterial().hasContainer() && adapter != null) { + CompoundTag tile = getTile(x, y, z); + if (tile != null) { synchronized (BukkitChunk_All.this) { - mutableLoc.setX(bx + x); - mutableLoc.setY(y); - mutableLoc.setZ(bz + z); - setBlock(adapter, chunk, mutableLoc, combined, update); + BaseBlock state = BaseBlock.getFromInternalId(combined, tile); + adapter.setBlock(chunk, bx + x, y, bz + z, state, update); } - } else { + continue; + } + } + if (type.getMaterial().isTicksRandomly()) { + synchronized (BukkitChunk_All.this) { mutableLoc.setX(bx + x); mutableLoc.setY(y); mutableLoc.setZ(bz + z); setBlock(adapter, chunk, mutableLoc, combined, update); } - if (light) { - parent.disableLighting(disableResult); - } + } else { + mutableLoc.setX(bx + x); + mutableLoc.setY(y); + mutableLoc.setZ(bz + z); + setBlock(adapter, chunk, mutableLoc, combined, update); } - if (System.currentTimeMillis() - start > recommended) { - index++; - break mainloop; + if (light) { + parent.disableLighting(disableResult); } } - index = 0; + if (System.currentTimeMillis() - start > recommended) { + index++; + break mainloop; + } } - } catch (final Throwable e) { - MainUtil.handleError(e); + index = 0; } - } while (System.currentTimeMillis() - start < recommended); - if (more || place) { - this.addToQueue(); + } catch (final Throwable e) { + MainUtil.handleError(e); } - parent.resetLighting(disableResult); - return this; + } while (System.currentTimeMillis() - start < recommended); + if (more || place) { + this.addToQueue(); + } + parent.resetLighting(disableResult); + return this; } public void setBlock(BukkitImplAdapter adapter, Chunk chunk, Location location, int combinedId, boolean update) { - com.sk89q.worldedit.world.block.BaseBlock base = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId).toBaseBlock(); + com.sk89q.worldedit.world.block.BaseBlock base = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId).toBaseBlock(); if (adapter != null) { adapter.setBlock(chunk, (int) location.getX(), (int) location.getY(), (int) location.getZ(), base, update); } else { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java index 60b3fe0f1..015b3b8fc 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java @@ -206,11 +206,6 @@ public class BukkitQueue_All extends BukkitQueue_0 { - public DataPaletteBlock[] sectionPalettes; + public ChunkSection[] sectionPalettes; + private static final IBlockData AIR = ((BlockMaterial_1_13) BlockTypes.AIR.getMaterial()).getState(); /** * A FaweSections object represents a chunk and the blocks that you wish to change in it. @@ -70,16 +87,22 @@ public class BukkitChunk_1_13 extends IntFaweChunk { super(parent, x, z); } - public BukkitChunk_1_13(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air, byte[] heightMap) { - super(parent, x, z, ids, count, air, heightMap); + public BukkitChunk_1_13(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { + super(parent, x, z, ids, count, air); } - public void storeBiomes(BiomeType[] biomes) { - this.biomes = Arrays.copyOf(biomes, biomes.length); + public void storeBiomes(BiomeBase[] biomes) { + if (biomes != null) { + if (this.biomes == null) { + this.biomes = new BiomeType[256]; + } + for (int i = 0; i < 256; i++) { + this.biomes[i] = BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(biomes[i])); + } + } } public boolean storeTile(TileEntity tile, BlockPosition pos) { - NBTTagCompound tag = new NBTTagCompound(); CompoundTag nativeTag = getParent().getTag(tile); setTile(pos.getX() & 15, pos.getY(), pos.getZ() & 15, nativeTag); return true; @@ -89,11 +112,6 @@ public class BukkitChunk_1_13 extends IntFaweChunk { if (ent instanceof EntityPlayer || BukkitQueue_0.getAdapter() == null) { return false; } - int x = (MathMan.roundInt(ent.locX) & 15); - int z = (MathMan.roundInt(ent.locZ) & 15); - int y = (MathMan.roundInt(ent.locY) & 0xFF); - int i = FaweCache.CACHE_I[y][z][x]; - int j = FaweCache.CACHE_J[y][z][x]; EntityTypes type = ent.P(); MinecraftKey id = EntityTypes.getName(type); if (id != null) { @@ -109,53 +127,118 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } } + public boolean storeSection(ChunkSection section, int layer) throws IllegalAccessException { + if (sectionPalettes == null) { + // TODO FIXME don't copy light + sectionPalettes = new ChunkSection[16]; + } + sectionPalettes[layer] = section; + return true; + } + + public ChunkSection copy(ChunkSection current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { + int y = current.getYPosition(); + ChunkSection newSection = new ChunkSection(y, current.getSkyLightArray() != null); + + // Copy light + NibbleArray skyLight = current.getSkyLightArray(); + NibbleArray blockLight = current.getEmittedLightArray(); + + NibbleArray newBlockLight = newSection.getEmittedLightArray(); + NibbleArray newSkyLight = newSection.getSkyLightArray(); + + byte[] newBlockBytes = newBlockLight.asBytes(); + byte[] blockLightBytes = blockLight.asBytes(); + for (int i = 0; i < 2048; i++) newBlockBytes[i] = blockLightBytes[i]; + if (skyLight != null) { + byte[] newSkyBytes = newSkyLight.asBytes(); + byte[] skyLightBytes = skyLight.asBytes(); + for (int i = 0; i < 2048; i++) newSkyBytes[i] = skyLightBytes[i]; + } + + // Copy counters + Object nonEmptyBlockCount = BukkitQueue_1_13.fieldNonEmptyBlockCount.get(current); + BukkitQueue_1_13.fieldNonEmptyBlockCount.set(newSection, nonEmptyBlockCount); + + Object tickingBlockCount = BukkitQueue_1_13.fieldTickingBlockCount.get(current); + BukkitQueue_1_13.fieldTickingBlockCount.set(newSection, tickingBlockCount); + + Object liquidCount = BukkitQueue_1_13.fieldLiquidCount.get(current); + BukkitQueue_1_13.fieldLiquidCount.set(newSection, liquidCount); + + // Copy blocks + DataPaletteBlock blocks = current.getBlocks(); + DataPaletteBlock blocksCopy = copy(blocks); + BukkitQueue_1_13.fieldSection.set(newSection, blocksCopy); + + return newSection; + } + + public DataPaletteBlock copy(DataPaletteBlock current) throws IllegalAccessException, InvocationTargetException, NoSuchFieldException { + // Clone palette + DataPalette currentPalette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(current); + DataPaletteBlock paletteBlock = newDataPaletteBlock(); + int size = BukkitQueue_1_13.fieldSize.getInt(current); + + DataPalette newPalette = currentPalette; + if (currentPalette instanceof DataPaletteHash) { + // TODO optimize resize + newPalette = new DataPaletteHash<>(Block.REGISTRY_ID, size, paletteBlock, GameProfileSerializer::d, GameProfileSerializer::a); + RegistryID currReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(currentPalette); + RegistryID newReg = (RegistryID) BukkitQueue_1_13.fieldHashBlocks.get(newPalette); + int arrLen = 1 << size; + System.arraycopy(fieldRegistryb.get(currReg), 0, fieldRegistryb.get(newReg), 0, arrLen); + System.arraycopy(fieldRegistryc.get(currReg), 0, fieldRegistryc.get(newReg), 0, arrLen); + System.arraycopy(fieldRegistryd.get(currReg), 0, fieldRegistryd.get(newReg), 0, arrLen); + fieldRegistrye.set(newReg, fieldRegistrye.get(currReg)); + fieldRegistryf.set(newReg, fieldRegistryf.get(currReg)); + } else if (currentPalette instanceof DataPaletteLinear) { + // TODO optimize resize + newPalette = new DataPaletteLinear<>(Block.REGISTRY_ID, size, paletteBlock, GameProfileSerializer::d); + Object[] currArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(currentPalette)); + Object[] newArray = ((Object[]) BukkitQueue_1_13.fieldLinearBlocks.get(newPalette)); + BukkitQueue_1_13.fieldLinearIndex.set(newPalette, BukkitQueue_1_13.fieldLinearIndex.get(currentPalette)); + for (int i = 0; i < newArray.length; i++) newArray[i] = currArray[i]; + } + + BukkitQueue_1_13.fieldPalette.set(paletteBlock, newPalette); + // Clone size + BukkitQueue_1_13.fieldSize.set(paletteBlock, size); + // Clone palette + DataBits currentBits = (DataBits) BukkitQueue_1_13.fieldBits.get(current); + DataBits newBits = new DataBits(currentBits.c(), currentBits.b(), currentBits.a().clone()); + BukkitQueue_1_13.fieldBits.set(paletteBlock, newBits); + + // TODO copy only if different + Object defaultBlock = BukkitQueue_1_13.fieldDefaultBlock.get(current); + if (defaultBlock != AIR) { + ReflectionUtils.setFailsafeFieldValue(BukkitQueue_1_13.fieldDefaultBlock, paletteBlock, BukkitQueue_1_13.fieldDefaultBlock.get(current)); + } + + return paletteBlock; + } + @Override public IntFaweChunk copy(boolean shallow) { BukkitChunk_1_13 copy; if (shallow) { - copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), ids, count, air, heightMap); + copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), ids, 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(), heightMap.clone()); + copy = new BukkitChunk_1_13(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); copy.biomes = biomes != null ? biomes.clone() : null; copy.chunk = chunk; } if (sectionPalettes != null) { - copy.sectionPalettes = new DataPaletteBlock[16]; + copy.sectionPalettes = new ChunkSection[16]; try { for (int i = 0; i < sectionPalettes.length; i++) { - DataPaletteBlock current = sectionPalettes[i]; + ChunkSection current = sectionPalettes[i]; if (current == null) { continue; } - // Clone palette - DataPalette currentPalette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(current); - if (!(currentPalette instanceof DataPaletteGlobal)) { - // TODO support non global palette - BukkitQueue_1_13.methodResize.invoke(current, 128); - currentPalette = (DataPalette) BukkitQueue_1_13.fieldPalette.get(current); - if (!(currentPalette instanceof DataPaletteGlobal)) { - throw new RuntimeException("Palette must be global!"); - } - } - DataPaletteBlock paletteBlock = newDataPaletteBlock(); - BukkitQueue_1_13.fieldPalette.set(paletteBlock, currentPalette); - // Clone size - BukkitQueue_1_13.fieldSize.set(paletteBlock, BukkitQueue_1_13.fieldSize.get(current)); - // Clone palette - DataBits currentBits = (DataBits) BukkitQueue_1_13.fieldBits.get(current); - DataBits newBits = new DataBits(1, 0); - for (Field field : DataBits.class.getDeclaredFields()) { - field.setAccessible(true); - Object currentValue = field.get(currentBits); - if (currentValue instanceof long[]) { - currentValue = ((long[]) currentValue).clone(); - } - field.set(newBits, currentValue); - } - BukkitQueue_1_13.fieldBits.set(paletteBlock, newBits); - copy.sectionPalettes[i] = paletteBlock; + sectionPalettes[i] = copy(current); } } catch (Throwable e) { MainUtil.handleError(e); @@ -178,26 +261,13 @@ public class BukkitChunk_1_13 extends IntFaweChunk { return; } int[][] arrays = getCombinedIdArrays(); - char lastChar = Character.MAX_VALUE; for (int layer = 0; layer < 16; layer++) { if (getCount(layer) > 0) { if (sectionPalettes == null) { - sectionPalettes = new DataPaletteBlock[16]; - } - DataPaletteBlock palette = newDataPaletteBlock(); - int[] blocks = getIdArray(layer); - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - int combinedId = blocks[FaweCache.CACHE_J[y][z][x]]; - if (combinedId != 0) { - BlockType state = BlockTypes.getFromStateId(combinedId); - IBlockData blockData = ((BlockMaterial_1_13) state.getMaterial()).getState(); - palette.setBlock(x, y, z, blockData); - } - } - } + sectionPalettes = new ChunkSection[16]; } + int[] array = arrays[layer]; + sectionPalettes[layer] = BukkitQueue_1_13.newChunkSection(layer, getParent().hasSky(), array); } } } @@ -215,6 +285,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { @Override 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; final Chunk chunk = this.getChunk(); @@ -230,8 +301,6 @@ public class BukkitChunk_1_13 extends IntFaweChunk { ChunkSection[] sections = nmsChunk.getSections(); List[] entities = nmsChunk.getEntitySlices(); Map tiles = nmsChunk.getTileEntities(); - // Set heightmap - getParent().setHeightMap(this, heightMap); // Remove entities HashSet entsToRemove = this.getEntityRemoves(); if (!entsToRemove.isEmpty()) { @@ -293,7 +362,9 @@ public class BukkitChunk_1_13 extends IntFaweChunk { if (y > layerYEnd || y < layerYStart) continue; int x = (MathMan.roundInt(entity.locX) & 15); int z = (MathMan.roundInt(entity.locZ) & 15); - if (array[FaweCache.CACHE_J[y][z][x]] != 0) { + + int index = (((y & 0xF) << 8) | (z << 4) | x); + if (array[index] != 0) { if (copy != null) { copy.storeEntity(entity); } @@ -341,7 +412,6 @@ public class BukkitChunk_1_13 extends IntFaweChunk { synchronized (BukkitQueue_0.class) { nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); } -// createdEntities.add(entity.getUniqueID()); } } } @@ -359,19 +429,20 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } ChunkSection section = sections[j]; if (copy != null) { - copy.storeSection(section, j); + if (section != null) { + copy.storeSection(copy(section), j); + } } if (section == null) { if (count == countAir) { continue; } if (this.sectionPalettes != null && this.sectionPalettes[j] != null) { - section = sections[j] = getParent().newChunkSection(j << 4, flag, null); - getParent().setPalette(section, this.sectionPalettes[j]); + section = sections[j] = this.sectionPalettes[j]; getParent().setCount(0, count - this.getAir(j), section); continue; } else { - sections[j] = getParent().newChunkSection(j << 4, flag, array); // TODO set data + sections[j] = getParent().newChunkSection(j << 4, flag, array); continue; } } else if (count >= 4096) { @@ -380,7 +451,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { continue; } if (this.sectionPalettes != null && this.sectionPalettes[j] != null) { - getParent().setPalette(section, this.sectionPalettes[j]); + section = sections[j] = this.sectionPalettes[j]; getParent().setCount(0, count - this.getAir(j), section); continue; } else { @@ -392,26 +463,25 @@ public class BukkitChunk_1_13 extends IntFaweChunk { DataPaletteBlock nibble = section.getBlocks(); int nonEmptyBlockCount = 0; IBlockData existing; - for (int y = 0; y < 16; y++) { - short[][] i1 = FaweCache.CACHE_J[y]; + + for (int y = 0, i = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { - short[] i2 = i1[z]; - for (int x= 0; x < 16; x++) { - int combinedId = array[i2[x]]; + for (int x= 0; x < 16; x++, i++) { + int combinedId = array[i]; switch (combinedId) { case 0: continue; - case 1: - case 2: - case 3: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: existing = nibble.a(x, y, z); if (!existing.isAir()) { if (existing.e() > 0) { getParent().getRelighter().addLightUpdate(bx + x, by + y, bz + z); } nonEmptyBlockCount--; + nibble.setBlock(x, y, z, AIR); } - nibble.setBlock(x, y, z, BukkitQueue_1_13.air); continue; default: existing = nibble.a(x, y, z); @@ -422,7 +492,9 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } else { nonEmptyBlockCount++; } - nibble.setBlock(x, y, z, getParent().IBD_CACHE[(int) combinedId]); + BlockState state = BlockState.getFromInternalId(combinedId); + IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + nibble.setBlock(x, y, z, ibd); } } } @@ -440,13 +512,13 @@ public class BukkitChunk_1_13 extends IntFaweChunk { int lx = pos.getX() & 15; int ly = pos.getY(); int lz = pos.getZ() & 15; - int j = FaweCache.CACHE_I[ly][lz][lx]; - int[] array = this.getIdArray(j); + int layer = ly >> 4; + int[] array = this.getIdArray(layer); if (array == null) { continue; } - int k = FaweCache.CACHE_J[ly][lz][lx]; - if (array[k] != 0) { + int index = (((ly & 0xF) << 8) | (lz << 4) | lx); + if (array[index] != 0) { if (toRemove == null) { toRemove = new HashMap<>(); } @@ -461,7 +533,7 @@ public class BukkitChunk_1_13 extends IntFaweChunk { for (Map.Entry entry : toRemove.entrySet()) { BlockPosition bp = entry.getKey(); TileEntity tile = entry.getValue(); - nmsWorld.s(bp); + nmsWorld.n(bp); tiles.remove(bp); tile.z(); tile.invalidateBlockCache(); @@ -472,14 +544,15 @@ public class BukkitChunk_1_13 extends IntFaweChunk { // Set biomes if (this.biomes != null) { - if (copy != null) { - copy.storeBiomes(nmsChunk.getBiomeIndex()); - } BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex(); + if (copy != null) { + copy.storeBiomes(currentBiomes); + } for (int i = 0 ; i < this.biomes.length; i++) { BiomeType biome = this.biomes[i]; if (biome != null) { - currentBiomes[i] = biome; + Biome craftBiome = adapter.adapt(biome); + currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome); } } } @@ -514,4 +587,4 @@ public class BukkitChunk_1_13 extends IntFaweChunk { } return this; } -} +} \ No newline at end of file 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 new file mode 100644 index 000000000..bb6357b8e --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitChunk_1_13_Copy.java @@ -0,0 +1,89 @@ +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() { + for (int i = 0; i < ids.length; i++) { + getIdArray(i); + } + return super.getCombinedIdArrays(); + } + + @Override + public int[] getIdArray(int layer) { + 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; + } + + @Override + public void setTile(int x, int y, int z, CompoundTag tile) { + throw new UnsupportedOperationException("Read only"); + } + + @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 new file mode 100644 index 000000000..1d1bd386a --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/BukkitQueue_1_13.java @@ -0,0 +1,918 @@ +package com.boydti.fawe.bukkit.v1_13; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.bukkit.BukkitPlayer; +import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13; +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.example.IntFaweChunk; +import com.boydti.fawe.jnbt.anvil.BitArray4096; +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.RegionWrapper; +import com.boydti.fawe.object.brush.visualization.VisualChunk; +import com.boydti.fawe.object.visitor.FaweChunkVisitor; +import com.boydti.fawe.util.MainUtil; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.ReflectionUtils; +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.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import net.minecraft.server.v1_13_R2.BiomeBase; +import net.minecraft.server.v1_13_R2.Block; +import net.minecraft.server.v1_13_R2.BlockPosition; +import net.minecraft.server.v1_13_R2.ChunkProviderGenerate; +import net.minecraft.server.v1_13_R2.ChunkProviderServer; +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.DataPaletteHash; +import net.minecraft.server.v1_13_R2.DataPaletteLinear; +import net.minecraft.server.v1_13_R2.Entity; +import net.minecraft.server.v1_13_R2.EntityPlayer; +import net.minecraft.server.v1_13_R2.EnumSkyBlock; +import net.minecraft.server.v1_13_R2.GameProfileSerializer; +import net.minecraft.server.v1_13_R2.IBlockData; +import net.minecraft.server.v1_13_R2.NBTTagCompound; +import net.minecraft.server.v1_13_R2.Packet; +import net.minecraft.server.v1_13_R2.PacketDataSerializer; +import net.minecraft.server.v1_13_R2.PacketPlayOutMapChunk; +import net.minecraft.server.v1_13_R2.PacketPlayOutMultiBlockChange; +import net.minecraft.server.v1_13_R2.PlayerChunk; +import net.minecraft.server.v1_13_R2.PlayerChunkMap; +import net.minecraft.server.v1_13_R2.RegistryID; +import net.minecraft.server.v1_13_R2.TileEntity; +import net.minecraft.server.v1_13_R2.WorldChunkManager; +import net.minecraft.server.v1_13_R2.WorldData; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.atomic.LongAdder; + +public class BukkitQueue_1_13 extends BukkitQueue_0 { + + protected final static Field fieldBits; + protected final static Field fieldPalette; + protected final static Field fieldSize; + + protected final static Field fieldHashBlocks; + protected final static Field fieldLinearBlocks; + protected final static Field fieldHashIndex; + protected final static Field fieldRegistryb; + protected final static Field fieldRegistryc; + protected final static Field fieldRegistryd; + protected final static Field fieldRegistrye; + protected final static Field fieldRegistryf; + + protected final static Field fieldLinearIndex; + protected final static Field fieldDefaultBlock; + + protected final static Field fieldTickingBlockCount; + protected final static Field fieldNonEmptyBlockCount; + protected final static Field fieldSection; + protected final static Field fieldLiquidCount; + protected final static Field fieldEmittedLight; + protected final static Field fieldSkyLight; + + +// protected final static Field fieldBiomes; + + protected final static Field fieldChunkGenerator; + protected final static Field fieldSeed; +// protected final static Field fieldBiomeCache; +// protected final static Field fieldBiomes2; + protected final static Field fieldGenLayer1; + protected final static Field fieldGenLayer2; + protected final static Field fieldSave; +// protected final static MutableGenLayer genLayer; + protected final static ChunkSection emptySection; + +// protected static final Method methodResize; + + static { + try { + emptySection = new ChunkSection(0, true); + Arrays.fill(emptySection.getSkyLightArray().asBytes(), (byte) 255); + fieldSection = ChunkSection.class.getDeclaredField("blockIds"); + fieldLiquidCount = ChunkSection.class.getDeclaredField("e"); + fieldEmittedLight = ChunkSection.class.getDeclaredField("emittedLight"); + fieldSkyLight = ChunkSection.class.getDeclaredField("skyLight"); + + + fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); + fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); + fieldSection.setAccessible(true); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount.setAccessible(true); + + fieldLiquidCount.setAccessible(true); + fieldEmittedLight.setAccessible(true); + fieldSkyLight.setAccessible(true); + +// fieldBiomes = ChunkProviderGenerate.class.getDeclaredField("D"); // * +// fieldBiomes.setAccessible(true); + + fieldChunkGenerator = ChunkProviderServer.class.getDeclaredField("chunkGenerator"); + fieldChunkGenerator.setAccessible(true); + fieldSeed = WorldData.class.getDeclaredField("e"); + fieldSeed.setAccessible(true); + +// fieldBiomeCache = WorldChunkManager.class.getDeclaredField("d"); // * +// fieldBiomeCache.setAccessible(true); +// fieldBiomes2 = WorldChunkManager.class.getDeclaredField("e"); // * +// fieldBiomes2.setAccessible(true); + fieldGenLayer1 = WorldChunkManager.class.getDeclaredField("b") ; + fieldGenLayer2 = WorldChunkManager.class.getDeclaredField("c") ; + fieldGenLayer1.setAccessible(true); + fieldGenLayer2.setAccessible(true); + + fieldSave = ReflectionUtils.setAccessible(net.minecraft.server.v1_13_R2.Chunk.class.getDeclaredField("s")); //* + + fieldHashBlocks = DataPaletteHash.class.getDeclaredField("b"); + fieldHashBlocks.setAccessible(true); + fieldLinearBlocks = DataPaletteLinear.class.getDeclaredField("b"); + fieldLinearBlocks.setAccessible(true); + + fieldHashIndex = DataPaletteHash.class.getDeclaredField("f"); + fieldHashIndex.setAccessible(true); + + fieldRegistryb = RegistryID.class.getDeclaredField("b"); + fieldRegistryc = RegistryID.class.getDeclaredField("c"); + fieldRegistryd = RegistryID.class.getDeclaredField("d"); + fieldRegistrye = RegistryID.class.getDeclaredField("e"); + fieldRegistryf = RegistryID.class.getDeclaredField("f"); + fieldRegistryb.setAccessible(true); + fieldRegistryc.setAccessible(true); + fieldRegistryd.setAccessible(true); + fieldRegistrye.setAccessible(true); + fieldRegistryf.setAccessible(true); + + fieldLinearIndex = DataPaletteLinear.class.getDeclaredField("f"); + fieldLinearIndex.setAccessible(true); + + fieldDefaultBlock = DataPaletteBlock.class.getDeclaredField("g"); + fieldDefaultBlock.setAccessible(true); + + fieldSize = DataPaletteBlock.class.getDeclaredField("i"); + fieldSize.setAccessible(true); + + fieldBits = DataPaletteBlock.class.getDeclaredField("a"); + fieldBits.setAccessible(true); + + fieldPalette = DataPaletteBlock.class.getDeclaredField("h"); + fieldPalette.setAccessible(true); + +// methodResize = DataPaletteBlock.class.getDeclaredMethod("b", int.class); +// methodResize.setAccessible(true); + + Fawe.debug("Using adapter: " + getAdapter()); + Fawe.debug("========================================="); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public BukkitQueue_1_13(final com.sk89q.worldedit.world.World world) { + super(world); + getImpWorld(); + } + + public BukkitQueue_1_13(final String world) { + super(world); + getImpWorld(); + } + + private boolean save(net.minecraft.server.v1_13_R2.Chunk chunk, ChunkProviderServer cps) { + cps.saveChunk(chunk, false); + chunk.a(false); + return true; + } + + @Override + public ChunkSection[] getSections(net.minecraft.server.v1_13_R2.Chunk chunk) { + return chunk.getSections(); + } + + @Override + public net.minecraft.server.v1_13_R2.Chunk loadChunk(World world, int x, int z, boolean generate) { + ChunkProviderServer provider = ((CraftWorld) world).getHandle().getChunkProvider(); + if (generate) { + return provider.getChunkAt(x, z, true, true); + } else { + return provider.getChunkAt(x, z, true, false); + } + } + + @Override + public ChunkSection[] getCachedSections(World world, int cx, int cz) { + net.minecraft.server.v1_13_R2.Chunk chunk = ((CraftWorld) world).getHandle().getChunkProvider().getChunkAt(cx, cz, false, false); + if (chunk != null) { + return chunk.getSections(); + } + return null; + } + + @Override + public net.minecraft.server.v1_13_R2.Chunk getCachedChunk(World world, int cx, int cz) { + return ((CraftWorld) world).getHandle().getChunkProvider().getChunkAt(cx, cz, false, false); + } + + @Override + public ChunkSection getCachedSection(ChunkSection[] chunkSections, int cy) { + return chunkSections[cy]; + } + + @Override + public void saveChunk(net.minecraft.server.v1_13_R2.Chunk chunk) { + chunk.f(true); // Set Modified + chunk.mustSave = true; + } + + @Override + public boolean regenerateChunk(World world, int x, int z, BiomeType biome, Long seed) { +// if (biome != null) { +// try { +// if (seed == null) { +// seed = world.getSeed(); +// } +// nmsWorld.worldData.getSeed(); +// boolean result; +// ChunkProviderGenerate generator = new ChunkProviderGenerate(nmsWorld, seed, false, ""); +// Biome bukkitBiome = getAdapter().getBiome(biome.getId()); +// BiomeBase base = BiomeBase.getBiome(biome.getId()); +// fieldBiomes.set(generator, new BiomeBase[]{base}); +// boolean cold = base.getTemperature() <= 1; +// net.minecraft.server.v1_13_R2.ChunkGenerator existingGenerator = nmsWorld.getChunkProvider().chunkGenerator; +// long existingSeed = world.getSeed(); +// { +// if (genLayer == null) genLayer = new MutableGenLayer(seed); +// genLayer.set(biome.getId()); +// Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager()); +// Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager()); +// fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer); +// fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer); +// +// fieldSeed.set(nmsWorld.worldData, seed); +// +// ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new BiomeCache(this.nmsWorld.getWorldChunkManager())); +// +// ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProvider(), generator); +// +// keepLoaded.remove(MathMan.pairInt(x, z)); +// result = getWorld().regenerateChunk(x, z); +// net.minecraft.server.v1_13_R2.Chunk nmsChunk = getCachedChunk(world, x, z); +// if (nmsChunk != null) { +// nmsChunk.f(true); // Set Modified +// nmsChunk.mustSave = true; +// } +// +// ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProvider(), existingGenerator); +// +// fieldSeed.set(nmsWorld.worldData, existingSeed); +// +// fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1); +// fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2); +// } +// return result; +// } catch (Throwable e) { +// e.printStackTrace(); +// } +// } + return super.regenerateChunk(world, x, z, biome, seed); + } + + @Override + public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean saveChunks, final boolean load) { + throw new UnsupportedOperationException("Anvil not implemented yet"); +// TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Boolean value) { +// long start = System.currentTimeMillis(); +// long last = start; +// synchronized (RegionFileCache.class) { +// World world = getWorld(); +// if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false); +// ChunkProviderServer provider = nmsWorld.getChunkProvider(); +// +// boolean mustSave = false; +// boolean[][] chunksUnloaded = null; +// { // Unload chunks +// Iterator iter = provider.a().iterator(); +// while (iter.hasNext()) { +// net.minecraft.server.v1_13_R2.Chunk chunk = iter.next(); +// if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) { +// boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ); +// if (isIn) { +// if (!load) { +// mustSave |= saveChunks && save(chunk, provider); +// continue; +// } +// iter.remove(); +// boolean save = saveChunks && chunk.a(false); +// mustSave |= save; +// provider.unloadChunk(chunk, save); +// if (chunksUnloaded == null) { +// chunksUnloaded = new boolean[32][]; +// } +// int relX = chunk.locX & 31; +// boolean[] arr = chunksUnloaded[relX]; +// if (arr == null) { +// arr = chunksUnloaded[relX] = new boolean[32]; +// } +// arr[chunk.locZ & 31] = true; +// } +// } +// } +// } +// if (mustSave) { +// provider.c(); // TODO only the necessary chunks +// } +// +// File unloadedRegion = null; +// if (load && !RegionFileCache.a.isEmpty()) { +// Map map = RegionFileCache.a; +// Iterator> iter = map.entrySet().iterator(); +// String requiredPath = world.getName() + File.separator + "region"; +// while (iter.hasNext()) { +// Map.Entry entry = iter.next(); +// File file = entry.getKey(); +// int[] regPos = MainUtil.regionNameToCoords(file.getPath()); +// if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) { +// if (file.exists()) { +// unloadedRegion = file; +// RegionFile regionFile = entry.getValue(); +// iter.remove(); +// try { +// regionFile.c(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// break; +// } +// } +// } +// +// long now = System.currentTimeMillis(); +// if (whileLocked != null) whileLocked.run(); +// if (!load) return; +// +// { // Load the region again +// if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) { +// final boolean[][] finalChunksUnloaded = chunksUnloaded; +// TaskManager.IMP.async(() -> { +// int bx = mcaX << 5; +// int bz = mcaZ << 5; +// for (int x = 0; x < finalChunksUnloaded.length; x++) { +// boolean[] arr = finalChunksUnloaded[x]; +// if (arr != null) { +// for (int z = 0; z < arr.length; z++) { +// if (arr[z]) { +// int cx = bx + x; +// int cz = bz + z; +// SetQueue.IMP.addTask(new Runnable() { +// @Override +// public void run() { +// net.minecraft.server.v1_13_R2.Chunk chunk = provider.getChunkAt(cx, cz, null, false); +// if (chunk != null) { +// PlayerChunk pc = getPlayerChunk(nmsWorld, cx, cz); +// if (pc != null) { +// sendChunk(pc, chunk, 0); +// } +// } +// } +// }); +// } +// } +// } +// } +// }); +// } +// } +// } +// } +// }); +// return true; + } + + @Override + public boolean next(int amount, long time) { + return super.next(amount, time); + } + + @Override + public void setSkyLight(ChunkSection section, int x, int y, int z, int value) { + section.getSkyLightArray().a(x & 15, y & 15, z & 15, value); + } + + @Override + public void setBlockLight(ChunkSection section, int x, int y, int z, int value) { + section.getEmittedLightArray().a(x & 15, y & 15, z & 15, value); + } + +// @Override +// public World createWorld(final WorldCreator creator) { +// final String name = creator.name(); +// ChunkGenerator generator = creator.generator(); +// final CraftServer server = (CraftServer) Bukkit.getServer(); +// final MinecraftServer console = server.getServer(); +// final File folder = new File(server.getWorldContainer(), name); +// final World world = server.getWorld(name); +// final WorldType type = WorldType.getType(creator.type().getName()); +// final boolean generateStructures = creator.generateStructures(); +// if (world != null) { +// return world; +// } +// if (folder.exists() && !folder.isDirectory()) { +// throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder"); +// } +// TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(Object value) { +// try { +// Field field = CraftServer.class.getDeclaredField("worlds"); +// field.setAccessible(true); +// Map existing = (Map) field.get(server); +// if (!existing.getClass().getName().contains("SynchronizedMap")) { +// field.set(server, Collections.synchronizedMap(existing)); +// } +// } catch (Throwable e) { +// e.printStackTrace(); +// } +// } +// }); +// if (generator == null) { +// generator = server.getGenerator(name); +// } +// int dimension = 10 + console.worlds.size(); +// boolean used = false; +// do { +// for (final WorldServer ws : console.worlds) { +// used = (ws.dimension == dimension); +// if (used) { +// ++dimension; +// break; +// } +// } +// } while (used); +// final boolean hardcore = false; +// final IDataManager sdm = new ServerNBTManager(server.getWorldContainer(), name, true, server.getHandle().getServer().dataConverterManager); +// WorldData worlddata = sdm.getWorldData(); +// final WorldSettings worldSettings; +// if (worlddata == null) { +// worldSettings = new WorldSettings(creator.seed(), EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type); +// worldSettings.setGeneratorSettings(creator.generatorSettings()); +// worlddata = new WorldData(worldSettings, name); +// } else { +// worldSettings = null; +// } +// worlddata.checkName(name); +// final WorldServer internal = (WorldServer)new WorldServer(console, sdm, worlddata, dimension, console.methodProfiler, creator.environment(), generator).b(); +// startSet(true); // Temporarily allow async chunk load since the world isn't added yet +// if (worldSettings != null) { +// internal.a(worldSettings); +// } +// endSet(true); +// internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle(); +// internal.tracker = new EntityTracker(internal); +// internal.addIWorldAccess(new WorldManager(console, internal)); +// internal.worldData.setDifficulty(EnumDifficulty.EASY); +// internal.setSpawnFlags(true, true); +// if (generator != null) { +// internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld())); +// } +// // Add the world +// return TaskManager.IMP.sync(new RunnableVal() { +// @Override +// public void run(World value) { +// console.worlds.add(internal); +// server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld())); +// server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld())); +// this.value = internal.getWorld(); +// } +// }); +// } + + @Override + public int getCombinedId4Data(ChunkSection lastSection, int x, int y, int z) { + DataPaletteBlock dataPalette = lastSection.getBlocks(); + IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + return ((Spigot_v1_13_R2) getAdapter()).adaptToInt(ibd); + } + + @Override + public BiomeType getBiome(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int z) { + BiomeBase base = chunk.getBiomeIndex()[((z & 15) << 4) + (x & 15)]; + return getAdapter().adapt(CraftBlock.biomeBaseToBiome(base)); + } + + @Override + public int getOpacity(ChunkSection section, int x, int y, int z) { + DataPaletteBlock dataPalette = section.getBlocks(); + IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + pos.a(x, y, z); + return ibd.b(nmsWorld, pos); + } + + @Override + public int getBrightness(ChunkSection section, int x, int y, int z) { + DataPaletteBlock dataPalette = section.getBlocks(); + IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + return ibd.e(); + } + + @Override + public int getOpacityBrightnessPair(ChunkSection section, int x, int y, int z) { + DataPaletteBlock dataPalette = section.getBlocks(); + IBlockData ibd = dataPalette.a(x & 15, y & 15, z & 15); + pos.a(x, y, z); + int opacity = ibd.b(nmsWorld, pos); + int brightness = ibd.e(); + return MathMan.pair16(brightness, opacity); + } + + @Override + public void sendChunk(int x, int z, int bitMask) { + net.minecraft.server.v1_13_R2.Chunk chunk = getCachedChunk(getWorld(), x, z); + if (chunk != null) { + sendChunk(getPlayerChunk((WorldServer) chunk.getWorld(), chunk.locX, chunk.locZ), chunk, bitMask); + } + } + + @Override + public void sendChunkUpdatePLIB(FaweChunk chunk, FawePlayer... players) { +// PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); +// ProtocolManager manager = ProtocolLibrary.getProtocolManager(); +// WirePacket packet = null; +// try { +// for (int i = 0; i < players.length; i++) { +// CraftPlayer bukkitPlayer = ((CraftPlayer) ((BukkitPlayer) players[i]).parent); +// EntityPlayer player = bukkitPlayer.getHandle(); +// +// if (playerManager.a(player, chunk.getX(), chunk.getZ())) { +// if (packet == null) { +// byte[] data; +// byte[] buffer = new byte[8192]; +// if (chunk instanceof LazyFaweChunk) { +// chunk = (FaweChunk) chunk.getChunk(); +// } +// if (chunk instanceof MCAChunk) { +// data = new MCAChunkPacket((MCAChunk) chunk, true, true, hasSky()).apply(buffer); +// } else { +// data = new FaweChunkPacket(chunk, true, true, hasSky()).apply(buffer); +// } +// packet = new WirePacket(PacketType.Play.Server.MAP_CHUNK, data); +// } +// manager.sendWirePacket(bukkitPlayer, packet); +// } +// } +// } catch (InvocationTargetException e) { +// throw new RuntimeException(e); +// } + super.sendChunkUpdatePLIB(chunk, players); // TODO remove + } + + @Override + public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) { + try { + PlayerChunkMap playerManager = ((CraftWorld) getWorld()).getHandle().getPlayerChunkMap(); + boolean watching = false; + boolean[] watchingArr = new boolean[players.length]; + for (int i = 0; i < players.length; i++) { + EntityPlayer player = ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle(); + if (playerManager.a(player, chunk.getX(), chunk.getZ())) { + watchingArr[i] = true; + watching = true; + } + } + if (!watching) return; + final LongAdder size = new LongAdder(); + if (chunk instanceof VisualChunk) { + size.add(((VisualChunk) chunk).size()); + } else if (chunk instanceof IntFaweChunk) { + size.add(((IntFaweChunk) chunk).getTotalCount()); + } else { + chunk.forEachQueuedBlock(new FaweChunkVisitor() { + @Override + public void run(int localX, int y, int localZ, int combined) { + size.add(1); + } + }); + } + if (size.intValue() == 0) return; + PacketPlayOutMultiBlockChange packet = new PacketPlayOutMultiBlockChange(); + ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(); + final PacketDataSerializer buffer = new PacketDataSerializer(byteBuf); + buffer.writeInt(chunk.getX()); + buffer.writeInt(chunk.getZ()); + buffer.d(size.intValue()); + chunk.forEachQueuedBlock(new FaweChunkVisitor() { + @Override + public void run(int localX, int y, int localZ, int combined) { + short index = (short) (localX << 12 | localZ << 8 | y); + if (combined < 16) combined = 0; + buffer.writeShort(index); + buffer.d(combined); + } + }); + packet.a(buffer); + for (int i = 0; i < players.length; i++) { + if (watchingArr[i]) ((CraftPlayer) ((BukkitPlayer) players[i]).parent).getHandle().playerConnection.sendPacket(packet); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void refreshChunk(FaweChunk fc) { + sendChunk(fc.getX(), fc.getZ(), fc.getBitMask()); + } + + public void sendPacket(int cx, int cz, Packet packet) { + PlayerChunk chunk = getPlayerChunk(nmsWorld, cx, cz); + if (chunk != null) { + for (EntityPlayer player : chunk.players) { + player.playerConnection.sendPacket(packet); + } + } + } + + private PlayerChunk getPlayerChunk(WorldServer w, int cx, int cz) { + PlayerChunkMap chunkMap = w.getPlayerChunkMap(); + PlayerChunk playerChunk = chunkMap.getChunk(cx, cz); + if (playerChunk == null) { + return null; + } + if (playerChunk.players.isEmpty()) { + return null; + } + return playerChunk; + } + + public boolean sendChunk(PlayerChunk playerChunk, net.minecraft.server.v1_13_R2.Chunk nmsChunk, int mask) { + if (playerChunk == null) { + return false; + } + if (mask == 0) { + PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535); + for (EntityPlayer player : playerChunk.players) { + player.playerConnection.sendPacket(packet); + } + return true; + } + // Send chunks + boolean empty = false; + ChunkSection[] sections = nmsChunk.getSections(); + for (int i = 0; i < sections.length; i++) { + if (sections[i] == null) { + sections[i] = emptySection; + empty = true; + } + } + if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { + PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280); + for (EntityPlayer player : playerChunk.players) { + player.playerConnection.sendPacket(packet); + } + mask = 255; + } + PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, mask); + for (EntityPlayer player : playerChunk.players) { + player.playerConnection.sendPacket(packet); + } + if (empty) { + for (int i = 0; i < sections.length; i++) { + if (sections[i] == emptySection) { + sections[i] = null; + } + } + } + return true; + } + + public boolean hasEntities(net.minecraft.server.v1_13_R2.Chunk nmsChunk) { + try { + final Collection[] entities = nmsChunk.entitySlices; + for (int i = 0; i < entities.length; i++) { + Collection slice = entities[i]; + if (slice != null && !slice.isEmpty()) { + return true; + } + } + } catch (Throwable ignore) {} + return false; + } + + @Override + public boolean removeSectionLighting(ChunkSection section, int layer, boolean sky) { + if (section != null) { + Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); + if (sky) { + byte[] light = section.getSkyLightArray().asBytes(); + if (light != null) { + Arrays.fill(light, (byte) 0); + } + } + return true; + } + return false; + } + + @Override + public void setFullbright(ChunkSection[] sections) { + for (int i = 0; i < sections.length; i++) { + ChunkSection section = sections[i]; + if (section != null) { + byte[] bytes = section.getSkyLightArray().asBytes(); + Arrays.fill(bytes, (byte) 255); + } + } + } + + @Override + public int getSkyLight(ChunkSection section, int x, int y, int z) { + return section.c(x & 15, y & 15, z & 15); + } + + @Override + public int getEmmittedLight(ChunkSection section, int x, int y, int z) { + return section.d(x & 15, y & 15, z & 15); + } + + @Override + public void relightBlock(int x, int y, int z) { + pos.c(x, y, z); + nmsWorld.c(EnumSkyBlock.BLOCK, pos); + } + + @Override + public void relightSky(int x, int y, int z) { + pos.c(x, y, z); + nmsWorld.c(EnumSkyBlock.SKY, pos); + } + + @Override + public void relight(int x, int y, int z) { + pos.c(x, y, z); + nmsWorld.r(pos); + } + + protected WorldServer nmsWorld; + + @Override + public World getImpWorld() { + World world = super.getImpWorld(); + if (world != null) { + this.nmsWorld = ((CraftWorld) world).getHandle(); + return super.getImpWorld(); + } else { + return null; + } + } + + public static void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException { + fieldTickingBlockCount.set(section, tickingBlockCount); + fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); + } + + public int getNonEmptyBlockCount(ChunkSection section) throws IllegalAccessException { + return (int) fieldNonEmptyBlockCount.get(section); + } + + public void setPalette(ChunkSection section, DataPaletteBlock palette) throws NoSuchFieldException, IllegalAccessException { + fieldSection.set(section, palette); + Arrays.fill(section.getEmittedLightArray().asBytes(), (byte) 0); + } + + public static ChunkSection newChunkSection(int y2, boolean flag, int[] blocks) { + if (blocks == null) { + return new ChunkSection(y2, flag); + } else { + ChunkSection section = new ChunkSection(y2, flag); + + int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); + int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); + long[] blockstates = FaweCache.BLOCK_STATES.get(); + int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); + try { + int num_palette = 0; + int air = 0; + for (int i = 0, j = 0; i < 4096; i++, j++) { + int stateId = blocks[i]; + switch (stateId) { + case 0: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + air++; + } + int ordinal = BlockState.getFromInternalId(stateId).getOrdinal(); // TODO fixme Remove all use of BlockTypes.BIT_OFFSET so that this conversion isn't necessary + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + // Set a value, because minecraft needs it for some reason + blockstates[0] = 0; + blockBitArrayEnd = 1; + } else { + BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + + // set palette & data bits + DataPaletteBlock dataPaletteBlocks = section.getBlocks(); + // private DataPalette h; + // protected DataBits a; + long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd); + DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); + DataPalette palette; +// DataPaletteHash hash = new DataPaletteHash<>(Block.REGISTRY_ID, num_palette, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); + palette = new DataPaletteLinear<>(Block.REGISTRY_ID, num_palette, dataPaletteBlocks, GameProfileSerializer::d); + // set palette + for (int i = 0; i < num_palette; i++) { + int ordinal = paletteToBlock[i]; + blockToPalette[ordinal] = Integer.MAX_VALUE; + BlockState state = BlockTypes.states[ordinal]; + IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState(); + palette.a(ibd); + } + try { + fieldBits.set(dataPaletteBlocks, nmsBits); + fieldPalette.set(dataPaletteBlocks, palette); + fieldSize.set(dataPaletteBlocks, num_palette); + setCount(0, 4096 - air, section); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + return section; + } catch (Throwable e){ + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + throw e; + } + } + } + + protected BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0); + + @Override + public CompoundTag getTileEntity(net.minecraft.server.v1_13_R2.Chunk chunk, int x, int y, int z) { + Map tiles = chunk.getTileEntities(); + pos.c(x, y, z); + TileEntity tile = tiles.get(pos); + return tile != null ? getTag(tile) : null; + } + + public CompoundTag getTag(TileEntity tile) { + try { + NBTTagCompound tag = new NBTTagCompound(); + tile.save(tag); // readTagIntoEntity + return (CompoundTag) toNative(tag); + } catch (Exception e) { + MainUtil.handleError(e); + return null; + } + } + + @Deprecated + public boolean unloadChunk(final String world, final Chunk chunk) { + net.minecraft.server.v1_13_R2.Chunk c = ((CraftChunk) chunk).getHandle(); + c.mustSave = false; + if (chunk.isLoaded()) { + chunk.unload(false, false); + } + return true; + } + + @Override + public BukkitChunk_1_13 getFaweChunk(int x, int z) { + return new BukkitChunk_1_13(this, x, z); + } +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 05774b84c..5a3edadaf 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.command.CommandMapping; +import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import org.bukkit.block.Block; import org.bukkit.event.Event.Result; @@ -110,11 +111,14 @@ public class WorldEditListener implements Listener { public void onPlayerCommand(PlayerCommandSendEvent event) { CommandLocals locals = new CommandLocals(); locals.put(Actor.class, plugin.wrapCommandSender(event.getPlayer())); - Set toRemove = plugin.getWorldEdit().getPlatformManager().getCommandManager().getDispatcher().getCommands().stream() - .filter(commandMapping -> !commandMapping.getCallable().testPermission(locals)) - .map(CommandMapping::getPrimaryAlias) - .collect(Collectors.toSet()); - event.getCommands().removeIf(toRemove::contains); + Dispatcher dispatcher = plugin.getWorldEdit().getPlatformManager().getCommandManager().getDispatcher(); + if (dispatcher != null) { + Set toRemove = dispatcher.getCommands().stream() + .filter(commandMapping -> !commandMapping.getCallable().testPermission(locals)) + .map(CommandMapping::getPrimaryAlias) + .collect(Collectors.toSet()); + event.getCommands().removeIf(toRemove::contains); + } } /** 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 c48e4035e..c3ed20bf8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,62 +1,43 @@ package com.boydti.fawe; +import com.boydti.fawe.object.collection.IterableThreadLocal; import com.sk89q.jnbt.*; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; import java.util.*; public class FaweCache { - /** - * [ y | z | x ] => index - */ - public final static short[][][] CACHE_I = new short[256][16][16]; - /** - * [ y | z | x ] => index - */ - public final static short[][][] CACHE_J = new short[256][16][16]; + public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { + @Override + public int[] init() { + int[] result = new int[BlockTypes.states.length]; + Arrays.fill(result, Integer.MAX_VALUE); + return result; + } + }; - /** - * [ i | j ] => x - */ - public final static byte[][] CACHE_X = new byte[16][]; - /** - * [ i | j ] => y - */ - public final static short[][] CACHE_Y = new short[16][4096]; - /** - * [ i | j ] => z - */ - public final static byte[][] CACHE_Z = new byte[16][]; + public static final IterableThreadLocal PALETTE_TO_BLOCK = new IterableThreadLocal() { + @Override + public int[] init() { + return new int[Character.MAX_VALUE]; + } + }; - static { - CACHE_X[0] = new byte[4096]; - CACHE_Z[0] = new byte[4096]; - for (int y = 0; y < 16; y++) { - CACHE_X[y] = CACHE_X[0]; - CACHE_Z[y] = CACHE_Z[0]; + public static final IterableThreadLocal BLOCK_STATES = new IterableThreadLocal() { + @Override + public long[] init() { + return new long[2048]; } - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - final short j = (short) (((y & 0xF) << 8) | (z << 4) | x); - CACHE_X[0][j] = (byte) x; - CACHE_Z[0][j] = (byte) z; - } - } + }; + + public static final IterableThreadLocal SECTION_BLOCKS = new IterableThreadLocal() { + @Override + public int[] init() { + return new int[4096]; } - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 256; y++) { - final short i = (short) (y >> 4); - final short j = (short) (((y & 0xF) << 8) | (z << 4) | x); - CACHE_I[y][z][x] = i; - CACHE_J[y][z][x] = j; - CACHE_Y[i][j] = (short) y; - } - } - } - } + }; public static Map asMap(Object... pairs) { HashMap map = new HashMap<>(pairs.length >> 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 73c7661fd..d435f4aa8 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 @@ -6,6 +6,7 @@ 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.*; @@ -15,7 +16,6 @@ public abstract class IntFaweChunk extends FaweChunk public final int[][] ids; public final short[] count; public final short[] air; - public final byte[] heightMap; public BiomeType[] biomes; public HashMap tiles; @@ -24,12 +24,11 @@ public abstract class IntFaweChunk extends FaweChunk public T chunk; - public IntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air, byte[] heightMap) { + public IntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { super(parent, x, z); this.ids = ids; this.count = count; this.air = air; - this.heightMap = heightMap; } /** @@ -44,7 +43,6 @@ public abstract class IntFaweChunk extends FaweChunk this.ids = new int[HEIGHT >> 4][]; this.count = new short[HEIGHT >> 4]; this.air = new short[HEIGHT >> 4]; - this.heightMap = new byte[256]; } @Override @@ -136,12 +134,11 @@ public abstract class IntFaweChunk extends FaweChunk @Override public int getBlockCombinedId(int x, int y, int z) { - short i = FaweCache.CACHE_I[y][z][x]; - int[] array = getIdArray(i); + int[] array = getIdArray(y >> 4); if (array == null) { return 0; } - return array[FaweCache.CACHE_J[y][z][x]]; + return array[(((y & 0xF) << 8) | (z << 4) | x)]; } @Override @@ -195,19 +192,20 @@ public abstract class IntFaweChunk extends FaweChunk @Override public void setBlock(int x, int y, int z, int combinedId) { - final int i = FaweCache.CACHE_I[y][z][x]; - final int j = FaweCache.CACHE_J[y][z][x]; + final int i = y >> 4; int[] vs = this.ids[i]; if (vs == null) { vs = this.ids[i] = new int[4096]; } - vs[j] = combinedId; + vs[(((y & 15) << 8) | (z << 4) | x)] = combinedId; this.count[i]++; - if (BlockTypes.getFromStateId(combinedId).getMaterial().isAir()) { - this.air[i]++; - return; + switch (combinedId) { + case 0: + case BlockID.AIR: + case BlockID.CAVE_AIR: + case BlockID.VOID_AIR: + this.air[i]++; } - heightMap[z << 4 | x] = (byte) y; return; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java index e8ca6d840..9fe3389a7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java @@ -76,7 +76,8 @@ public abstract class NMSMappedFaweQueue ex byte[] fix = new byte[(maxY + 1) >> 4]; boolean sky = hasSky(); if (sky) { - for (int i = cfc.ids.length - 1; i >= 0; i--) { + int layers = FaweChunk.HEIGHT >> 4; + for (int i = layers - 1; i >= 0; i--) { int air = cfc.getAir(i); int solid = cfc.getCount(i); if (air == 4096) { @@ -107,8 +108,6 @@ public abstract class NMSMappedFaweQueue ex } } - public abstract void setHeightMap(FaweChunk chunk, byte[] heightMap); - public abstract void setFullbright(CHUNKSECTION sections); public boolean removeLighting(CHUNKSECTION sections, RelightMode mode, boolean hasSky) { @@ -143,13 +142,12 @@ public abstract class NMSMappedFaweQueue ex if ((y < 0) || (y > maxY)) { return BlockTypes.AIR.getInternalId(); } - final int i = FaweCache.CACHE_I[y][z][x]; + final int i = y >> 4; final char[] section = sections[i]; if (section == null) { return 0; } - final int j = FaweCache.CACHE_J[y][z][x]; - return section[j] >> 4; + return section[(((y & 0xF) << 8) | (z << 4) | x)] >> 4; } public void saveChunk(CHUNK chunk) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java b/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java index 3d3789095..ed33a9b5e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/example/NMSRelighter.java @@ -409,8 +409,8 @@ public class NMSRelighter implements Relighter { } } - byte[] cacheX = FaweCache.CACHE_X[0]; - byte[] cacheZ = FaweCache.CACHE_Z[0]; +// byte[] cacheX = FaweCache.CACHE_X[0]; +// byte[] cacheZ = FaweCache.CACHE_Z[0]; for (int y = FaweChunk.HEIGHT - 1; y > 0; y--) { for (RelightSkyEntry chunk : chunks) { // Propogate skylight int layer = y >> 4; @@ -434,58 +434,58 @@ public class NMSRelighter implements Relighter { queue.removeSectionLighting(section, y >> 4, true); } - for (int j = 0; j <= maxY; j++) { - int x = cacheX[j]; - int z = cacheZ[j]; - byte value = mask[j]; - byte pair = (byte) queue.getOpacityBrightnessPair(section, x, y, z); - int opacity = MathMan.unpair16x(pair); - int brightness = MathMan.unpair16y(pair); - if (brightness > 1 && (brightness != 15 || opacity != 15)) { - addLightUpdate(bx + x, y, bz + z); - } - switch (value) { - case 0: - if (opacity > 1) { - queue.setSkyLight(section, x, y, z, 0); + for (int z = 0, j = 0; z < 16; z++) { + for (int x = 0; x < 16; x++, j++) { + byte value = mask[j]; + byte pair = (byte) queue.getOpacityBrightnessPair(section, x, y, z); + int opacity = MathMan.unpair16x(pair); + int brightness = MathMan.unpair16y(pair); + if (brightness > 1 && (brightness != 15 || opacity != 15)) { + addLightUpdate(bx + x, y, bz + z); + } + switch (value) { + case 0: + if (opacity > 1) { + queue.setSkyLight(section, x, y, z, 0); + continue; + } + 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: + if (opacity >= value) { + mask[j] = 0; + queue.setSkyLight(section, x, y, z, 0); + continue; + } + if (opacity <= 1) { + mask[j] = --value; + } else { + mask[j] = value = (byte) Math.max(0, value - opacity); + } + break; + case 15: + if (opacity > 1) { + value -= opacity; + mask[j] = value; + } + queue.setSkyLight(section, x, y, z, value); continue; - } - 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: - if (opacity >= value) { - mask[j] = 0; - queue.setSkyLight(section, x, y, z, 0); - continue; - } - if (opacity <= 1) { - mask[j] = --value; - } else { - mask[j] = value = (byte) Math.max(0, value - opacity); - } - break; - case 15: - if (opacity > 1) { - value -= opacity; - mask[j] = value; - } - queue.setSkyLight(section, x, y, z, value); - continue; + } + chunk.smooth = true; + queue.setSkyLight(section, x, y, z, value); } - chunk.smooth = true; - queue.setSkyLight(section, x, y, z, value); } queue.saveChunk(chunkObj); } 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 79bd95e2f..d86146b33 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 @@ -9,8 +9,8 @@ public class NullQueueIntFaweChunk extends IntFaweChunk { super(null, cx, cz); } - public NullQueueIntFaweChunk(int x, int z, int[][] ids, short[] count, short[] air, byte[] heightMap) { - super(null, x, z, ids, count, air, heightMap); + public NullQueueIntFaweChunk(int x, int z, int[][] ids, short[] count, short[] air) { + super(null, x, z, ids, count, air); } @Override @@ -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, heightMap); + return new NullQueueIntFaweChunk(getX(), getZ(), ids, count, air); } else { - return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone(), heightMap.clone()); + return new NullQueueIntFaweChunk(getX(), getZ(), (int[][]) MainUtil.copyNd(ids), 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 cd92a1af3..1abe2429e 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 @@ -10,8 +10,8 @@ public class SimpleIntFaweChunk extends IntFaweChunk { super(parent, x, z); } - public SimpleIntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air, byte[] heightMap) { - super(parent, x, z, ids, count, air, heightMap); + public SimpleIntFaweChunk(FaweQueue parent, int x, int z, int[][] ids, short[] count, short[] air) { + super(parent, x, z, ids, count, air); } @Override @@ -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, heightMap); + copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), ids, count, air); copy.biomes = biomes; } else { - copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone(), heightMap.clone()); + copy = new SimpleIntFaweChunk(getParent(), getX(), getZ(), (int[][]) MainUtil.copyNd(ids), count.clone(), air.clone()); copy.biomes = biomes != null ? biomes.clone() : null; } return copy; @@ -37,4 +37,4 @@ public class SimpleIntFaweChunk extends IntFaweChunk { getParent().setChunk(this); return this; } -} +} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java index d025aa5c6..d0a93bcc8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/BitArray4096.java @@ -69,15 +69,14 @@ public final class BitArray4096 { } } - public final void fromRaw(int[] arr, int offset) { + public final void fromRaw(int[] arr) { final long[] data = this.data; final int bitsPerEntry = this.bitsPerEntry; - final int maxEntryValue = this.maxEntryValue; final int maxSeqLocIndex = this.maxSeqLocIndex; int localStart = 0; int lastVal; - int arrI = offset; + int arrI = 0; long l = 0; long nextVal; for (int i = 0; i < longLen; i++) { @@ -123,11 +122,11 @@ public final class BitArray4096 { return arr; } - public final char[] toRaw() { - return toRaw(new char[4096]); + public final int[] toRaw() { + return toRaw(new int[4096]); } - protected final char[] toRaw(char[] buffer) { + public final int[] toRaw(int[] buffer) { final long[] data = this.data; final int dataLength = longLen; final int bitsPerEntry = this.bitsPerEntry; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java index 97e46bbb2..3e4f4262d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java @@ -597,8 +597,7 @@ public class MCAChunk extends FaweChunk { if (idLayer == null) { return 0; } - int j = FaweCache.CACHE_J[y][z & 15][x & 15]; - return idLayer[j]; + return idLayer[(((y & 15) << 8) | ((z & 15) << 4) | (x & 15))]; } @Override @@ -627,8 +626,7 @@ public class MCAChunk extends FaweChunk { if (skyLayer == null) { return; } - int index = FaweCache.CACHE_J[y][z & 15][x & 15]; - setNibble(index, skyLayer, value); + setNibble((((y & 15) << 8) | ((z & 15) << 4) | (x & 15)), skyLayer, value); } public void setBlockLight(int x, int y, int z, int value) { @@ -638,8 +636,7 @@ public class MCAChunk extends FaweChunk { if (blockLayer == null) { return; } - int index = FaweCache.CACHE_J[y][z & 15][x & 15]; - setNibble(index, blockLayer, value); + setNibble((((y & 15) << 8) | ((z & 15) << 4) | (x & 15)), blockLayer, value); } public int getSkyLight(int x, int y, int z) { @@ -648,8 +645,7 @@ public class MCAChunk extends FaweChunk { if (skyLayer == null) { return 0; } - int index = FaweCache.CACHE_J[y][z & 15][x & 15]; - return getNibble(index, skyLayer); + return getNibble((((y & 15) << 8) | ((z & 15) << 4) | (x & 15)), skyLayer); } public int getBlockLight(int x, int y, int z) { @@ -658,8 +654,7 @@ public class MCAChunk extends FaweChunk { if (blockLayer == null) { return 0; } - int index = FaweCache.CACHE_J[y][z & 15][x & 15]; - return getNibble(index, blockLayer); + return getNibble((((y & 15) << 8) | ((z & 15) << 4) | (x & 15)), blockLayer); } public void setFullbright() { @@ -729,8 +724,7 @@ public class MCAChunk extends FaweChunk { this.skyLight[layer] = new byte[2048]; this.blockLight[layer] = new byte[2048]; } - int j = FaweCache.CACHE_J[y][z & 15][x & 15]; - idsLayer[j] = combinedId; + idsLayer[(((y & 15) << 8) | ((z & 15) << 4) | (x & 15))] = combinedId; } @Override diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java index a05b93f36..7069f4114 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java @@ -652,21 +652,6 @@ public class MCAQueue extends NMSMappedFaweQueue currentHeight) { - otherMap[i] = newHeight; - } - } - } - } - @Override public void setFullbright(FaweChunk sections) { if (sections.getClass() == MCAChunk.class) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/WritableMCAChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/WritableMCAChunk.java index 39e7d7978..8d2f6d19f 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/WritableMCAChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/WritableMCAChunk.java @@ -1,5 +1,6 @@ package com.boydti.fawe.jnbt.anvil; +import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.util.MathMan; @@ -81,14 +82,12 @@ public class WritableMCAChunk extends FaweChunk { Arrays.fill(hasSections, false); } - private transient final int[] blockToPalette = new int[BlockTypes.states.length]; - { - Arrays.fill(blockToPalette, Integer.MAX_VALUE); - } - private transient final int[] paletteToBlock = new int[Character.MAX_VALUE]; - private transient final long[] blockstates = new long[2048]; - public void write(NBTOutputStream nbtOut) throws IOException { + int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); + int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); + long[] blockstates = FaweCache.BLOCK_STATES.get(); + int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); + nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND); nbtOut.writeNamedTag("DataVersion", 1631); nbtOut.writeLazyCompoundTag("Level", out -> { @@ -128,7 +127,7 @@ public class WritableMCAChunk extends FaweChunk { int blockIndexEnd = blockIndexStart + 4096; int num_palette = 0; try { - for (int i = blockIndexStart; i < blockIndexEnd; i++) { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { int stateId = blocks[i]; int ordinal = BlockState.getFromInternalId(stateId).getOrdinal(); // TODO fixme Remove all use of BlockTypes.BIT_OFFSET so that this conversion isn't necessary int palette = blockToPalette[ordinal]; @@ -138,7 +137,7 @@ public class WritableMCAChunk extends FaweChunk { paletteToBlock[num_palette] = ordinal; num_palette++; } - blocks[i] = palette; + blocksCopy[j] = palette; } for (int i = 0; i < num_palette; i++) { @@ -184,7 +183,7 @@ public class WritableMCAChunk extends FaweChunk { blockBitArrayEnd = 1; } else { BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); - bitArray.fromRaw(blocks, blockIndexStart); + bitArray.fromRaw(blocksCopy); } out.writeNamedTagName("BlockStates", NBTConstants.TYPE_LONG_ARRAY); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java b/worldedit-core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java index aa7fba380..7216bbfeb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/change/MutableChunkChange.java @@ -68,4 +68,4 @@ public class MutableChunkChange implements Change { queue.setChunk(to); } } -} +} \ No newline at end of file