From 61d00e51ef2fa51a6e9227d48228d0d4d678991d Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Fri, 26 Aug 2016 03:02:50 +1000 Subject: [PATCH] Fixes #1303 --- .../bukkit/util/block/BukkitLocalQueue.java | 58 ++++++++ .../util/block/BukkitLocalQueue_1_9.java | 134 ++++++++---------- 2 files changed, 117 insertions(+), 75 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue.java index f61d4d6a2..0e0b296da 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue.java @@ -4,6 +4,8 @@ import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.StringMan; import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -126,4 +128,60 @@ public class BukkitLocalQueue extends BasicLocalBlockQueue { } } } + + private Field fieldNeighbors; + private Method chunkGetHandle; + + /** + * Exploiting a bug in the vanilla lighting algorithm for faster block placement + * - Could have been achieved without reflection by force unloading specific chunks + * - Much faster just setting the variable manually though + * @param chunk + * @return + */ + protected Object[] disableLighting(Chunk chunk) { + try { + if (chunkGetHandle == null) { + chunkGetHandle = chunk.getClass().getDeclaredMethod("getHandle"); + chunkGetHandle.setAccessible(true); + } + Object nmsChunk = chunkGetHandle.invoke(chunk); + if (fieldNeighbors == null) { + fieldNeighbors = nmsChunk.getClass().getDeclaredField("neighbors"); + fieldNeighbors.setAccessible(true); + } + Object value = fieldNeighbors.get(nmsChunk); + fieldNeighbors.set(nmsChunk, 0); + return new Object[] {nmsChunk, value}; + } catch (Throwable ignore) {} + return null; + } + + protected void disableLighting(Object[] disableResult) { + if (disableResult != null) { + try { + fieldNeighbors.set(disableResult[0], 0); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + protected void resetLighting(Object[] disableResult) { + if (disableResult != null) { + try { + fieldNeighbors.set(disableResult[0], disableResult[1]); + } catch (Throwable ignore) { + ignore.printStackTrace(); + } + } + } + + protected void enableLighting(Object[] disableResult) { + if (disableResult != null) { + try { + fieldNeighbors.set(disableResult[0], 0x739C0); + } catch (Throwable ignore) {} + } + } } \ No newline at end of file diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_9.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_9.java index 03ef49963..485bb53d9 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_9.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/BukkitLocalQueue_1_9.java @@ -1,9 +1,7 @@ package com.plotsquared.bukkit.util.block; -import com.intellectualcrafters.plot.object.ChunkLoc; import com.intellectualcrafters.plot.object.ChunkWrapper; import com.intellectualcrafters.plot.object.PseudoRandom; -import com.intellectualcrafters.plot.util.ChunkManager; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.ReflectionUtils; import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue; @@ -380,87 +378,73 @@ public class BukkitLocalQueue_1_9 extends BukkitLocalQueue { Object c = this.methodGetHandleChunk.of(chunk).call(); ChunkWrapper wrapper = new ChunkWrapper(getWorld(), bc.getX(), bc.getZ()); - if (fixAll && !(boolean) this.methodAreNeighborsLoaded.of(c).call(1)) { - World world = chunk.getWorld(); - for (int x = wrapper.x - 1; x <= wrapper.x + 1; x++) { - for (int z = wrapper.z - 1; z <= wrapper.z + 1; z++) { - if (x != 0 && z != 0) { - Chunk other = world.getChunkAt(x, z); - while (!other.isLoaded()) { - other.load(true); - } - ChunkManager.manager.loadChunk(getWorld(), new ChunkLoc(x, z), true); - } - } - } - } + Object[] result = disableLighting(chunk); + enableLighting(result); this.methodInitLighting.of(c).call(); - if (bc.getTotalRelight() == 0 && !fixAll) { - return true; - } + if (bc.getTotalRelight() != 0 || fixAll) { + Object[] sections = (Object[]) this.fieldSections.of(c).get(); + Object w = this.fieldWorld.of(c).get(); - Object[] sections = (Object[]) this.fieldSections.of(c).get(); - Object w = this.fieldWorld.of(c).get(); - - int X = chunk.getX() << 4; - int Z = chunk.getZ() << 4; - - ReflectionUtils.RefMethod.RefExecutor relight = this.methodW.of(w); - for (int j = 0; j < sections.length; j++) { - Object section = sections[j]; - if (section == null) { - continue; - } - if (bc.getRelight(j) == 0 && !fixAll || bc.getCount(j) == 0 || bc.getCount(j) >= 4096 && bc.getAir(j) == 0) { - continue; - } - char[] array = bc.getIdArray(j); - if (array != null) { - int l = PseudoRandom.random.random(2); - for (int k = 0; k < array.length; k++) { - int i = array[k]; - if (i < 16) { - continue; - } - short id = (short) (i >> 4); - switch (id) { // Lighting - default: - if (!fixAll) { - continue; - } - if ((k & 1) == l) { - l = 1 - l; - continue; - } - case 10: - case 11: - case 39: - case 40: - case 50: - case 51: - case 62: - case 74: - case 76: - case 89: - case 122: - case 124: - case 130: - case 138: - case 169: - int x = MainUtil.x_loc[j][k]; - int y = MainUtil.y_loc[j][k]; - int z = MainUtil.z_loc[j][k]; - if (isSurrounded(bc.blocks, x, y, z)) { - continue; - } - Object pos = this.classBlockPositionConstructor.create(X + x, y, Z + z); - relight.call(pos); + int X = chunk.getX() << 4; + int Z = chunk.getZ() << 4; + ReflectionUtils.RefMethod.RefExecutor relight = this.methodW.of(w); + for (int j = 0; j < sections.length; j++) { + Object section = sections[j]; + if (section == null) { + continue; + } + if (bc.getRelight(j) == 0 && !fixAll || bc.getCount(j) == 0 || bc.getCount(j) >= 4096 && bc.getAir(j) == 0) { + continue; + } + char[] array = bc.getIdArray(j); + if (array != null) { + int l = PseudoRandom.random.random(2); + for (int k = 0; k < array.length; k++) { + int i = array[k]; + if (i < 16) { + continue; + } + short id = (short) (i >> 4); + switch (id) { // Lighting + default: + if (!fixAll) { + continue; + } + if ((k & 1) == l) { + l = 1 - l; + continue; + } + case 10: + case 11: + case 39: + case 40: + case 50: + case 51: + case 62: + case 74: + case 76: + case 89: + case 122: + case 124: + case 130: + case 138: + case 169: + int x = MainUtil.x_loc[j][k]; + int y = MainUtil.y_loc[j][k]; + int z = MainUtil.z_loc[j][k]; + if (isSurrounded(bc.blocks, x, y, z)) { + continue; + } + Object pos = this.classBlockPositionConstructor.create(X + x, y, Z + z); + relight.call(pos); + } } } } } + resetLighting(result); return true; } catch (Throwable e) { e.printStackTrace();