package com.plotsquared.bukkit.util.block; import com.intellectualcrafters.plot.object.ChunkWrapper; import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.ReflectionUtils; import com.intellectualcrafters.plot.util.TaskManager; import com.plotsquared.bukkit.util.SendChunk; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Block; import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass; public class BukkitLocalQueue_1_8 extends BukkitLocalQueue<PlotBlock[]> { private final ReflectionUtils.RefMethod methodInitLighting; private final ReflectionUtils.RefClass classBlock = getRefClass("{nms}.Block"); private final ReflectionUtils.RefClass classBlockPosition = getRefClass("{nms}.BlockPosition"); private final ReflectionUtils.RefClass classIBlockData = getRefClass("{nms}.IBlockData"); private final ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk"); private final ReflectionUtils.RefClass classWorld = getRefClass("{nms}.World"); private final ReflectionUtils.RefClass classCraftWorld = getRefClass("{cb}.CraftWorld"); private final HashMap<ChunkWrapper, Chunk> toUpdate = new HashMap<>(); private final ReflectionUtils.RefMethod methodGetHandle; private final ReflectionUtils.RefMethod methodGetChunkAt; private final ReflectionUtils.RefMethod methodA; private final ReflectionUtils.RefMethod methodGetByCombinedId; private final ReflectionUtils.RefConstructor constructorBlockPosition; private final SendChunk sendChunk; public BukkitLocalQueue_1_8(String world) throws NoSuchMethodException, ClassNotFoundException, NoSuchFieldException { super(world); this.methodInitLighting = this.classChunk.getMethod("initLighting"); this.constructorBlockPosition = this.classBlockPosition.getConstructor(int.class, int.class, int.class); this.methodGetByCombinedId = this.classBlock.getMethod("getByCombinedId", int.class); this.methodGetHandle = this.classCraftWorld.getMethod("getHandle"); this.methodGetChunkAt = this.classWorld.getMethod("getChunkAt", int.class, int.class); this.methodA = this.classChunk.getMethod("a", this.classBlockPosition, this.classIBlockData); this.sendChunk = new SendChunk(); TaskManager.runTaskRepeat(new Runnable() { @Override public void run() { if (BukkitLocalQueue_1_8.this.toUpdate.isEmpty()) { return; } int count = 0; ArrayList<Chunk> chunks = new ArrayList<>(); Iterator<Map.Entry<ChunkWrapper, Chunk>> i = BukkitLocalQueue_1_8.this.toUpdate.entrySet().iterator(); while (i.hasNext() && count < 128) { chunks.add(i.next().getValue()); i.remove(); count++; } if (count == 0) { return; } update(chunks); } }, 1); MainUtil.initCache(); } @Override public void fixChunkLighting(int x, int z) { Object c = this.methodGetHandle.of(getChunk(x, z)).call(); this.methodInitLighting.of(c).call(); } @Override public void setBlocks(LocalChunk<PlotBlock[]> lc) { Chunk chunk = getChunk(lc.getX(), lc.getZ()); chunk.load(true); World world = chunk.getWorld(); ChunkWrapper wrapper = new ChunkWrapper(getWorld(), lc.getX(), lc.getZ()); if (!this.toUpdate.containsKey(wrapper)) { this.toUpdate.put(wrapper, chunk); } Object w = this.methodGetHandle.of(world).call(); Object c = this.methodGetChunkAt.of(w).call(lc.getX(), lc.getZ()); for (int i = 0; i < lc.blocks.length; i++) { PlotBlock[] result2 = lc.blocks[i]; if (result2 == null) { continue; } for (int j = 0; j < 4096; j++) { int x = MainUtil.x_loc[i][j]; int y = MainUtil.y_loc[i][j]; int z = MainUtil.z_loc[i][j]; PlotBlock newBlock = result2[j]; if (newBlock.id == -1) { chunk.getBlock(x, y, z).setData(newBlock.data, false); continue; } // Start blockstate workaround // switch (newBlock.id) { case 54: case 130: case 142: case 132: case 27: case 137: case 52: case 154: case 84: case 25: case 144: case 138: case 176: case 177: case 119: case 63: case 68: case 323: case 117: case 116: case 28: case 66: case 157: case 61: case 62: case 140: case 146: case 149: case 150: case 158: case 23: case 123: case 124: case 29: case 33: case 151: case 178: Block block = world.getBlockAt(x, y, z); if (block.getData() == newBlock.data) { if (block.getTypeId() != newBlock.id) { block.setTypeId(newBlock.id, false); } } else { if (block.getTypeId() == newBlock.id) { block.setData(newBlock.data, false); } else { block.setTypeIdAndData(newBlock.id, newBlock.data, false); } } continue; } // Start data value shortcut Block block = world.getBlockAt(x, y, z); int currentId = block.getTypeId(); if (currentId == newBlock.id) { switch (newBlock.id) { case 0: case 2: case 4: case 13: case 14: case 15: case 20: case 21: case 22: case 25: case 30: case 32: case 37: case 39: case 40: case 41: case 42: case 45: case 46: case 47: case 48: case 49: case 51: case 52: case 54: case 55: case 56: case 57: case 58: case 60: case 61: case 62: case 7: case 8: case 9: case 10: case 11: case 73: case 74: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 87: case 88: case 101: case 102: case 103: case 110: case 112: case 113: case 117: case 121: case 122: case 123: case 124: case 129: case 133: case 138: case 137: case 140: case 165: case 166: case 169: case 170: case 172: case 173: case 174: case 176: case 177: case 181: case 182: case 188: case 189: case 190: case 191: case 192: continue; } if (block.getData() == newBlock.data) { return; } block.setData(newBlock.data, false); return; } // blockstate switch (currentId) { case 54: case 130: case 132: case 142: case 27: case 137: case 52: case 154: case 84: case 25: case 144: case 138: case 176: case 177: case 63: case 68: case 323: case 117: case 119: case 116: case 28: case 66: case 157: case 61: case 62: case 140: case 146: case 149: case 150: case 158: case 23: case 123: case 124: case 29: case 33: case 151: case 178: if (block.getData() == newBlock.data) { block.setTypeId(newBlock.id, false); } else { block.setTypeIdAndData(newBlock.id, newBlock.data, false); } continue; } // End blockstate workaround // // check sign Object pos = null; try { pos = this.constructorBlockPosition.create(x, y, z); } catch (ReflectiveOperationException e) { e.printStackTrace(); } Object combined = this.methodGetByCombinedId.call(newBlock.id + (newBlock.data << 12)); this.methodA.of(chunk).call(pos, combined); } } fixChunkLighting(lc.getX(), lc.getZ()); } public void update(Collection<Chunk> chunks) { if (chunks.isEmpty()) { return; } if (!MainUtil.canSendChunk) { for (Chunk chunk : chunks) { chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ()); chunk.unload(true, false); chunk.load(); } return; } try { this.sendChunk.sendChunk(chunks); } catch (Throwable e) { e.printStackTrace(); MainUtil.canSendChunk = false; } } @Override public void refreshChunk(int x, int z) { update(Arrays.asList(Bukkit.getWorld(getWorld()).getChunkAt(x, z))); } }