diff --git a/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/BukkitVersionHelperSpigot114_1.java b/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/BukkitVersionHelperSpigot114_1.java index 34a71069..c77e5074 100644 --- a/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/BukkitVersionHelperSpigot114_1.java +++ b/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/BukkitVersionHelperSpigot114_1.java @@ -159,7 +159,7 @@ public class BukkitVersionHelperSpigot114_1 extends BukkitVersionHelperCB { */ @Override public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { - MapChunkCache114_1 c = new MapChunkCache114_1(); + MapChunkCache114_1 c = new MapChunkCache114_1(gencache); c.setChunks(dw, chunks); return c; } @@ -222,5 +222,9 @@ public class BukkitVersionHelperSpigot114_1 extends BukkitVersionHelperCB { } return biomenames; } + @Override + public boolean useGenericCache() { + return true; + } } diff --git a/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/MapChunkCache114_1.java b/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/MapChunkCache114_1.java index eddd5761..c218c47a 100644 --- a/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/MapChunkCache114_1.java +++ b/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/MapChunkCache114_1.java @@ -1,460 +1,71 @@ package org.dynmap.bukkit.helper.v114_1; -import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; import java.io.IOException; -import java.util.Arrays; +import java.util.List; -import org.bukkit.ChunkSnapshot; import org.bukkit.World; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.bukkit.helper.AbstractMapChunkCache; -import org.dynmap.bukkit.helper.BukkitVersionHelper; -import org.dynmap.bukkit.helper.SnapshotCache; -import org.dynmap.bukkit.helper.SnapshotCache.SnapshotRec; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.utils.DynIntHashMap; -import org.dynmap.utils.VisibilityLimit; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; import net.minecraft.server.v1_14_R1.Chunk; import net.minecraft.server.v1_14_R1.ChunkCoordIntPair; import net.minecraft.server.v1_14_R1.ChunkRegionLoader; -import net.minecraft.server.v1_14_R1.ChunkStatus; -import net.minecraft.server.v1_14_R1.DataBits; import net.minecraft.server.v1_14_R1.NBTTagCompound; -import net.minecraft.server.v1_14_R1.NBTTagList; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class MapChunkCache114_1 extends AbstractMapChunkCache { - - public static class NBTSnapshot implements Snapshot { - 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 Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - private final Object[] biomebase; - private final long captureFulltime; - private final int sectionCnt; - private final long inhabitedTicks; - - private static final int BLOCKS_PER_SECTION = 16 * 16 * 16; - private static final int COLUMNS_PER_CHUNK = 16 * 16; - private static final byte[] emptyData = new byte[BLOCKS_PER_SECTION / 2]; - private static final byte[] fullData = new byte[BLOCKS_PER_SECTION / 2]; - - static - { - 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 = fullData; - 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 - * - * @param x - * @param z - */ - public NBTSnapshot(int worldheight, int x, int z, long captime, long inhabitedTime) - { - this.x = x; - this.z = z; - this.captureFulltime = captime; - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - this.sectionCnt = worldheight / 16; - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - - /* Create empty height map */ - this.hmap = new int[16 * 16]; - - this.inhabitedTicks = inhabitedTime; - } - - public NBTSnapshot(NBTTagCompound nbt, int worldheight) { - this.x = nbt.getInt("xPos"); - this.z = nbt.getInt("zPos"); - this.captureFulltime = 0; - this.hmap = nbt.getIntArray("HeightMap"); - this.sectionCnt = worldheight / 16; - if (nbt.hasKey("InhabitedTime")) { - this.inhabitedTicks = nbt.getLong("InhabitedTime"); - } - else { - this.inhabitedTicks = 0; - } - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - /* Get sections */ - NBTTagList sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - NBTTagCompound sec = sect.getCompound(i); - int secnum = sec.getByte("Y"); - if (secnum >= this.sectionCnt) { - //Log.info("Section " + (int) secnum + " above world height " + worldheight); - continue; - } - if (secnum < 0) - continue; - //System.out.println("section(" + secnum + ")=" + sec.asString()); - // Create normal section to initialize - StdSection cursect = new StdSection(); - this.section[secnum] = cursect; - DynmapBlockState[] states = cursect.states; - DynmapBlockState[] palette = null; - // If we've got palette and block states list, process non-empty section - if (sec.hasKeyOfType("Palette", 9) && sec.hasKeyOfType("BlockStates", 12)) { - NBTTagList plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - NBTTagCompound tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.hasKey("Properties")) { - StringBuilder statestr = new StringBuilder(); - NBTTagCompound prop = tc.getCompound("Properties"); - for (String pid : prop.getKeys()) { - if (statestr.length() > 0) statestr.append(','); - statestr.append(pid).append('=').append(prop.get(pid).asString()); - } - palette[pi] = DynmapBlockState.getStateByNameAndState(pname, statestr.toString()); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.getBaseStateByName(pname); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.AIR; - } - } - int bitsperblock = (statelist.length * 64) / 4096; - DataBits db = new DataBits(bitsperblock, 4096, statelist); - if (bitsperblock > 8) { // Not palette - for (int j = 0; j < 4096; j++) { - states[j] = DynmapBlockState.getStateByGlobalIndex(db.a(j)); - } - } - else { - for (int j = 0; j < 4096; j++) { - int v = db.a(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.hasKey("BlockLight")) { - cursect.emitlight = sec.getByteArray("BlockLight"); - } - if (sec.hasKey("SkyLight")) { - cursect.skylight = sec.getByteArray("SkyLight"); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - Object[] bbl = BukkitVersionHelper.helper.getBiomeBaseList(); - if (nbt.hasKey("Biomes")) { - int[] bb = nbt.getIntArray("Biomes"); - if (bb != null) { - for (int i = 0; i < bb.length; i++) { - int bv = bb[i]; - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - } - } - - public int getX() - { - return x; - } - - public int getZ() - { - return z; - } - - public DynmapBlockState getBlockType(int x, int y, int z) - { - return section[y >> 4].getBlockType(x, y, z); - } - - public int getBlockSkyLight(int x, int y, int z) - { - return section[y >> 4].getBlockSkyLight(x, y, z); - } - - public int getBlockEmittedLight(int x, int y, int z) - { - return section[y >> 4].getBlockEmittedLight(x, y, z); - } - - public int getHighestBlockYAt(int x, int z) - { - return hmap[z << 4 | x]; - } - - public final long getCaptureFullTime() - { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) - { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } - - @Override - public Biome getBiome(int x, int z) { - return AbstractMapChunkCache.getBiomeByID(biome[z << 4 | x]); - } - - @Override - public Object[] getBiomeBaseFromSnapshot() { - return this.biomebase; - } +public class MapChunkCache114_1 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache114_1(GenericChunkCache cc) { + super(cc); + init(); } - - private NBTTagCompound fetchLoadedChunkNBT(World w, int x, int z) { + + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - if (cw.isChunkLoaded(x, z)) { - Chunk c = cw.getHandle().getChunkAt(x, z); + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkAt(chunk.x, chunk.z); if ((c != null) && c.loaded) { nbt = ChunkRegionLoader.saveChunk(cw.getHandle(), c); } - } - if (nbt != null) { - nbt = nbt.getCompound("Level"); if (nbt != null) { - String stat = nbt.getString("Status"); - ChunkStatus cs = ChunkStatus.a(stat); - if ((stat == null) || (!cs.b(ChunkStatus.LIGHT))) { - nbt = null; - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } } - return nbt; - } - - private NBTTagCompound loadChunkNBT(World w, int x, int z) { + return gc; + } + + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - ChunkCoordIntPair cc = new ChunkCoordIntPair(x, z); + ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); + GenericChunk gc = null; try { nbt = cw.getHandle().getChunkProvider().playerChunkMap.read(cc); } catch (IOException iox) { } if (nbt != null) { - nbt = nbt.getCompound("Level"); - if (nbt != null) { - String stat = nbt.getString("Status"); - if ((stat == null) || (stat.equals("full") == false)) { - nbt = null; - if ((stat == null) || stat.equals("") && DynmapCore.migrateChunks()) { - Chunk c = cw.getHandle().getChunkAt(x, z); - if (c != null) { - nbt = fetchLoadedChunkNBT(w, x, z); - cw.getHandle().unloadChunk(c); - } - } - } - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } - return nbt; - } - - @Override - public Snapshot wrapChunkSnapshot(ChunkSnapshot css) { - // TODO Auto-generated method stub - return null; - } - - // Load chunk snapshots - @Override - public int loadChunks(int max_to_load) { - if(dw.isLoaded() == false) - return 0; - int cnt = 0; - if(iterator == null) - iterator = chunks.listIterator(); + return gc; + } - DynmapCore.setIgnoreChunkLoads(true); - // Load the required chunks. - while((cnt < max_to_load) && iterator.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iterator.next(); - boolean vis = true; - if(visible_limits != null) { - vis = false; - for(VisibilityLimit limit : visible_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = true; - break; - } - } - } - if(vis && (hidden_limits != null)) { - for(VisibilityLimit limit : hidden_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = false; - break; - } - } - } - /* Check if cached chunk snapshot found */ - Snapshot ss = null; - long inhabited_ticks = 0; - DynIntHashMap tileData = null; - int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - SnapshotRec ssr = SnapshotCache.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if(ssr != null) { - inhabited_ticks = ssr.inhabitedTicks; - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - else { - ss = ssr.ss; - } - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - continue; - } - // Fetch NTB for chunk if loaded - NBTTagCompound nbt = fetchLoadedChunkNBT(w, chunk.x, chunk.z); - boolean did_load = false; - if (nbt == null) { - // Load NTB for chunk, if it exists - nbt = loadChunkNBT(w, chunk.x, chunk.z); - did_load = true; - } - if (nbt != null) { - NBTSnapshot nss = new NBTSnapshot(nbt, w.getMaxHeight()); - ss = nss; - inhabited_ticks = nss.getInhabitedTicks(); - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - } - else { - ss = EMPTY; - } - ssr = new SnapshotRec(); - ssr.ss = ss; - ssr.inhabitedTicks = inhabited_ticks; - ssr.tileData = tileData; - SnapshotCache.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - if (nbt == null) - endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); - else if (did_load) - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - else - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - DynmapCore.setIgnoreChunkLoads(false); - - if(iterator.hasNext() == false) { /* If we're done */ - isempty = true; - /* Fill missing chunks with empty dummy chunk */ - for(int i = 0; i < snaparray.length; i++) { - if(snaparray[i] == null) - snaparray[i] = EMPTY; - else if(snaparray[i] != EMPTY) - isempty = false; - } - } - - return cnt; - } + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } } + diff --git a/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/NBT.java b/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/NBT.java new file mode 100644 index 00000000..ee8ec466 --- /dev/null +++ b/bukkit-helper-114-1/src/main/java/org/dynmap/bukkit/helper/v114_1/NBT.java @@ -0,0 +1,127 @@ +package org.dynmap.bukkit.helper.v114_1; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import net.minecraft.server.v1_14_R1.DataBits; +import net.minecraft.server.v1_14_R1.NBTTagCompound; +import net.minecraft.server.v1_14_R1.NBTTagList; + +import java.util.Set; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final NBTTagCompound obj; + public NBTCompound(NBTTagCompound t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.getKeys(); + } + @Override + public boolean contains(String s) { + return obj.hasKey(s); + } + @Override + public boolean contains(String s, int i) { + return obj.hasKeyOfType(s, i); + } + @Override + public byte getByte(String s) { + return obj.getByte(s); + } + @Override + public short getShort(String s) { + return obj.getShort(s); + } + @Override + public int getInt(String s) { + return obj.getInt(s); + } + @Override + public long getLong(String s) { + return obj.getLong(s); + } + @Override + public float getFloat(String s) { + return obj.getFloat(s); + } + @Override + public double getDouble(String s) { + return obj.getDouble(s); + } + @Override + public String getString(String s) { + return obj.getString(s); + } + @Override + public byte[] getByteArray(String s) { + return obj.getByteArray(s); + } + @Override + public int[] getIntArray(String s) { + return obj.getIntArray(s); + } + @Override + public long[] getLongArray(String s) { + return obj.getLongArray(s); + } + @Override + public GenericNBTCompound getCompound(String s) { + return new NBTCompound(obj.getCompound(s)); + } + @Override + public GenericNBTList getList(String s, int i) { + return new NBTList(obj.getList(s, i)); + } + @Override + public boolean getBoolean(String s) { + return obj.getBoolean(s); + } + @Override + public String getAsString(String s) { + return obj.get(s).asString(); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + public String toString() { + return obj.toString(); + } + } + public static class NBTList implements GenericNBTList { + private final NBTTagList obj; + public NBTList(NBTTagList t) { + obj = t; + } + @Override + public int size() { + return obj.size(); + } + @Override + public String getString(int idx) { + return obj.getString(idx); + } + @Override + public GenericNBTCompound getCompound(int idx) { + return new NBTCompound(obj.getCompound(idx)); + } + public String toString() { + return obj.toString(); + } + } + public static class OurBitStorage implements GenericBitStorage { + private final DataBits bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new DataBits(bits, count, data); + } + @Override + public int get(int idx) { + return bs.a(idx); + } + } +} diff --git a/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/BukkitVersionHelperSpigot115.java b/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/BukkitVersionHelperSpigot115.java index 394c0a91..2870e951 100644 --- a/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/BukkitVersionHelperSpigot115.java +++ b/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/BukkitVersionHelperSpigot115.java @@ -15,7 +15,6 @@ import org.dynmap.DynmapChunk; import org.dynmap.Log; import org.dynmap.bukkit.helper.BukkitVersionHelperCB; import org.dynmap.bukkit.helper.BukkitWorld; -import org.dynmap.bukkit.helper.v115.MapChunkCache115; import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.Polygon; @@ -159,7 +158,7 @@ public class BukkitVersionHelperSpigot115 extends BukkitVersionHelperCB { */ @Override public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { - MapChunkCache115 c = new MapChunkCache115(); + MapChunkCache115 c = new MapChunkCache115(gencache); c.setChunks(dw, chunks); return c; } @@ -222,5 +221,9 @@ public class BukkitVersionHelperSpigot115 extends BukkitVersionHelperCB { } return biomenames; } + @Override + public boolean useGenericCache() { + return true; + } } diff --git a/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/MapChunkCache115.java b/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/MapChunkCache115.java index 3b556470..59ba14bc 100644 --- a/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/MapChunkCache115.java +++ b/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/MapChunkCache115.java @@ -1,485 +1,70 @@ package org.dynmap.bukkit.helper.v115; -import org.bukkit.Bukkit; -import org.bukkit.block.Biome; -import org.bukkit.craftbukkit.libs.jline.internal.Log; import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; import java.io.IOException; -import java.util.Arrays; +import java.util.List; -import org.bukkit.ChunkSnapshot; import org.bukkit.World; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.bukkit.helper.AbstractMapChunkCache; -import org.dynmap.bukkit.helper.BukkitVersionHelper; -import org.dynmap.bukkit.helper.SnapshotCache; -import org.dynmap.bukkit.helper.SnapshotCache.SnapshotRec; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.utils.DynIntHashMap; -import org.dynmap.utils.VisibilityLimit; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; import net.minecraft.server.v1_15_R1.Chunk; import net.minecraft.server.v1_15_R1.ChunkCoordIntPair; import net.minecraft.server.v1_15_R1.ChunkRegionLoader; -import net.minecraft.server.v1_15_R1.ChunkStatus; -import net.minecraft.server.v1_15_R1.DataBits; import net.minecraft.server.v1_15_R1.NBTTagCompound; -import net.minecraft.server.v1_15_R1.NBTTagList; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class MapChunkCache115 extends AbstractMapChunkCache { - - public static class NBTSnapshot implements Snapshot { - 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 Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - private final Object[] biomebase; - private final long captureFulltime; - private final int sectionCnt; - private final long inhabitedTicks; - - private static final int BLOCKS_PER_SECTION = 16 * 16 * 16; - private static final int COLUMNS_PER_CHUNK = 16 * 16; - private static final int V1_15_BIOME_PER_CHUNK = 4 * 4 * 64; - private static final byte[] emptyData = new byte[BLOCKS_PER_SECTION / 2]; - private static final byte[] fullData = new byte[BLOCKS_PER_SECTION / 2]; - - static - { - Arrays.fill(fullData, (byte)0xFF); - } - - private static byte[] dataCopy(byte[] v) { - if (Arrays.equals(v, emptyData)) - return emptyData; - else if (Arrays.equals(v, fullData)) - return fullData; - else - return v.clone(); - } - - 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 - * - * @param x - * @param z - */ - public NBTSnapshot(int worldheight, int x, int z, long captime, long inhabitedTime) - { - this.x = x; - this.z = z; - this.captureFulltime = captime; - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - this.sectionCnt = worldheight / 16; - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - - /* Create empty height map */ - this.hmap = new int[16 * 16]; - - this.inhabitedTicks = inhabitedTime; - } - - public NBTSnapshot(NBTTagCompound nbt, int worldheight) { - this.x = nbt.getInt("xPos"); - this.z = nbt.getInt("zPos"); - this.captureFulltime = 0; - this.hmap = nbt.getIntArray("HeightMap"); - this.sectionCnt = worldheight / 16; - if (nbt.hasKey("InhabitedTime")) { - this.inhabitedTicks = nbt.getLong("InhabitedTime"); - } - else { - this.inhabitedTicks = 0; - } - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - /* Get sections */ - NBTTagList sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - NBTTagCompound sec = sect.getCompound(i); - int secnum = sec.getByte("Y"); - if (secnum >= this.sectionCnt) { - //Log.info("Section " + (int) secnum + " above world height " + worldheight); - continue; - } - if (secnum < 0) - continue; - //System.out.println("section(" + secnum + ")=" + sec.asString()); - // Create normal section to initialize - StdSection cursect = new StdSection(); - this.section[secnum] = cursect; - DynmapBlockState[] states = cursect.states; - DynmapBlockState[] palette = null; - // If we've got palette and block states list, process non-empty section - if (sec.hasKeyOfType("Palette", 9) && sec.hasKeyOfType("BlockStates", 12)) { - NBTTagList plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - NBTTagCompound tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.hasKey("Properties")) { - StringBuilder statestr = new StringBuilder(); - NBTTagCompound prop = tc.getCompound("Properties"); - for (String pid : prop.getKeys()) { - if (statestr.length() > 0) statestr.append(','); - statestr.append(pid).append('=').append(prop.get(pid).asString()); - } - palette[pi] = DynmapBlockState.getStateByNameAndState(pname, statestr.toString()); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.getBaseStateByName(pname); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.AIR; - } - } - int bitsperblock = (statelist.length * 64) / 4096; - DataBits db = new DataBits(bitsperblock, 4096, statelist); - if (bitsperblock > 8) { // Not palette - for (int j = 0; j < 4096; j++) { - states[j] = DynmapBlockState.getStateByGlobalIndex(db.a(j)); - } - } - else { - for (int j = 0; j < 4096; j++) { - int v = db.a(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.hasKey("BlockLight")) { - cursect.emitlight = dataCopy(sec.getByteArray("BlockLight")); - } - if (sec.hasKey("SkyLight")) { - cursect.skylight = dataCopy(sec.getByteArray("SkyLight")); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - Object[] bbl = BukkitVersionHelper.helper.getBiomeBaseList(); - if (nbt.hasKey("Biomes")) { - int[] bb = nbt.getIntArray("Biomes"); - if (bb != null) { - // If v1.15+ format - if (bb.length > COLUMNS_PER_CHUNK) { - // For now, just pad the grid with the first 16 - for (int i = 0; i < COLUMNS_PER_CHUNK; i++) { - int off = ((i >> 4) & 0xC) + ((i >> 2) & 0x3); - int bv = bb[off + 64]; // Offset to y=64 - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - else { // Else, older chunks - for (int i = 0; i < bb.length; i++) { - int bv = bb[i]; - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - } - } - } - - public int getX() - { - return x; - } - - public int getZ() - { - return z; - } - - public DynmapBlockState getBlockType(int x, int y, int z) - { - return section[y >> 4].getBlockType(x, y, z); - } - - public int getBlockSkyLight(int x, int y, int z) - { - return section[y >> 4].getBlockSkyLight(x, y, z); - } - - public int getBlockEmittedLight(int x, int y, int z) - { - return section[y >> 4].getBlockEmittedLight(x, y, z); - } - - public int getHighestBlockYAt(int x, int z) - { - return hmap[z << 4 | x]; - } - - public final long getCaptureFullTime() - { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) - { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } - - @Override - public Biome getBiome(int x, int z) { - return AbstractMapChunkCache.getBiomeByID(biome[z << 4 | x]); - } - - @Override - public Object[] getBiomeBaseFromSnapshot() { - return this.biomebase; - } +public class MapChunkCache115 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache115(GenericChunkCache cc) { + super(cc); + init(); } - - private NBTTagCompound fetchLoadedChunkNBT(World w, int x, int z) { + + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - if (cw.isChunkLoaded(x, z)) { - Chunk c = cw.getHandle().getChunkAt(x, z); + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkAt(chunk.x, chunk.z); if ((c != null) && c.loaded) { nbt = ChunkRegionLoader.saveChunk(cw.getHandle(), c); } - } - if (nbt != null) { - nbt = nbt.getCompound("Level"); if (nbt != null) { - String stat = nbt.getString("Status"); - ChunkStatus cs = ChunkStatus.a(stat); - if ((stat == null) || (!cs.b(ChunkStatus.LIGHT))) { - nbt = null; - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } } - return nbt; - } - - private NBTTagCompound loadChunkNBT(World w, int x, int z) { + return gc; + } + + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - ChunkCoordIntPair cc = new ChunkCoordIntPair(x, z); + ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); + GenericChunk gc = null; try { nbt = cw.getHandle().getChunkProvider().playerChunkMap.read(cc); } catch (IOException iox) { } if (nbt != null) { - nbt = nbt.getCompound("Level"); - if (nbt != null) { - String stat = nbt.getString("Status"); - if ((stat == null) || (stat.equals("full") == false)) { - nbt = null; - if ((stat == null) || stat.equals("") && DynmapCore.migrateChunks()) { - Chunk c = cw.getHandle().getChunkAt(x, z); - if (c != null) { - nbt = fetchLoadedChunkNBT(w, x, z); - cw.getHandle().unloadChunk(c); - } - } - } - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } - return nbt; - } - - @Override - public Snapshot wrapChunkSnapshot(ChunkSnapshot css) { - // TODO Auto-generated method stub - return null; - } - - // Load chunk snapshots - @Override - public int loadChunks(int max_to_load) { - if(dw.isLoaded() == false) - return 0; - int cnt = 0; - if(iterator == null) - iterator = chunks.listIterator(); + return gc; + } - DynmapCore.setIgnoreChunkLoads(true); - // Load the required chunks. - while((cnt < max_to_load) && iterator.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iterator.next(); - boolean vis = true; - if(visible_limits != null) { - vis = false; - for(VisibilityLimit limit : visible_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = true; - break; - } - } - } - if(vis && (hidden_limits != null)) { - for(VisibilityLimit limit : hidden_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = false; - break; - } - } - } - /* Check if cached chunk snapshot found */ - Snapshot ss = null; - long inhabited_ticks = 0; - DynIntHashMap tileData = null; - int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - SnapshotRec ssr = SnapshotCache.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if(ssr != null) { - inhabited_ticks = ssr.inhabitedTicks; - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - else { - ss = ssr.ss; - } - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - continue; - } - // Fetch NTB for chunk if loaded - NBTTagCompound nbt = fetchLoadedChunkNBT(w, chunk.x, chunk.z); - boolean did_load = false; - if (nbt == null) { - // Load NTB for chunk, if it exists - nbt = loadChunkNBT(w, chunk.x, chunk.z); - did_load = true; - } - if (nbt != null) { - NBTSnapshot nss = new NBTSnapshot(nbt, w.getMaxHeight()); - ss = nss; - inhabited_ticks = nss.getInhabitedTicks(); - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - } - else { - ss = EMPTY; - } - ssr = new SnapshotRec(); - ssr.ss = ss; - ssr.inhabitedTicks = inhabited_ticks; - ssr.tileData = tileData; - SnapshotCache.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - if (nbt == null) - endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); - else if (did_load) - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - else - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - DynmapCore.setIgnoreChunkLoads(false); - - if(iterator.hasNext() == false) { /* If we're done */ - isempty = true; - /* Fill missing chunks with empty dummy chunk */ - for(int i = 0; i < snaparray.length; i++) { - if(snaparray[i] == null) - snaparray[i] = EMPTY; - else if(snaparray[i] != EMPTY) - isempty = false; - } - } - - return cnt; - } + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } } diff --git a/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/NBT.java b/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/NBT.java new file mode 100644 index 00000000..19b2b5d4 --- /dev/null +++ b/bukkit-helper-115/src/main/java/org/dynmap/bukkit/helper/v115/NBT.java @@ -0,0 +1,127 @@ +package org.dynmap.bukkit.helper.v115; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import net.minecraft.server.v1_15_R1.DataBits; +import net.minecraft.server.v1_15_R1.NBTTagCompound; +import net.minecraft.server.v1_15_R1.NBTTagList; + +import java.util.Set; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final NBTTagCompound obj; + public NBTCompound(NBTTagCompound t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.getKeys(); + } + @Override + public boolean contains(String s) { + return obj.hasKey(s); + } + @Override + public boolean contains(String s, int i) { + return obj.hasKeyOfType(s, i); + } + @Override + public byte getByte(String s) { + return obj.getByte(s); + } + @Override + public short getShort(String s) { + return obj.getShort(s); + } + @Override + public int getInt(String s) { + return obj.getInt(s); + } + @Override + public long getLong(String s) { + return obj.getLong(s); + } + @Override + public float getFloat(String s) { + return obj.getFloat(s); + } + @Override + public double getDouble(String s) { + return obj.getDouble(s); + } + @Override + public String getString(String s) { + return obj.getString(s); + } + @Override + public byte[] getByteArray(String s) { + return obj.getByteArray(s); + } + @Override + public int[] getIntArray(String s) { + return obj.getIntArray(s); + } + @Override + public long[] getLongArray(String s) { + return obj.getLongArray(s); + } + @Override + public GenericNBTCompound getCompound(String s) { + return new NBTCompound(obj.getCompound(s)); + } + @Override + public GenericNBTList getList(String s, int i) { + return new NBTList(obj.getList(s, i)); + } + @Override + public boolean getBoolean(String s) { + return obj.getBoolean(s); + } + @Override + public String getAsString(String s) { + return obj.get(s).asString(); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + public String toString() { + return obj.toString(); + } + } + public static class NBTList implements GenericNBTList { + private final NBTTagList obj; + public NBTList(NBTTagList t) { + obj = t; + } + @Override + public int size() { + return obj.size(); + } + @Override + public String getString(int idx) { + return obj.getString(idx); + } + @Override + public GenericNBTCompound getCompound(int idx) { + return new NBTCompound(obj.getCompound(idx)); + } + public String toString() { + return obj.toString(); + } + } + public static class OurBitStorage implements GenericBitStorage { + private final DataBits bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new DataBits(bits, count, data); + } + @Override + public int get(int idx) { + return bs.a(idx); + } + } +} diff --git a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java index 46bbd18c..d2c01657 100644 --- a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java +++ b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/BukkitVersionHelperSpigot116_2.java @@ -1,16 +1,13 @@ package org.dynmap.bukkit.helper.v116_2; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import org.bukkit.Bukkit; import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.World; @@ -19,16 +16,13 @@ import org.bukkit.entity.Player; import org.dynmap.DynmapChunk; import org.dynmap.Log; import org.dynmap.bukkit.helper.BukkitMaterial; -import org.dynmap.bukkit.helper.BukkitVersionHelperCB; import org.dynmap.bukkit.helper.BukkitVersionHelperGeneric; import org.dynmap.bukkit.helper.BukkitWorld; -import org.dynmap.bukkit.helper.v116_2.MapChunkCache116_2; import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.Polygon; import net.minecraft.server.v1_16_R2.BiomeBase; -import net.minecraft.server.v1_16_R2.BiomeFog; import net.minecraft.server.v1_16_R2.Block; import net.minecraft.server.v1_16_R2.BlockFluids; import net.minecraft.server.v1_16_R2.BlockRotatable; @@ -151,7 +145,7 @@ public class BukkitVersionHelperSpigot116_2 extends BukkitVersionHelperGeneric { */ @Override public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { - MapChunkCache116_2 c = new MapChunkCache116_2(); + MapChunkCache116_2 c = new MapChunkCache116_2(gencache); c.setChunks(dw, chunks); return c; } @@ -268,4 +262,8 @@ public class BukkitVersionHelperSpigot116_2 extends BukkitVersionHelperGeneric { } return null; } + @Override + public boolean useGenericCache() { + return true; + } } diff --git a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/MapChunkCache116_2.java b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/MapChunkCache116_2.java index 1e7cbc36..f8b66cf1 100644 --- a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/MapChunkCache116_2.java +++ b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/MapChunkCache116_2.java @@ -1,493 +1,71 @@ package org.dynmap.bukkit.helper.v116_2; -import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; import java.io.IOException; -import java.util.Arrays; +import java.util.List; -import org.bukkit.ChunkSnapshot; import org.bukkit.World; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.bukkit.helper.AbstractMapChunkCache; -import org.dynmap.bukkit.helper.BukkitVersionHelper; -import org.dynmap.bukkit.helper.SnapshotCache; -import org.dynmap.bukkit.helper.SnapshotCache.SnapshotRec; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.utils.DynIntHashMap; -import org.dynmap.utils.VisibilityLimit; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; import net.minecraft.server.v1_16_R2.Chunk; import net.minecraft.server.v1_16_R2.ChunkCoordIntPair; import net.minecraft.server.v1_16_R2.ChunkRegionLoader; -import net.minecraft.server.v1_16_R2.ChunkStatus; -import net.minecraft.server.v1_16_R2.DataBits; -import net.minecraft.server.v1_16_R2.DataBitsPacked; import net.minecraft.server.v1_16_R2.NBTTagCompound; -import net.minecraft.server.v1_16_R2.NBTTagList; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class MapChunkCache116_2 extends AbstractMapChunkCache { - - public static class NBTSnapshot implements Snapshot { - 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 Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - private final Object[] biomebase; - private final long captureFulltime; - private final int sectionCnt; - private final long inhabitedTicks; - - private static final int BLOCKS_PER_SECTION = 16 * 16 * 16; - private static final int COLUMNS_PER_CHUNK = 16 * 16; - private static final int V1_15_BIOME_PER_CHUNK = 4 * 4 * 64; - private static final byte[] emptyData = new byte[BLOCKS_PER_SECTION / 2]; - private static final byte[] fullData = new byte[BLOCKS_PER_SECTION / 2]; - - static - { - Arrays.fill(fullData, (byte)0xFF); - } - - private static byte[] dataCopy(byte[] v) { - if (Arrays.equals(v, emptyData)) - return emptyData; - else if (Arrays.equals(v, fullData)) - return fullData; - else - return v.clone(); - } - - 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 - * - * @param x - * @param z - */ - public NBTSnapshot(int worldheight, int x, int z, long captime, long inhabitedTime) - { - this.x = x; - this.z = z; - this.captureFulltime = captime; - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - this.sectionCnt = worldheight / 16; - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - - /* Create empty height map */ - this.hmap = new int[16 * 16]; - - this.inhabitedTicks = inhabitedTime; - } - - public NBTSnapshot(NBTTagCompound nbt, int worldheight) { - this.x = nbt.getInt("xPos"); - this.z = nbt.getInt("zPos"); - this.captureFulltime = 0; - this.hmap = nbt.getIntArray("HeightMap"); - this.sectionCnt = worldheight / 16; - if (nbt.hasKey("InhabitedTime")) { - this.inhabitedTicks = nbt.getLong("InhabitedTime"); - } - else { - this.inhabitedTicks = 0; - } - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - /* Get sections */ - NBTTagList sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - NBTTagCompound sec = sect.getCompound(i); - int secnum = sec.getByte("Y"); - if (secnum >= this.sectionCnt) { - //Log.info("Section " + (int) secnum + " above world height " + worldheight); - continue; - } - if (secnum < 0) - continue; - //System.out.println("section(" + secnum + ")=" + sec.asString()); - // Create normal section to initialize - StdSection cursect = new StdSection(); - this.section[secnum] = cursect; - DynmapBlockState[] states = cursect.states; - DynmapBlockState[] palette = null; - // If we've got palette and block states list, process non-empty section - if (sec.hasKeyOfType("Palette", 9) && sec.hasKeyOfType("BlockStates", 12)) { - NBTTagList plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - NBTTagCompound tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.hasKey("Properties")) { - StringBuilder statestr = new StringBuilder(); - NBTTagCompound prop = tc.getCompound("Properties"); - for (String pid : prop.getKeys()) { - if (statestr.length() > 0) statestr.append(','); - statestr.append(pid).append('=').append(prop.get(pid).asString()); - } - palette[pi] = DynmapBlockState.getStateByNameAndState(pname, statestr.toString()); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.getBaseStateByName(pname); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.AIR; - } - } - int recsperblock = (4096 + statelist.length - 1) / statelist.length; - int bitsperblock = 64 / recsperblock; - DataBits db = null; - DataBitsPacked dbp = null; - try { - db = new DataBits(bitsperblock, 4096, statelist); - } catch (Exception x) { // Handle legacy encoded - bitsperblock = (statelist.length * 64) / 4096; - dbp = new DataBitsPacked(bitsperblock, 4096, statelist); - } - if (bitsperblock > 8) { // Not palette - for (int j = 0; j < 4096; j++) { - int v = (db != null) ? db.a(j) : dbp.a(j); - states[j] = DynmapBlockState.getStateByGlobalIndex(v); - } - } - else { - for (int j = 0; j < 4096; j++) { - int v = (db != null) ? db.a(j) : dbp.a(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.hasKey("BlockLight")) { - cursect.emitlight = dataCopy(sec.getByteArray("BlockLight")); - } - if (sec.hasKey("SkyLight")) { - cursect.skylight = dataCopy(sec.getByteArray("SkyLight")); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - Object[] bbl = BukkitVersionHelper.helper.getBiomeBaseList(); - if (nbt.hasKey("Biomes")) { - int[] bb = nbt.getIntArray("Biomes"); - if (bb != null) { - // If v1.15+ format - if (bb.length > COLUMNS_PER_CHUNK) { - // For now, just pad the grid with the first 16 - for (int i = 0; i < COLUMNS_PER_CHUNK; i++) { - int off = ((i >> 4) & 0xC) + ((i >> 2) & 0x3); - int bv = bb[off + 64]; // Offset to y=64 - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - else { // Else, older chunks - for (int i = 0; i < bb.length; i++) { - int bv = bb[i]; - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - } - } - } - - public int getX() - { - return x; - } - - public int getZ() - { - return z; - } - - public DynmapBlockState getBlockType(int x, int y, int z) - { - return section[y >> 4].getBlockType(x, y, z); - } - - public int getBlockSkyLight(int x, int y, int z) - { - return section[y >> 4].getBlockSkyLight(x, y, z); - } - - public int getBlockEmittedLight(int x, int y, int z) - { - return section[y >> 4].getBlockEmittedLight(x, y, z); - } - - public int getHighestBlockYAt(int x, int z) - { - return hmap[z << 4 | x]; - } - - public final long getCaptureFullTime() - { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) - { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } - - @Override - public Biome getBiome(int x, int z) { - return AbstractMapChunkCache.getBiomeByID(biome[z << 4 | x]); - } - - @Override - public Object[] getBiomeBaseFromSnapshot() { - return this.biomebase; - } +public class MapChunkCache116_2 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache116_2(GenericChunkCache cc) { + super(cc); + init(); } - - private NBTTagCompound fetchLoadedChunkNBT(World w, int x, int z) { + + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - if (cw.isChunkLoaded(x, z)) { - Chunk c = cw.getHandle().getChunkAt(x, z); + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkAt(chunk.x, chunk.z); if ((c != null) && c.loaded) { nbt = ChunkRegionLoader.saveChunk(cw.getHandle(), c); } - } - if (nbt != null) { - nbt = nbt.getCompound("Level"); if (nbt != null) { - String stat = nbt.getString("Status"); - ChunkStatus cs = ChunkStatus.a(stat); - if ((stat == null) || (!cs.b(ChunkStatus.LIGHT))) { - nbt = null; - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } } - return nbt; - } - - private NBTTagCompound loadChunkNBT(World w, int x, int z) { + return gc; + } + + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - ChunkCoordIntPair cc = new ChunkCoordIntPair(x, z); + ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); + GenericChunk gc = null; try { nbt = cw.getHandle().getChunkProvider().playerChunkMap.read(cc); } catch (IOException iox) { } if (nbt != null) { - nbt = nbt.getCompound("Level"); - if (nbt != null) { - String stat = nbt.getString("Status"); - if ((stat == null) || (stat.equals("full") == false)) { - nbt = null; - if ((stat == null) || stat.equals("") && DynmapCore.migrateChunks()) { - Chunk c = cw.getHandle().getChunkAt(x, z); - if (c != null) { - nbt = fetchLoadedChunkNBT(w, x, z); - cw.getHandle().unloadChunk(c); - } - } - } - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } - return nbt; - } - - @Override - public Snapshot wrapChunkSnapshot(ChunkSnapshot css) { - // TODO Auto-generated method stub - return null; - } - - // Load chunk snapshots - @Override - public int loadChunks(int max_to_load) { - if(dw.isLoaded() == false) - return 0; - int cnt = 0; - if(iterator == null) - iterator = chunks.listIterator(); + return gc; + } - DynmapCore.setIgnoreChunkLoads(true); - // Load the required chunks. - while((cnt < max_to_load) && iterator.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iterator.next(); - boolean vis = true; - if(visible_limits != null) { - vis = false; - for(VisibilityLimit limit : visible_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = true; - break; - } - } - } - if(vis && (hidden_limits != null)) { - for(VisibilityLimit limit : hidden_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = false; - break; - } - } - } - /* Check if cached chunk snapshot found */ - Snapshot ss = null; - long inhabited_ticks = 0; - DynIntHashMap tileData = null; - int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - SnapshotRec ssr = SnapshotCache.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if(ssr != null) { - inhabited_ticks = ssr.inhabitedTicks; - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - else { - ss = ssr.ss; - } - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - continue; - } - // Fetch NTB for chunk if loaded - NBTTagCompound nbt = fetchLoadedChunkNBT(w, chunk.x, chunk.z); - boolean did_load = false; - if (nbt == null) { - // Load NTB for chunk, if it exists - nbt = loadChunkNBT(w, chunk.x, chunk.z); - did_load = true; - } - if (nbt != null) { - NBTSnapshot nss = new NBTSnapshot(nbt, w.getMaxHeight()); - ss = nss; - inhabited_ticks = nss.getInhabitedTicks(); - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - } - else { - ss = EMPTY; - } - ssr = new SnapshotRec(); - ssr.ss = ss; - ssr.inhabitedTicks = inhabited_ticks; - ssr.tileData = tileData; - SnapshotCache.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - if (nbt == null) - endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); - else if (did_load) - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - else - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - DynmapCore.setIgnoreChunkLoads(false); - - if(iterator.hasNext() == false) { /* If we're done */ - isempty = true; - /* Fill missing chunks with empty dummy chunk */ - for(int i = 0; i < snaparray.length; i++) { - if(snaparray[i] == null) - snaparray[i] = EMPTY; - else if(snaparray[i] != EMPTY) - isempty = false; - } - } - - return cnt; - } + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } } + diff --git a/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/NBT.java b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/NBT.java new file mode 100644 index 00000000..5b54b0af --- /dev/null +++ b/bukkit-helper-116-2/src/main/java/org/dynmap/bukkit/helper/v116_2/NBT.java @@ -0,0 +1,127 @@ +package org.dynmap.bukkit.helper.v116_2; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import net.minecraft.server.v1_16_R2.DataBits; +import net.minecraft.server.v1_16_R2.NBTTagCompound; +import net.minecraft.server.v1_16_R2.NBTTagList; + +import java.util.Set; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final NBTTagCompound obj; + public NBTCompound(NBTTagCompound t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.getKeys(); + } + @Override + public boolean contains(String s) { + return obj.hasKey(s); + } + @Override + public boolean contains(String s, int i) { + return obj.hasKeyOfType(s, i); + } + @Override + public byte getByte(String s) { + return obj.getByte(s); + } + @Override + public short getShort(String s) { + return obj.getShort(s); + } + @Override + public int getInt(String s) { + return obj.getInt(s); + } + @Override + public long getLong(String s) { + return obj.getLong(s); + } + @Override + public float getFloat(String s) { + return obj.getFloat(s); + } + @Override + public double getDouble(String s) { + return obj.getDouble(s); + } + @Override + public String getString(String s) { + return obj.getString(s); + } + @Override + public byte[] getByteArray(String s) { + return obj.getByteArray(s); + } + @Override + public int[] getIntArray(String s) { + return obj.getIntArray(s); + } + @Override + public long[] getLongArray(String s) { + return obj.getLongArray(s); + } + @Override + public GenericNBTCompound getCompound(String s) { + return new NBTCompound(obj.getCompound(s)); + } + @Override + public GenericNBTList getList(String s, int i) { + return new NBTList(obj.getList(s, i)); + } + @Override + public boolean getBoolean(String s) { + return obj.getBoolean(s); + } + @Override + public String getAsString(String s) { + return obj.get(s).asString(); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + public String toString() { + return obj.toString(); + } + } + public static class NBTList implements GenericNBTList { + private final NBTTagList obj; + public NBTList(NBTTagList t) { + obj = t; + } + @Override + public int size() { + return obj.size(); + } + @Override + public String getString(int idx) { + return obj.getString(idx); + } + @Override + public GenericNBTCompound getCompound(int idx) { + return new NBTCompound(obj.getCompound(idx)); + } + public String toString() { + return obj.toString(); + } + } + public static class OurBitStorage implements GenericBitStorage { + private final DataBits bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new DataBits(bits, count, data); + } + @Override + public int get(int idx) { + return bs.a(idx); + } + } +} diff --git a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java index d8902cc5..aba68db6 100644 --- a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java +++ b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/BukkitVersionHelperSpigot116_3.java @@ -1,16 +1,13 @@ package org.dynmap.bukkit.helper.v116_3; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import org.bukkit.Bukkit; import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.World; @@ -19,16 +16,13 @@ import org.bukkit.entity.Player; import org.dynmap.DynmapChunk; import org.dynmap.Log; import org.dynmap.bukkit.helper.BukkitMaterial; -import org.dynmap.bukkit.helper.BukkitVersionHelperCB; import org.dynmap.bukkit.helper.BukkitVersionHelperGeneric; import org.dynmap.bukkit.helper.BukkitWorld; -import org.dynmap.bukkit.helper.v116_3.MapChunkCache116_3; import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.Polygon; import net.minecraft.server.v1_16_R2.BiomeBase; -import net.minecraft.server.v1_16_R2.BiomeFog; import net.minecraft.server.v1_16_R2.Block; import net.minecraft.server.v1_16_R2.BlockFluids; import net.minecraft.server.v1_16_R2.BlockRotatable; @@ -151,7 +145,7 @@ public class BukkitVersionHelperSpigot116_3 extends BukkitVersionHelperGeneric { */ @Override public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { - MapChunkCache116_3 c = new MapChunkCache116_3(); + MapChunkCache116_3 c = new MapChunkCache116_3(gencache); c.setChunks(dw, chunks); return c; } @@ -268,4 +262,8 @@ public class BukkitVersionHelperSpigot116_3 extends BukkitVersionHelperGeneric { } return null; } + @Override + public boolean useGenericCache() { + return true; + } } diff --git a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/MapChunkCache116_3.java b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/MapChunkCache116_3.java index cc75b580..13bae84f 100644 --- a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/MapChunkCache116_3.java +++ b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/MapChunkCache116_3.java @@ -1,493 +1,70 @@ package org.dynmap.bukkit.helper.v116_3; -import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; import java.io.IOException; -import java.util.Arrays; +import java.util.List; -import org.bukkit.ChunkSnapshot; import org.bukkit.World; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.bukkit.helper.AbstractMapChunkCache; -import org.dynmap.bukkit.helper.BukkitVersionHelper; -import org.dynmap.bukkit.helper.SnapshotCache; -import org.dynmap.bukkit.helper.SnapshotCache.SnapshotRec; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.utils.DynIntHashMap; -import org.dynmap.utils.VisibilityLimit; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; import net.minecraft.server.v1_16_R2.Chunk; import net.minecraft.server.v1_16_R2.ChunkCoordIntPair; import net.minecraft.server.v1_16_R2.ChunkRegionLoader; -import net.minecraft.server.v1_16_R2.ChunkStatus; -import net.minecraft.server.v1_16_R2.DataBits; -import net.minecraft.server.v1_16_R2.DataBitsPacked; import net.minecraft.server.v1_16_R2.NBTTagCompound; -import net.minecraft.server.v1_16_R2.NBTTagList; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class MapChunkCache116_3 extends AbstractMapChunkCache { - - public static class NBTSnapshot implements Snapshot { - 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 Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - private final Object[] biomebase; - private final long captureFulltime; - private final int sectionCnt; - private final long inhabitedTicks; - - private static final int BLOCKS_PER_SECTION = 16 * 16 * 16; - private static final int COLUMNS_PER_CHUNK = 16 * 16; - private static final int V1_15_BIOME_PER_CHUNK = 4 * 4 * 64; - private static final byte[] emptyData = new byte[BLOCKS_PER_SECTION / 2]; - private static final byte[] fullData = new byte[BLOCKS_PER_SECTION / 2]; - - static - { - Arrays.fill(fullData, (byte)0xFF); - } - - private static byte[] dataCopy(byte[] v) { - if (Arrays.equals(v, emptyData)) - return emptyData; - else if (Arrays.equals(v, fullData)) - return fullData; - else - return v.clone(); - } - - 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 - * - * @param x - * @param z - */ - public NBTSnapshot(int worldheight, int x, int z, long captime, long inhabitedTime) - { - this.x = x; - this.z = z; - this.captureFulltime = captime; - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - this.sectionCnt = worldheight / 16; - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - - /* Create empty height map */ - this.hmap = new int[16 * 16]; - - this.inhabitedTicks = inhabitedTime; - } - - public NBTSnapshot(NBTTagCompound nbt, int worldheight) { - this.x = nbt.getInt("xPos"); - this.z = nbt.getInt("zPos"); - this.captureFulltime = 0; - this.hmap = nbt.getIntArray("HeightMap"); - this.sectionCnt = worldheight / 16; - if (nbt.hasKey("InhabitedTime")) { - this.inhabitedTicks = nbt.getLong("InhabitedTime"); - } - else { - this.inhabitedTicks = 0; - } - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - /* Get sections */ - NBTTagList sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - NBTTagCompound sec = sect.getCompound(i); - int secnum = sec.getByte("Y"); - if (secnum >= this.sectionCnt) { - //Log.info("Section " + (int) secnum + " above world height " + worldheight); - continue; - } - if (secnum < 0) - continue; - //System.out.println("section(" + secnum + ")=" + sec.asString()); - // Create normal section to initialize - StdSection cursect = new StdSection(); - this.section[secnum] = cursect; - DynmapBlockState[] states = cursect.states; - DynmapBlockState[] palette = null; - // If we've got palette and block states list, process non-empty section - if (sec.hasKeyOfType("Palette", 9) && sec.hasKeyOfType("BlockStates", 12)) { - NBTTagList plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - NBTTagCompound tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.hasKey("Properties")) { - StringBuilder statestr = new StringBuilder(); - NBTTagCompound prop = tc.getCompound("Properties"); - for (String pid : prop.getKeys()) { - if (statestr.length() > 0) statestr.append(','); - statestr.append(pid).append('=').append(prop.get(pid).asString()); - } - palette[pi] = DynmapBlockState.getStateByNameAndState(pname, statestr.toString()); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.getBaseStateByName(pname); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.AIR; - } - } - int recsperblock = (4096 + statelist.length - 1) / statelist.length; - int bitsperblock = 64 / recsperblock; - DataBits db = null; - DataBitsPacked dbp = null; - try { - db = new DataBits(bitsperblock, 4096, statelist); - } catch (Exception x) { // Handle legacy encoded - bitsperblock = (statelist.length * 64) / 4096; - dbp = new DataBitsPacked(bitsperblock, 4096, statelist); - } - if (bitsperblock > 8) { // Not palette - for (int j = 0; j < 4096; j++) { - int v = (db != null) ? db.a(j) : dbp.a(j); - states[j] = DynmapBlockState.getStateByGlobalIndex(v); - } - } - else { - for (int j = 0; j < 4096; j++) { - int v = (db != null) ? db.a(j) : dbp.a(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.hasKey("BlockLight")) { - cursect.emitlight = dataCopy(sec.getByteArray("BlockLight")); - } - if (sec.hasKey("SkyLight")) { - cursect.skylight = dataCopy(sec.getByteArray("SkyLight")); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - Object[] bbl = BukkitVersionHelper.helper.getBiomeBaseList(); - if (nbt.hasKey("Biomes")) { - int[] bb = nbt.getIntArray("Biomes"); - if (bb != null) { - // If v1.15+ format - if (bb.length > COLUMNS_PER_CHUNK) { - // For now, just pad the grid with the first 16 - for (int i = 0; i < COLUMNS_PER_CHUNK; i++) { - int off = ((i >> 4) & 0xC) + ((i >> 2) & 0x3); - int bv = bb[off + 64]; // Offset to y=64 - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - else { // Else, older chunks - for (int i = 0; i < bb.length; i++) { - int bv = bb[i]; - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - } - } - } - - public int getX() - { - return x; - } - - public int getZ() - { - return z; - } - - public DynmapBlockState getBlockType(int x, int y, int z) - { - return section[y >> 4].getBlockType(x, y, z); - } - - public int getBlockSkyLight(int x, int y, int z) - { - return section[y >> 4].getBlockSkyLight(x, y, z); - } - - public int getBlockEmittedLight(int x, int y, int z) - { - return section[y >> 4].getBlockEmittedLight(x, y, z); - } - - public int getHighestBlockYAt(int x, int z) - { - return hmap[z << 4 | x]; - } - - public final long getCaptureFullTime() - { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) - { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } - - @Override - public Biome getBiome(int x, int z) { - return AbstractMapChunkCache.getBiomeByID(biome[z << 4 | x]); - } - - @Override - public Object[] getBiomeBaseFromSnapshot() { - return this.biomebase; - } +public class MapChunkCache116_3 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache116_3(GenericChunkCache cc) { + super(cc); + init(); } - - private NBTTagCompound fetchLoadedChunkNBT(World w, int x, int z) { + + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - if (cw.isChunkLoaded(x, z)) { - Chunk c = cw.getHandle().getChunkAt(x, z); + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkAt(chunk.x, chunk.z); if ((c != null) && c.loaded) { nbt = ChunkRegionLoader.saveChunk(cw.getHandle(), c); } - } - if (nbt != null) { - nbt = nbt.getCompound("Level"); if (nbt != null) { - String stat = nbt.getString("Status"); - ChunkStatus cs = ChunkStatus.a(stat); - if ((stat == null) || (!cs.b(ChunkStatus.LIGHT))) { - nbt = null; - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } } - return nbt; - } - - private NBTTagCompound loadChunkNBT(World w, int x, int z) { + return gc; + } + + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - ChunkCoordIntPair cc = new ChunkCoordIntPair(x, z); + ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); + GenericChunk gc = null; try { nbt = cw.getHandle().getChunkProvider().playerChunkMap.read(cc); } catch (IOException iox) { } if (nbt != null) { - nbt = nbt.getCompound("Level"); - if (nbt != null) { - String stat = nbt.getString("Status"); - if ((stat == null) || (stat.equals("full") == false)) { - nbt = null; - if ((stat == null) || stat.equals("") && DynmapCore.migrateChunks()) { - Chunk c = cw.getHandle().getChunkAt(x, z); - if (c != null) { - nbt = fetchLoadedChunkNBT(w, x, z); - cw.getHandle().unloadChunk(c); - } - } - } - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } - return nbt; - } - - @Override - public Snapshot wrapChunkSnapshot(ChunkSnapshot css) { - // TODO Auto-generated method stub - return null; - } - - // Load chunk snapshots - @Override - public int loadChunks(int max_to_load) { - if(dw.isLoaded() == false) - return 0; - int cnt = 0; - if(iterator == null) - iterator = chunks.listIterator(); + return gc; + } - DynmapCore.setIgnoreChunkLoads(true); - // Load the required chunks. - while((cnt < max_to_load) && iterator.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iterator.next(); - boolean vis = true; - if(visible_limits != null) { - vis = false; - for(VisibilityLimit limit : visible_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = true; - break; - } - } - } - if(vis && (hidden_limits != null)) { - for(VisibilityLimit limit : hidden_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = false; - break; - } - } - } - /* Check if cached chunk snapshot found */ - Snapshot ss = null; - long inhabited_ticks = 0; - DynIntHashMap tileData = null; - int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - SnapshotRec ssr = SnapshotCache.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if(ssr != null) { - inhabited_ticks = ssr.inhabitedTicks; - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - else { - ss = ssr.ss; - } - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - continue; - } - // Fetch NTB for chunk if loaded - NBTTagCompound nbt = fetchLoadedChunkNBT(w, chunk.x, chunk.z); - boolean did_load = false; - if (nbt == null) { - // Load NTB for chunk, if it exists - nbt = loadChunkNBT(w, chunk.x, chunk.z); - did_load = true; - } - if (nbt != null) { - NBTSnapshot nss = new NBTSnapshot(nbt, w.getMaxHeight()); - ss = nss; - inhabited_ticks = nss.getInhabitedTicks(); - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - } - else { - ss = EMPTY; - } - ssr = new SnapshotRec(); - ssr.ss = ss; - ssr.inhabitedTicks = inhabited_ticks; - ssr.tileData = tileData; - SnapshotCache.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - if (nbt == null) - endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); - else if (did_load) - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - else - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - DynmapCore.setIgnoreChunkLoads(false); - - if(iterator.hasNext() == false) { /* If we're done */ - isempty = true; - /* Fill missing chunks with empty dummy chunk */ - for(int i = 0; i < snaparray.length; i++) { - if(snaparray[i] == null) - snaparray[i] = EMPTY; - else if(snaparray[i] != EMPTY) - isempty = false; - } - } - - return cnt; - } + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } } diff --git a/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/NBT.java b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/NBT.java new file mode 100644 index 00000000..a1cd9a34 --- /dev/null +++ b/bukkit-helper-116-3/src/main/java/org/dynmap/bukkit/helper/v116_3/NBT.java @@ -0,0 +1,127 @@ +package org.dynmap.bukkit.helper.v116_3; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import net.minecraft.server.v1_16_R2.DataBits; +import net.minecraft.server.v1_16_R2.NBTTagCompound; +import net.minecraft.server.v1_16_R2.NBTTagList; + +import java.util.Set; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final NBTTagCompound obj; + public NBTCompound(NBTTagCompound t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.getKeys(); + } + @Override + public boolean contains(String s) { + return obj.hasKey(s); + } + @Override + public boolean contains(String s, int i) { + return obj.hasKeyOfType(s, i); + } + @Override + public byte getByte(String s) { + return obj.getByte(s); + } + @Override + public short getShort(String s) { + return obj.getShort(s); + } + @Override + public int getInt(String s) { + return obj.getInt(s); + } + @Override + public long getLong(String s) { + return obj.getLong(s); + } + @Override + public float getFloat(String s) { + return obj.getFloat(s); + } + @Override + public double getDouble(String s) { + return obj.getDouble(s); + } + @Override + public String getString(String s) { + return obj.getString(s); + } + @Override + public byte[] getByteArray(String s) { + return obj.getByteArray(s); + } + @Override + public int[] getIntArray(String s) { + return obj.getIntArray(s); + } + @Override + public long[] getLongArray(String s) { + return obj.getLongArray(s); + } + @Override + public GenericNBTCompound getCompound(String s) { + return new NBTCompound(obj.getCompound(s)); + } + @Override + public GenericNBTList getList(String s, int i) { + return new NBTList(obj.getList(s, i)); + } + @Override + public boolean getBoolean(String s) { + return obj.getBoolean(s); + } + @Override + public String getAsString(String s) { + return obj.get(s).asString(); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + public String toString() { + return obj.toString(); + } + } + public static class NBTList implements GenericNBTList { + private final NBTTagList obj; + public NBTList(NBTTagList t) { + obj = t; + } + @Override + public int size() { + return obj.size(); + } + @Override + public String getString(int idx) { + return obj.getString(idx); + } + @Override + public GenericNBTCompound getCompound(int idx) { + return new NBTCompound(obj.getCompound(idx)); + } + public String toString() { + return obj.toString(); + } + } + public static class OurBitStorage implements GenericBitStorage { + private final DataBits bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new DataBits(bits, count, data); + } + @Override + public int get(int idx) { + return bs.a(idx); + } + } +} diff --git a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java index 4d413e62..8bfcb32c 100644 --- a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java +++ b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/BukkitVersionHelperSpigot116.java @@ -1,16 +1,13 @@ package org.dynmap.bukkit.helper.v116; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import org.bukkit.Bukkit; import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.World; @@ -19,16 +16,13 @@ import org.bukkit.entity.Player; import org.dynmap.DynmapChunk; import org.dynmap.Log; import org.dynmap.bukkit.helper.BukkitMaterial; -import org.dynmap.bukkit.helper.BukkitVersionHelperCB; import org.dynmap.bukkit.helper.BukkitVersionHelperGeneric; import org.dynmap.bukkit.helper.BukkitWorld; -import org.dynmap.bukkit.helper.v116.MapChunkCache116; import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.Polygon; import net.minecraft.server.v1_16_R1.BiomeBase; -import net.minecraft.server.v1_16_R1.BiomeFog; import net.minecraft.server.v1_16_R1.Block; import net.minecraft.server.v1_16_R1.BlockFluids; import net.minecraft.server.v1_16_R1.BlockRotatable; @@ -141,7 +135,7 @@ public class BukkitVersionHelperSpigot116 extends BukkitVersionHelperGeneric { */ @Override public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { - MapChunkCache116 c = new MapChunkCache116(); + MapChunkCache116 c = new MapChunkCache116(gencache); c.setChunks(dw, chunks); return c; } @@ -258,4 +252,8 @@ public class BukkitVersionHelperSpigot116 extends BukkitVersionHelperGeneric { } return null; } + @Override + public boolean useGenericCache() { + return true; + } } diff --git a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/MapChunkCache116.java b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/MapChunkCache116.java index 72430d29..0fe3abf0 100644 --- a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/MapChunkCache116.java +++ b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/MapChunkCache116.java @@ -1,495 +1,70 @@ package org.dynmap.bukkit.helper.v116; -import org.bukkit.Bukkit; -import org.bukkit.block.Biome; -import org.bukkit.craftbukkit.libs.jline.internal.Log; import org.bukkit.craftbukkit.v1_16_R1.CraftWorld; import java.io.IOException; -import java.util.Arrays; +import java.util.List; -import org.bukkit.ChunkSnapshot; import org.bukkit.World; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.bukkit.helper.AbstractMapChunkCache; -import org.dynmap.bukkit.helper.BukkitVersionHelper; -import org.dynmap.bukkit.helper.SnapshotCache; -import org.dynmap.bukkit.helper.SnapshotCache.SnapshotRec; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.utils.DynIntHashMap; -import org.dynmap.utils.VisibilityLimit; +import org.dynmap.bukkit.helper.BukkitWorld; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; import net.minecraft.server.v1_16_R1.Chunk; import net.minecraft.server.v1_16_R1.ChunkCoordIntPair; import net.minecraft.server.v1_16_R1.ChunkRegionLoader; -import net.minecraft.server.v1_16_R1.ChunkStatus; -import net.minecraft.server.v1_16_R1.DataBits; -import net.minecraft.server.v1_16_R1.DataBitsPacked; import net.minecraft.server.v1_16_R1.NBTTagCompound; -import net.minecraft.server.v1_16_R1.NBTTagList; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class MapChunkCache116 extends AbstractMapChunkCache { - - public static class NBTSnapshot implements Snapshot { - 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 Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - private final Object[] biomebase; - private final long captureFulltime; - private final int sectionCnt; - private final long inhabitedTicks; - - private static final int BLOCKS_PER_SECTION = 16 * 16 * 16; - private static final int COLUMNS_PER_CHUNK = 16 * 16; - private static final int V1_15_BIOME_PER_CHUNK = 4 * 4 * 64; - private static final byte[] emptyData = new byte[BLOCKS_PER_SECTION / 2]; - private static final byte[] fullData = new byte[BLOCKS_PER_SECTION / 2]; - - static - { - Arrays.fill(fullData, (byte)0xFF); - } - - private static byte[] dataCopy(byte[] v) { - if (Arrays.equals(v, emptyData)) - return emptyData; - else if (Arrays.equals(v, fullData)) - return fullData; - else - return v.clone(); - } - - 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 - * - * @param x - * @param z - */ - public NBTSnapshot(int worldheight, int x, int z, long captime, long inhabitedTime) - { - this.x = x; - this.z = z; - this.captureFulltime = captime; - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - this.sectionCnt = worldheight / 16; - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - - /* Create empty height map */ - this.hmap = new int[16 * 16]; - - this.inhabitedTicks = inhabitedTime; - } - - public NBTSnapshot(NBTTagCompound nbt, int worldheight) { - this.x = nbt.getInt("xPos"); - this.z = nbt.getInt("zPos"); - this.captureFulltime = 0; - this.hmap = nbt.getIntArray("HeightMap"); - this.sectionCnt = worldheight / 16; - if (nbt.hasKey("InhabitedTime")) { - this.inhabitedTicks = nbt.getLong("InhabitedTime"); - } - else { - this.inhabitedTicks = 0; - } - /* Allocate arrays indexed by section */ - this.section = new Section[this.sectionCnt+1]; - /* Fill with empty data */ - for (int i = 0; i <= this.sectionCnt; i++) { - this.section[i] = empty_section; - } - /* Get sections */ - NBTTagList sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - NBTTagCompound sec = sect.getCompound(i); - int secnum = sec.getByte("Y"); - if (secnum >= this.sectionCnt) { - //Log.info("Section " + (int) secnum + " above world height " + worldheight); - continue; - } - if (secnum < 0) - continue; - //System.out.println("section(" + secnum + ")=" + sec.asString()); - // Create normal section to initialize - StdSection cursect = new StdSection(); - this.section[secnum] = cursect; - DynmapBlockState[] states = cursect.states; - DynmapBlockState[] palette = null; - // If we've got palette and block states list, process non-empty section - if (sec.hasKeyOfType("Palette", 9) && sec.hasKeyOfType("BlockStates", 12)) { - NBTTagList plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - NBTTagCompound tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.hasKey("Properties")) { - StringBuilder statestr = new StringBuilder(); - NBTTagCompound prop = tc.getCompound("Properties"); - for (String pid : prop.getKeys()) { - if (statestr.length() > 0) statestr.append(','); - statestr.append(pid).append('=').append(prop.get(pid).asString()); - } - palette[pi] = DynmapBlockState.getStateByNameAndState(pname, statestr.toString()); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.getBaseStateByName(pname); - } - if (palette[pi] == null) { - palette[pi] = DynmapBlockState.AIR; - } - } - int recsperblock = (4096 + statelist.length - 1) / statelist.length; - int bitsperblock = 64 / recsperblock; - DataBits db = null; - DataBitsPacked dbp = null; - try { - db = new DataBits(bitsperblock, 4096, statelist); - } catch (Exception x) { // Handle legacy encoded - bitsperblock = (statelist.length * 64) / 4096; - dbp = new DataBitsPacked(bitsperblock, 4096, statelist); - } - if (bitsperblock > 8) { // Not palette - for (int j = 0; j < 4096; j++) { - int v = (db != null) ? db.a(j) : dbp.a(j); - states[j] = DynmapBlockState.getStateByGlobalIndex(v); - } - } - else { - for (int j = 0; j < 4096; j++) { - int v = (db != null) ? db.a(j) : dbp.a(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.hasKey("BlockLight")) { - cursect.emitlight = dataCopy(sec.getByteArray("BlockLight")); - } - if (sec.hasKey("SkyLight")) { - cursect.skylight = dataCopy(sec.getByteArray("SkyLight")); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - this.biomebase = new Object[COLUMNS_PER_CHUNK]; - Object[] bbl = BukkitVersionHelper.helper.getBiomeBaseList(); - if (nbt.hasKey("Biomes")) { - int[] bb = nbt.getIntArray("Biomes"); - if (bb != null) { - // If v1.15+ format - if (bb.length > COLUMNS_PER_CHUNK) { - // For now, just pad the grid with the first 16 - for (int i = 0; i < COLUMNS_PER_CHUNK; i++) { - int off = ((i >> 4) & 0xC) + ((i >> 2) & 0x3); - int bv = bb[off + 64]; // Offset to y=64 - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - else { // Else, older chunks - for (int i = 0; i < bb.length; i++) { - int bv = bb[i]; - if (bv < 0) bv = 0; - this.biome[i] = bv; - this.biomebase[i] = bbl[bv]; - } - } - } - } - } - - public int getX() - { - return x; - } - - public int getZ() - { - return z; - } - - public DynmapBlockState getBlockType(int x, int y, int z) - { - return section[y >> 4].getBlockType(x, y, z); - } - - public int getBlockSkyLight(int x, int y, int z) - { - return section[y >> 4].getBlockSkyLight(x, y, z); - } - - public int getBlockEmittedLight(int x, int y, int z) - { - return section[y >> 4].getBlockEmittedLight(x, y, z); - } - - public int getHighestBlockYAt(int x, int z) - { - return hmap[z << 4 | x]; - } - - public final long getCaptureFullTime() - { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) - { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } - - @Override - public Biome getBiome(int x, int z) { - return AbstractMapChunkCache.getBiomeByID(biome[z << 4 | x]); - } - - @Override - public Object[] getBiomeBaseFromSnapshot() { - return this.biomebase; - } +public class MapChunkCache116 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache116(GenericChunkCache cc) { + super(cc); + init(); } - - private NBTTagCompound fetchLoadedChunkNBT(World w, int x, int z) { + + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - if (cw.isChunkLoaded(x, z)) { - Chunk c = cw.getHandle().getChunkAt(x, z); + GenericChunk gc = null; + if (cw.isChunkLoaded(chunk.x, chunk.z)) { + Chunk c = cw.getHandle().getChunkAt(chunk.x, chunk.z); if ((c != null) && c.loaded) { nbt = ChunkRegionLoader.saveChunk(cw.getHandle(), c); } - } - if (nbt != null) { - nbt = nbt.getCompound("Level"); if (nbt != null) { - String stat = nbt.getString("Status"); - ChunkStatus cs = ChunkStatus.a(stat); - if ((stat == null) || (!cs.b(ChunkStatus.LIGHT))) { - nbt = null; - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } } - return nbt; - } - - private NBTTagCompound loadChunkNBT(World w, int x, int z) { + return gc; + } + + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { CraftWorld cw = (CraftWorld) w; NBTTagCompound nbt = null; - ChunkCoordIntPair cc = new ChunkCoordIntPair(x, z); + ChunkCoordIntPair cc = new ChunkCoordIntPair(chunk.x, chunk.z); + GenericChunk gc = null; try { nbt = cw.getHandle().getChunkProvider().playerChunkMap.read(cc); } catch (IOException iox) { } if (nbt != null) { - nbt = nbt.getCompound("Level"); - if (nbt != null) { - String stat = nbt.getString("Status"); - if ((stat == null) || (stat.equals("full") == false)) { - nbt = null; - if ((stat == null) || stat.equals("") && DynmapCore.migrateChunks()) { - Chunk c = cw.getHandle().getChunkAt(x, z); - if (c != null) { - nbt = fetchLoadedChunkNBT(w, x, z); - cw.getHandle().unloadChunk(c); - } - } - } - } + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); } - return nbt; - } - - @Override - public Snapshot wrapChunkSnapshot(ChunkSnapshot css) { - // TODO Auto-generated method stub - return null; - } - - // Load chunk snapshots - @Override - public int loadChunks(int max_to_load) { - if(dw.isLoaded() == false) - return 0; - int cnt = 0; - if(iterator == null) - iterator = chunks.listIterator(); + return gc; + } - DynmapCore.setIgnoreChunkLoads(true); - // Load the required chunks. - while((cnt < max_to_load) && iterator.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iterator.next(); - boolean vis = true; - if(visible_limits != null) { - vis = false; - for(VisibilityLimit limit : visible_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = true; - break; - } - } - } - if(vis && (hidden_limits != null)) { - for(VisibilityLimit limit : hidden_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = false; - break; - } - } - } - /* Check if cached chunk snapshot found */ - Snapshot ss = null; - long inhabited_ticks = 0; - DynIntHashMap tileData = null; - int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - SnapshotRec ssr = SnapshotCache.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if(ssr != null) { - inhabited_ticks = ssr.inhabitedTicks; - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - else { - ss = ssr.ss; - } - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - continue; - } - // Fetch NTB for chunk if loaded - NBTTagCompound nbt = fetchLoadedChunkNBT(w, chunk.x, chunk.z); - boolean did_load = false; - if (nbt == null) { - // Load NTB for chunk, if it exists - nbt = loadChunkNBT(w, chunk.x, chunk.z); - did_load = true; - } - if (nbt != null) { - NBTSnapshot nss = new NBTSnapshot(nbt, w.getMaxHeight()); - ss = nss; - inhabited_ticks = nss.getInhabitedTicks(); - if(!vis) { - if(hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - ss = STONE; - else if(hidestyle == HiddenChunkStyle.FILL_OCEAN) - ss = OCEAN; - else - ss = EMPTY; - } - } - else { - ss = EMPTY; - } - ssr = new SnapshotRec(); - ssr.ss = ss; - ssr.inhabitedTicks = inhabited_ticks; - ssr.tileData = tileData; - SnapshotCache.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - inhabitedTicks[idx] = inhabited_ticks; - if (nbt == null) - endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS); - else if (did_load) - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - else - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - DynmapCore.setIgnoreChunkLoads(false); - - if(iterator.hasNext() == false) { /* If we're done */ - isempty = true; - /* Fill missing chunks with empty dummy chunk */ - for(int i = 0; i < snaparray.length; i++) { - if(snaparray[i] == null) - snaparray[i] = EMPTY; - else if(snaparray[i] != EMPTY) - isempty = false; - } - } - - return cnt; - } + public void setChunks(BukkitWorld dw, List chunks) { + this.w = dw.getWorld(); + super.setChunks(dw, chunks); + } } diff --git a/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/NBT.java b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/NBT.java new file mode 100644 index 00000000..f77af495 --- /dev/null +++ b/bukkit-helper-116/src/main/java/org/dynmap/bukkit/helper/v116/NBT.java @@ -0,0 +1,127 @@ +package org.dynmap.bukkit.helper.v116; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import net.minecraft.server.v1_16_R1.DataBits; +import net.minecraft.server.v1_16_R1.NBTTagCompound; +import net.minecraft.server.v1_16_R1.NBTTagList; + +import java.util.Set; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final NBTTagCompound obj; + public NBTCompound(NBTTagCompound t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.getKeys(); + } + @Override + public boolean contains(String s) { + return obj.hasKey(s); + } + @Override + public boolean contains(String s, int i) { + return obj.hasKeyOfType(s, i); + } + @Override + public byte getByte(String s) { + return obj.getByte(s); + } + @Override + public short getShort(String s) { + return obj.getShort(s); + } + @Override + public int getInt(String s) { + return obj.getInt(s); + } + @Override + public long getLong(String s) { + return obj.getLong(s); + } + @Override + public float getFloat(String s) { + return obj.getFloat(s); + } + @Override + public double getDouble(String s) { + return obj.getDouble(s); + } + @Override + public String getString(String s) { + return obj.getString(s); + } + @Override + public byte[] getByteArray(String s) { + return obj.getByteArray(s); + } + @Override + public int[] getIntArray(String s) { + return obj.getIntArray(s); + } + @Override + public long[] getLongArray(String s) { + return obj.getLongArray(s); + } + @Override + public GenericNBTCompound getCompound(String s) { + return new NBTCompound(obj.getCompound(s)); + } + @Override + public GenericNBTList getList(String s, int i) { + return new NBTList(obj.getList(s, i)); + } + @Override + public boolean getBoolean(String s) { + return obj.getBoolean(s); + } + @Override + public String getAsString(String s) { + return obj.get(s).asString(); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + public String toString() { + return obj.toString(); + } + } + public static class NBTList implements GenericNBTList { + private final NBTTagList obj; + public NBTList(NBTTagList t) { + obj = t; + } + @Override + public int size() { + return obj.size(); + } + @Override + public String getString(int idx) { + return obj.getString(idx); + } + @Override + public GenericNBTCompound getCompound(int idx) { + return new NBTCompound(obj.getCompound(idx)); + } + public String toString() { + return obj.toString(); + } + } + public static class OurBitStorage implements GenericBitStorage { + private final DataBits bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new DataBits(bits, count, data); + } + @Override + public int get(int idx) { + return bs.a(idx); + } + } +}