From 690b56d6d3fb45694d95663aeaddec0bc283291c Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Thu, 6 Sep 2018 22:29:34 -0500 Subject: [PATCH] Chunk state performance for 1.9.4 --- .../org/dynmap/forge_1_9_4/ChunkSnapshot.java | 225 ++++++++++-------- .../forge_1_9_4/ForgeMapChunkCache.java | 5 - 2 files changed, 132 insertions(+), 98 deletions(-) diff --git a/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ChunkSnapshot.java b/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ChunkSnapshot.java index f1863a91..dc105ee0 100644 --- a/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ChunkSnapshot.java +++ b/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ChunkSnapshot.java @@ -1,15 +1,12 @@ package org.dynmap.forge_1_9_4; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.util.Arrays; import org.dynmap.Log; import org.dynmap.renderer.DynmapBlockState; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.world.chunk.NibbleArray; -import scala.actors.threadpool.Arrays; /** * Represents a static, thread-safe snapshot of chunk of blocks @@ -17,11 +14,15 @@ import scala.actors.threadpool.Arrays; */ public class ChunkSnapshot { + private static interface Section { + public DynmapBlockState getBlockType(int x, int y, int z); + public int getBlockSkyLight(int x, int y, int z); + public int getBlockEmittedLight(int x, int y, int z); + public boolean isEmpty(); + } + private final int x, z; - private final int[][] blockidx; /* Block state index, by section */ - private final byte[][] skylight; - private final byte[][] emitlight; - private final boolean[] empty; + private final Section[] section; private final int[] hmap; // Height map private final int[] biome; private final long captureFulltime; @@ -30,18 +31,66 @@ public class ChunkSnapshot private static final int BLOCKS_PER_SECTION = 16 * 16 * 16; private static final int COLUMNS_PER_CHUNK = 16 * 16; - private static final int[] emptyIdx = new int[BLOCKS_PER_SECTION]; private static final byte[] emptyData = new byte[BLOCKS_PER_SECTION / 2]; private static final byte[] fullData = new byte[BLOCKS_PER_SECTION / 2]; static { - for (int i = 0; i < fullData.length; i++) - { - fullData[i] = (byte)0xFF; - } + Arrays.fill(fullData, (byte)0xFF); } + private static class EmptySection implements Section { + @Override + public DynmapBlockState getBlockType(int x, int y, int z) { + return DynmapBlockState.AIR; + } + @Override + public int getBlockSkyLight(int x, int y, int z) { + return 15; + } + @Override + public int getBlockEmittedLight(int x, int y, int z) { + return 0; + } + @Override + public boolean isEmpty() { + return true; + } + } + + private static final EmptySection empty_section = new EmptySection(); + + private static class StdSection implements Section { + DynmapBlockState[] states; + byte[] skylight; + byte[] emitlight; + + public StdSection() { + states = new DynmapBlockState[BLOCKS_PER_SECTION]; + Arrays.fill(states, DynmapBlockState.AIR); + skylight = emptyData; + emitlight = emptyData; + } + @Override + public DynmapBlockState getBlockType(int x, int y, int z) { + return states[((y & 0xF) << 8) | (z << 4) | x]; + } + @Override + public int getBlockSkyLight(int x, int y, int z) { + int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); + return (skylight[off] >> (4 * (x & 1))) & 0xF; + } + @Override + public int getBlockEmittedLight(int x, int y, int z) + { + int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); + return (emitlight[off] >> (4 * (x & 1))) & 0xF; + } + @Override + public boolean isEmpty() { + return false; + } + } /** * Construct empty chunk snapshot * @@ -56,18 +105,11 @@ public class ChunkSnapshot this.biome = new int[COLUMNS_PER_CHUNK]; this.sectionCnt = worldheight / 16; /* Allocate arrays indexed by section */ - this.blockidx = new int[this.sectionCnt][]; - this.skylight = new byte[this.sectionCnt][]; - this.emitlight = new byte[this.sectionCnt][]; - this.empty = new boolean[this.sectionCnt]; + this.section = new Section[this.sectionCnt]; /* Fill with empty data */ - for (int i = 0; i < this.sectionCnt; i++) - { - this.empty[i] = true; - this.blockidx[i] = emptyIdx; - this.emitlight[i] = emptyData; - this.skylight[i] = fullData; + for (int i = 0; i < this.sectionCnt; i++) { + this.section[i] = empty_section; } /* Create empty height map */ @@ -89,16 +131,10 @@ public class ChunkSnapshot this.inhabitedTicks = 0; } /* Allocate arrays indexed by section */ - this.blockidx = new int[this.sectionCnt][]; - this.skylight = new byte[this.sectionCnt][]; - this.emitlight = new byte[this.sectionCnt][]; - this.empty = new boolean[this.sectionCnt]; + this.section = new Section[this.sectionCnt]; /* Fill with empty data */ for (int i = 0; i < this.sectionCnt; i++) { - this.empty[i] = true; - this.blockidx[i] = emptyIdx; - this.emitlight[i] = emptyData; - this.skylight[i] = fullData; + this.section[i] = empty_section; } /* Get sections */ NBTTagList sect = nbt.getTagList("Sections", 10); @@ -109,8 +145,10 @@ public class ChunkSnapshot Log.info("Section " + (int) secnum + " above world height " + worldheight); continue; } - int[] blkidxs = new int[BLOCKS_PER_SECTION]; - this.blockidx[secnum] = blkidxs; + // Create normal section to initialize + StdSection cursect = new StdSection(); + this.section[secnum] = cursect; + DynmapBlockState[] states = cursect.states; // JEI format if (sec.hasKey("Palette", 11)) { int[] p = sec.getIntArray("Palette"); @@ -128,59 +166,73 @@ public class ChunkSnapshot idx2 += (255 & msb_bytes[2*j+1]) << 4; } // Get even block id - blkidxs[2*j] = (idx < p.length) ? p[idx] : 0; + states[2*j] = DynmapPlugin.stateByID[(idx < p.length) ? p[idx] : 0]; // Get odd block id - blkidxs[2*j+1] = (idx2 < p.length) ? p[idx2] : 0; + states[2*j+1] = DynmapPlugin.stateByID[(idx2 < p.length) ? p[idx2] : 0]; } } else { + // Get block IDs byte[] lsb_bytes = sec.getByteArray("Blocks"); - int len = BLOCKS_PER_SECTION; - if(len > lsb_bytes.length) len = lsb_bytes.length; - for(int j = 0; j < len; j++) { - blkidxs[j] = (0xFF & lsb_bytes[j]) << 4; + if (lsb_bytes.length < BLOCKS_PER_SECTION) { + lsb_bytes = Arrays.copyOf(lsb_bytes, BLOCKS_PER_SECTION); } - if (sec.hasKey("Add", 7)) { /* If additional data, add it */ - byte[] msb = sec.getByteArray("Add"); - len = BLOCKS_PER_SECTION / 2; - if(len > msb.length) len = msb.length; - for (int j = 0; j < len; j++) { - short b = (short)(msb[j] & 0xFF); - if (b == 0) { - continue; - } - blkidxs[j << 1] |= (b & 0x0F) << 12; - blkidxs[(j << 1) + 1] |= (b & 0xF0) << 8; - } - } - if (sec.hasKey("Add2", 7)) { /* If additional data (NEID), add it */ - byte[] msb = sec.getByteArray("Add2"); - len = BLOCKS_PER_SECTION / 2; - if(len > msb.length) len = msb.length; - for (int j = 0; j < len; j++) { - short b = (short)(msb[j] & 0xFF); - if (b == 0) { - continue; - } - blkidxs[j << 1] |= (b & 0x0F) << 16; - blkidxs[(j << 1) + 1] |= (b & 0xF0) << 12; - } - } - byte[] bd = sec.getByteArray("Data"); - for (int j = 0; j < bd.length; j++) { - int b = bd[j] & 0xFF; - if (b == 0) { - continue; - } - blkidxs[j << 1] |= b & 0x0F; - blkidxs[(j << 1) + 1] |= (b & 0xF0) >> 4; + // Get any additional ID data + byte[] addid = null; + if (sec.hasKey("Add", 7)) { /* If additional data, add it */ + addid = sec.getByteArray("Add"); + if (addid.length < (BLOCKS_PER_SECTION / 2)) { + addid = Arrays.copyOf(addid, (BLOCKS_PER_SECTION / 2)); + } + } + // Check for NEID additional additional ID data + byte[] addid2 = null; + if (sec.hasKey("Add2", 7)) { /* If additional data (NEID), add it */ + addid2 = sec.getByteArray("Add2"); + if (addid2.length < (BLOCKS_PER_SECTION / 2)) { + addid2 = Arrays.copyOf(addid2, (BLOCKS_PER_SECTION / 2)); + } + } + // Get meta nibble data + byte[] bd = null; + if (sec.hasKey("Data", 7)) { + bd = sec.getByteArray("Data"); + if (bd.length < (BLOCKS_PER_SECTION / 2)) { + bd = Arrays.copyOf(bd, (BLOCKS_PER_SECTION / 2)); + } + } + // Traverse section + for(int j = 0; j < BLOCKS_PER_SECTION; j += 2) { + // Start with block ID + int id = (0xFF & lsb_bytes[j]) << 4; + int id2 = (0xFF & lsb_bytes[j+1]) << 4; + // Add in additional parts + if (addid != null) { + byte b = addid[j >> 1]; + id += (0xF & b) << 12; + id2 += (0xF0 & b) << 8; + } + // Add in additional additional parts + if (addid2 != null) { + byte b = addid2[j >> 1]; + id += (0xF & b) << 16; + id2 += (0xF0 & b) << 12; + } + // Add in metadata + if (bd != null) { + byte b = bd[j >> 1]; + id += (0xF & b); + id2 += (0xF0 & b) >> 4; + } + // Compute states + states[j] = DynmapPlugin.stateByID[id]; + states[j+1] = DynmapPlugin.stateByID[id2]; } } - this.emitlight[secnum] = sec.getByteArray("BlockLight"); + cursect.emitlight = sec.getByteArray("BlockLight"); if (sec.hasKey("SkyLight")) { - this.skylight[secnum] = sec.getByteArray("SkyLight"); + cursect.skylight = sec.getByteArray("SkyLight"); } - this.empty[secnum] = false; } /* Get biome data */ this.biome = new int[COLUMNS_PER_CHUNK]; @@ -213,33 +265,20 @@ public class ChunkSnapshot { return z; } - - public int getBlockTypeId(int x, int y, int z) - { - return blockidx[y >> 4][((y & 0xF) << 8) | (z << 4) | x] >> 4; - } - - public int getBlockData(int x, int y, int z) - { - return blockidx[y >> 4][((y & 0xF) << 8) | (z << 4) | x] & 0xF; - } public DynmapBlockState getBlockType(int x, int y, int z) { - int id = blockidx[y >> 4][((y & 0xF) << 8) | (z << 4) | x]; - return DynmapPlugin.stateByID[id]; + return section[y >> 4].getBlockType(x, y, z); } public int getBlockSkyLight(int x, int y, int z) { - int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); - return (skylight[y >> 4][off] >> ((x & 1) << 2)) & 0xF; + return section[y >> 4].getBlockSkyLight(x, y, z); } public int getBlockEmittedLight(int x, int y, int z) { - int off = ((y & 0xF) << 7) | (z << 3) | (x >> 1); - return (emitlight[y >> 4][off] >> ((x & 1) << 2)) & 0xF; + return section[y >> 4].getBlockEmittedLight(x, y, z); } public int getHighestBlockYAt(int x, int z) @@ -259,7 +298,7 @@ public class ChunkSnapshot public boolean isSectionEmpty(int sy) { - return empty[sy]; + return section[sy].isEmpty(); } public long getInhabitedTicks() { diff --git a/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ForgeMapChunkCache.java b/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ForgeMapChunkCache.java index 8732a20e..5fb0a74b 100644 --- a/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ForgeMapChunkCache.java +++ b/forge-1.9.4/src/main/java/org/dynmap/forge_1_9_4/ForgeMapChunkCache.java @@ -850,11 +850,6 @@ public class ForgeMapChunkCache extends MapChunkCache return DynmapBlockState.AIR; } @Override - public final int getBlockData(int x, int y, int z) - { - return 0; - } - @Override public final int getBlockSkyLight(int x, int y, int z) { if (y < 64)