From eb62377c0f52eb7ff56aa0bcf4d6170233d3ec18 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 14 Aug 2016 20:55:17 +1000 Subject: [PATCH] Optimizations for BukkitQueue_All This queue is used to place blocks when no (fast) NMS one is found. - Exploits a bug in vanilla relight algorithm for faster placement --- .../fawe/bukkit/v0/BukkitChunk_All.java | 76 ++++++++++++------- .../fawe/bukkit/v0/BukkitQueue_All.java | 59 ++++++++++++++ .../main/java/com/boydti/fawe/FaweCache.java | 24 ++++++ 3 files changed, 130 insertions(+), 29 deletions(-) diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java index b1cfcabb..f6fad6eb 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java @@ -1,6 +1,7 @@ package com.boydti.fawe.bukkit.v0; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.config.Settings; import com.boydti.fawe.example.CharFaweChunk; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MainUtil; @@ -43,8 +44,9 @@ public class BukkitChunk_All extends CharFaweChunk { public void execute(long start) { int recommended = 25 + BukkitQueue_All.ALLOCATE; boolean more = true; - FaweQueue parent = getParent(); + BukkitQueue_All parent = (BukkitQueue_All) getParent(); final Chunk chunk = getChunk(); + Object[] disableResult = parent.disableLighting(chunk); chunk.load(true); final World world = chunk.getWorld(); char[][] sections = getCombinedIdArrays(); @@ -106,12 +108,15 @@ public class BukkitChunk_All extends CharFaweChunk { 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]; boolean checkTime = !((getAir(layer) == 4096 || (getCount(layer) == 4096 && getAir(layer) == 0) || (getCount(layer) == getAir(layer))) && getRelight(layer) == 0); if (!checkTime) { ArrayList threads = new ArrayList(); for (int k = 0; k < 16; k++) { final int l = k << 8; - final int y = FaweCache.CACHE_Y[layer][l]; + final int y = cacheY[l]; Thread thread = new Thread(new Runnable() { @Override public void run() { @@ -122,23 +127,18 @@ public class BukkitChunk_All extends CharFaweChunk { continue; case 1: if (!place) { - int x = FaweCache.CACHE_X[layer][m]; - int z = FaweCache.CACHE_Z[layer][m]; - chunk.getBlock(x, y, z).setTypeId(0, false); + int x = cacheX[m]; + int z = cacheZ[m]; + setBlock(chunk.getBlock(x, y, z), 0, (byte) 0); } continue; default: if (place) { - int x = FaweCache.CACHE_X[layer][m]; - int z = FaweCache.CACHE_Z[layer][m]; + int x = cacheX[m]; + int z = cacheZ[m]; int id = combined >> 4; - int data = combined & 0xF; Block block = chunk.getBlock(x, y, z); - if (data == 0) { - block.setTypeId(id, false); - } else { - block.setTypeIdAndData(id, (byte) data, false); - } + setBlock(block, id, (byte) (combined & 0xF)); } continue; } @@ -157,28 +157,41 @@ public class BukkitChunk_All extends CharFaweChunk { char combined = newArray[j]; switch (combined) { case 0: - break; + continue; case 1: if (!place) { - int x = FaweCache.CACHE_X[layer][j]; - int z = FaweCache.CACHE_Z[layer][j]; - int y = FaweCache.CACHE_Y[layer][j]; - chunk.getBlock(x, y, z).setTypeId(0, false); + int x = cacheX[j]; + int z = cacheZ[j]; + int y = cacheY[j]; + setBlock(chunk.getBlock(x, y, z), 0, (byte) 0); } break; default: - if (place) { - int id = combined >> 4; - int data = combined & 0xF; - int x = FaweCache.CACHE_X[layer][j]; - int z = FaweCache.CACHE_Z[layer][j]; - int y = FaweCache.CACHE_Y[layer][j]; - Block block = chunk.getBlock(x, y, z); - if (data == 0) { - block.setTypeId(id, false); - } else { - block.setTypeIdAndData(id, (byte) data, false); + int id = combined >> 4; + boolean light = FaweCache.hasLight(id); + if (light) { + if (place) { + continue; } + } else if (!place) { + continue; + } + if (light != place) { + light = light && Settings.LIGHTING.MODE != 0; + if (light) { + parent.enableLighting(disableResult); + } + int data = combined & 0xF; + int x = cacheX[j]; + int z = cacheZ[j]; + int y = cacheY[j]; + Block block = chunk.getBlock(x, y, z); + setBlock(block, id, (byte) data); + if (light) { + parent.disableLighting(disableResult); + } + } else { + continue; } break; } @@ -196,5 +209,10 @@ public class BukkitChunk_All extends CharFaweChunk { if (more || place) { this.addToQueue(); } + parent.resetLighting(disableResult); + } + + public void setBlock(Block block, int id, byte data) { + block.setTypeIdAndData(id, data, false); } } diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java index b40dbbd0..007445ff 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java @@ -7,6 +7,8 @@ import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Block; @@ -15,6 +17,7 @@ public class BukkitQueue_All extends BukkitQueue_0 { public static int ALLOCATE; public static double TPS_TARGET = 18.5; + private static int LIGHT_MASK = 0x739C0; public BukkitQueue_All(String world) { super(world); @@ -124,6 +127,62 @@ public class BukkitQueue_All extends BukkitQueue_0 { super.startSet(true); } + 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) {} + } + } + @Override public void endSet(boolean parallel) { super.endSet(true); diff --git a/core/src/main/java/com/boydti/fawe/FaweCache.java b/core/src/main/java/com/boydti/fawe/FaweCache.java index 153990e2..6219b8b1 100644 --- a/core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/core/src/main/java/com/boydti/fawe/FaweCache.java @@ -317,6 +317,30 @@ public class FaweCache { } } + public static boolean hasLight(int id) { + switch (id) { + case 39: + case 40: + case 50: + case 51: + case 76: + case 10: + case 11: + case 62: + case 74: + case 89: + case 122: + case 124: + case 130: + case 138: + case 169: + case 213: + return true; + default: + return false; + } + } + public enum LightType { TRANSPARENT, OCCLUDING, SOLID_EMIT, TRANSPARENT_EMIT }