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
This commit is contained in:
Jesse Boyd 2016-08-14 20:55:17 +10:00
parent 80045cfa6c
commit eb62377c0f
3 changed files with 130 additions and 29 deletions

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.bukkit.v0; package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.CharFaweChunk; import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
@ -43,8 +44,9 @@ public class BukkitChunk_All extends CharFaweChunk<Chunk> {
public void execute(long start) { public void execute(long start) {
int recommended = 25 + BukkitQueue_All.ALLOCATE; int recommended = 25 + BukkitQueue_All.ALLOCATE;
boolean more = true; boolean more = true;
FaweQueue parent = getParent(); BukkitQueue_All parent = (BukkitQueue_All) getParent();
final Chunk chunk = getChunk(); final Chunk chunk = getChunk();
Object[] disableResult = parent.disableLighting(chunk);
chunk.load(true); chunk.load(true);
final World world = chunk.getWorld(); final World world = chunk.getWorld();
char[][] sections = getCombinedIdArrays(); char[][] sections = getCombinedIdArrays();
@ -106,12 +108,15 @@ public class BukkitChunk_All extends CharFaweChunk<Chunk> {
if (newArray == null) { if (newArray == null) {
continue; 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); boolean checkTime = !((getAir(layer) == 4096 || (getCount(layer) == 4096 && getAir(layer) == 0) || (getCount(layer) == getAir(layer))) && getRelight(layer) == 0);
if (!checkTime) { if (!checkTime) {
ArrayList<Thread> threads = new ArrayList<Thread>(); ArrayList<Thread> threads = new ArrayList<Thread>();
for (int k = 0; k < 16; k++) { for (int k = 0; k < 16; k++) {
final int l = k << 8; final int l = k << 8;
final int y = FaweCache.CACHE_Y[layer][l]; final int y = cacheY[l];
Thread thread = new Thread(new Runnable() { Thread thread = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -122,23 +127,18 @@ public class BukkitChunk_All extends CharFaweChunk<Chunk> {
continue; continue;
case 1: case 1:
if (!place) { if (!place) {
int x = FaweCache.CACHE_X[layer][m]; int x = cacheX[m];
int z = FaweCache.CACHE_Z[layer][m]; int z = cacheZ[m];
chunk.getBlock(x, y, z).setTypeId(0, false); setBlock(chunk.getBlock(x, y, z), 0, (byte) 0);
} }
continue; continue;
default: default:
if (place) { if (place) {
int x = FaweCache.CACHE_X[layer][m]; int x = cacheX[m];
int z = FaweCache.CACHE_Z[layer][m]; int z = cacheZ[m];
int id = combined >> 4; int id = combined >> 4;
int data = combined & 0xF;
Block block = chunk.getBlock(x, y, z); Block block = chunk.getBlock(x, y, z);
if (data == 0) { setBlock(block, id, (byte) (combined & 0xF));
block.setTypeId(id, false);
} else {
block.setTypeIdAndData(id, (byte) data, false);
}
} }
continue; continue;
} }
@ -157,28 +157,41 @@ public class BukkitChunk_All extends CharFaweChunk<Chunk> {
char combined = newArray[j]; char combined = newArray[j];
switch (combined) { switch (combined) {
case 0: case 0:
break; continue;
case 1: case 1:
if (!place) { if (!place) {
int x = FaweCache.CACHE_X[layer][j]; int x = cacheX[j];
int z = FaweCache.CACHE_Z[layer][j]; int z = cacheZ[j];
int y = FaweCache.CACHE_Y[layer][j]; int y = cacheY[j];
chunk.getBlock(x, y, z).setTypeId(0, false); setBlock(chunk.getBlock(x, y, z), 0, (byte) 0);
} }
break; break;
default: default:
if (place) { int id = combined >> 4;
int id = combined >> 4; boolean light = FaweCache.hasLight(id);
int data = combined & 0xF; if (light) {
int x = FaweCache.CACHE_X[layer][j]; if (place) {
int z = FaweCache.CACHE_Z[layer][j]; continue;
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);
} }
} 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; break;
} }
@ -196,5 +209,10 @@ public class BukkitChunk_All extends CharFaweChunk<Chunk> {
if (more || place) { if (more || place) {
this.addToQueue(); this.addToQueue();
} }
parent.resetLighting(disableResult);
}
public void setBlock(Block block, int id, byte data) {
block.setTypeIdAndData(id, data, false);
} }
} }

View File

@ -7,6 +7,8 @@ import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -15,6 +17,7 @@ public class BukkitQueue_All extends BukkitQueue_0<Chunk, Chunk, Chunk> {
public static int ALLOCATE; public static int ALLOCATE;
public static double TPS_TARGET = 18.5; public static double TPS_TARGET = 18.5;
private static int LIGHT_MASK = 0x739C0;
public BukkitQueue_All(String world) { public BukkitQueue_All(String world) {
super(world); super(world);
@ -124,6 +127,62 @@ public class BukkitQueue_All extends BukkitQueue_0<Chunk, Chunk, Chunk> {
super.startSet(true); 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 @Override
public void endSet(boolean parallel) { public void endSet(boolean parallel) {
super.endSet(true); super.endSet(true);

View File

@ -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 { public enum LightType {
TRANSPARENT, OCCLUDING, SOLID_EMIT, TRANSPARENT_EMIT TRANSPARENT, OCCLUDING, SOLID_EMIT, TRANSPARENT_EMIT
} }