Improved speed greatly by deferring lighting until after all blocks are in place.

This needs CraftBukkit to work.
This commit is contained in:
TomyLobo 2011-10-17 06:07:58 +02:00 committed by TomyLobo
parent e8dcee1acf
commit 4f7e1a6b31
2 changed files with 44 additions and 10 deletions

View File

@ -554,9 +554,14 @@ public class EditSession {
return; return;
} }
final Set<BlockVector2D> dirtyChunks = new HashSet<BlockVector2D>();
for (Map.Entry<BlockVector, BaseBlock> entry : queueAfter) { for (Map.Entry<BlockVector, BaseBlock> entry : queueAfter) {
BlockVector pt = (BlockVector) entry.getKey(); BlockVector pt = (BlockVector) entry.getKey();
rawSetBlock(pt, (BaseBlock) entry.getValue()); rawSetBlock(pt, (BaseBlock) entry.getValue());
// TODO: use ChunkStore.toChunk(pt) after optimizing it.
if (fastMode) dirtyChunks.add(new BlockVector2D(pt.getBlockX() >> 4, pt.getBlockZ() >> 4));
} }
// We don't want to place these blocks if other blocks were missing // We don't want to place these blocks if other blocks were missing
@ -622,10 +627,15 @@ public class EditSession {
for (BlockVector pt : walked) { for (BlockVector pt : walked) {
rawSetBlock(pt, blockTypes.get(pt)); rawSetBlock(pt, blockTypes.get(pt));
blocks.remove(pt); blocks.remove(pt);
// TODO: use ChunkStore.toChunk(pt) after optimizing it.
if (fastMode) dirtyChunks.add(new BlockVector2D(pt.getBlockX() >> 4, pt.getBlockZ() >> 4));
} }
} }
} }
if (!dirtyChunks.isEmpty()) world.fixLighting(dirtyChunks);
queueAfter.clear(); queueAfter.clear();
queueLast.clear(); queueLast.clear();
} }

View File

@ -107,7 +107,17 @@ public class BukkitWorld extends LocalWorld {
*/ */
@Override @Override
public boolean setBlockTypeFast(Vector pt, int type) { public boolean setBlockTypeFast(Vector pt, int type) {
return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeId(type, false); final Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
if (fastLighting) {
type = type & 255;
final int previousOpacity = Block_lightOpacity[type];
Block_lightOpacity[type] = 0;
final boolean ret = block.setTypeId(type);
Block_lightOpacity[type] = previousOpacity;
return ret;
}
return block.setTypeId(type, false);
} }
/** /**
@ -131,7 +141,17 @@ public class BukkitWorld extends LocalWorld {
*/ */
@Override @Override
public boolean setTypeIdAndDataFast(Vector pt, int type, int data){ public boolean setTypeIdAndDataFast(Vector pt, int type, int data){
return world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).setTypeIdAndData(type, (byte) data, false); final Block block = world.getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
if (fastLighting) {
type = type & 255;
final int previousOpacity = Block_lightOpacity[type];
Block_lightOpacity[type] = 0;
final boolean ret = block.setTypeIdAndData(type, (byte) data, true);
Block_lightOpacity[type] = previousOpacity;
return ret;
}
return block.setTypeIdAndData(type, (byte) data, false);
} }
/** /**
@ -726,8 +746,8 @@ public class BukkitWorld extends LocalWorld {
Object chunk = World_getChunkFromChunkCoords.invoke(notchWorld, x, z); Object chunk = World_getChunkFromChunkCoords.invoke(notchWorld, x, z);
int length = ((byte[])Chunk_b.get(chunk)).length; int length = ((byte[])Chunk_blocks.get(chunk)).length;
Chunk_h.set(chunk, NibbleArray_ctor.newInstance(length, 7)); Chunk_skylightMap.set(chunk, NibbleArray_ctor.newInstance(length, 7));
//Chunk_i.set(chunk, NibbleArray_ctor.newInstance(length, 7)); //Chunk_i.set(chunk, NibbleArray_ctor.newInstance(length, 7));
Chunk_generateSkylightMap.invoke(chunk); Chunk_generateSkylightMap.invoke(chunk);
@ -740,25 +760,29 @@ public class BukkitWorld extends LocalWorld {
} }
private static boolean fastLighting = false; private static boolean fastLighting = false;
private static int[] Block_lightOpacity;
private static Method CraftWorld_getHandle; private static Method CraftWorld_getHandle;
private static Method World_getChunkFromChunkCoords; private static Method World_getChunkFromChunkCoords;
private static Method Chunk_generateSkylightMap; private static Method Chunk_generateSkylightMap;
private static Field Chunk_b; private static Field Chunk_blocks;
private static Field Chunk_h; private static Field Chunk_skylightMap;
//private static Field Chunk_i; //private static Field Chunk_blocklightMap;
private static Constructor<?> NibbleArray_ctor; private static Constructor<?> NibbleArray_ctor;
static { static {
if (Bukkit.getServer().getName().equalsIgnoreCase("CraftBukkit")) { if (Bukkit.getServer().getName().equalsIgnoreCase("CraftBukkit")) {
try { try {
Block_lightOpacity = (int[]) Class.forName("net.minecraft.server.Block").getDeclaredField("q").get(null);
CraftWorld_getHandle = Class.forName("org.bukkit.craftbukkit.CraftWorld").getMethod("getHandle"); CraftWorld_getHandle = Class.forName("org.bukkit.craftbukkit.CraftWorld").getMethod("getHandle");
World_getChunkFromChunkCoords = Class.forName("net.minecraft.server.World").getMethod("getChunkAt", int.class, int.class); World_getChunkFromChunkCoords = Class.forName("net.minecraft.server.World").getMethod("getChunkAt", int.class, int.class);
Chunk_generateSkylightMap = Class.forName("net.minecraft.server.Chunk").getMethod("initLighting"); Chunk_generateSkylightMap = Class.forName("net.minecraft.server.Chunk").getMethod("initLighting");
Chunk_b = Class.forName("net.minecraft.server.Chunk").getField("b"); Chunk_blocks = Class.forName("net.minecraft.server.Chunk").getField("b");
Chunk_h = Class.forName("net.minecraft.server.Chunk").getField("h"); Chunk_skylightMap = Class.forName("net.minecraft.server.Chunk").getField("h");
//Chunk_i = Class.forName("net.minecraft.server.Chunk").getField("i"); //Chunk_blocklightMap = Class.forName("net.minecraft.server.Chunk").getField("i");
NibbleArray_ctor = Class.forName("net.minecraft.server.NibbleArray").getConstructor(int.class, int.class); NibbleArray_ctor = Class.forName("net.minecraft.server.NibbleArray").getConstructor(int.class, int.class);
fastLighting = true; fastLighting = true;
} }
catch (Throwable e) { catch (Throwable e) {