diff --git a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java index 5a413682..29c4a46d 100644 --- a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java +++ b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/BukkitVersionHelperSpigot116_4.java @@ -136,7 +136,7 @@ public class BukkitVersionHelperSpigot116_4 extends BukkitVersionHelperGeneric { */ @Override public MapChunkCache getChunkCache(BukkitWorld dw, List chunks) { - MapChunkCache116_4 c = new MapChunkCache116_4(); + MapChunkCache116_4 c = new MapChunkCache116_4(gencache); c.setChunks(dw, chunks); return c; } @@ -253,4 +253,8 @@ public class BukkitVersionHelperSpigot116_4 extends BukkitVersionHelperGeneric { } return null; } + @Override + public boolean useGenericCache() { + return true; + } } diff --git a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/MapChunkCache116_4.java b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/MapChunkCache116_4.java index 06349890..8af9ac9d 100644 --- a/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/MapChunkCache116_4.java +++ b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/MapChunkCache116_4.java @@ -1,484 +1,87 @@ package org.dynmap.bukkit.helper.v116_4; import net.minecraft.server.v1_16_R3.*; -import org.bukkit.ChunkSnapshot; + import org.bukkit.World; -import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; 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 java.io.IOException; -import java.util.Arrays; +import java.util.List; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class MapChunkCache116_4 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_4 extends GenericMapChunkCache { + private World w; + /** + * Construct empty cache + */ + public MapChunkCache116_4(GenericChunkCache cc) { + super(cc); + init(); } - private NBTTagCompound fetchLoadedChunkNBT(World w, int x, int z) { + private boolean isLitChunk(NBTTagCompound nbt) { + if ((nbt != null) && nbt.hasKey("Level")) { + nbt = nbt.getCompound("Level"); + } + if (nbt != null) { + String stat = nbt.getString("Status"); + ChunkStatus cs = ChunkStatus.a(stat); + if ((stat != null) && cs.b(ChunkStatus.LIGHT)) { // ChunkStatus.LIGHT + return true; + } + } + return false; + } + + // 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 (!isLitChunk(nbt)) { + nbt = null; + } 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 (!isLitChunk(nbt)) { + nbt = null; + } 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-4/src/main/java/org/dynmap/bukkit/helper/v116_4/NBT.java b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/NBT.java new file mode 100644 index 00000000..ea6ba46b --- /dev/null +++ b/bukkit-helper-116-4/src/main/java/org/dynmap/bukkit/helper/v116_4/NBT.java @@ -0,0 +1,121 @@ +package org.dynmap.bukkit.helper.v116_4; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import net.minecraft.server.v1_16_R3.DataBits; +import net.minecraft.server.v1_16_R3.NBTTagCompound; +import net.minecraft.server.v1_16_R3.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 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 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/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/ChunkSnapshot.java b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/ChunkSnapshot.java deleted file mode 100644 index 3e2e688a..00000000 --- a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/ChunkSnapshot.java +++ /dev/null @@ -1,302 +0,0 @@ -package org.dynmap.fabric_1_16_4; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.util.collection.PackedIntegerArray; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.WordPackedArray; -import org.dynmap.Log; -import org.dynmap.renderer.DynmapBlockState; - -import java.util.Arrays; - -/** - * Represents a static, thread-safe snapshot of chunk of blocks - * Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering) - */ -public class ChunkSnapshot { - private static interface Section { - public DynmapBlockState getBlockType(int x, int y, int z); - - public int getBlockSkyLight(int x, int y, int z); - - public int getBlockEmittedLight(int x, int y, int z); - - public boolean isEmpty(); - } - - private final int x, z; - private final Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - 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 = 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 ChunkSnapshot(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.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 static class StateListException extends Exception { - private static boolean loggedOnce = false; - - public StateListException(int x, int z, int actualLength, int expectedLength, int expectedLegacyLength) { - if (Log.verbose || !loggedOnce) { - loggedOnce = true; - Log.info("Skipping chunk at x=" + x + ",z=" + z + ". Expected statelist of length " + expectedLength + " or " + expectedLegacyLength + " but got " + actualLength + ". This can happen if the chunk was not yet converted to the 1.16 format which can be fixed by visiting the chunk."); - if (!Log.verbose) { - Log.info("You will only see this message once. Turn on verbose logging in the configuration to see all messages."); - } - } - } - } - - public ChunkSnapshot(CompoundTag nbt, int worldheight) throws StateListException { - this.x = nbt.getInt("xPos"); - this.z = nbt.getInt("zPos"); - this.captureFulltime = 0; - this.hmap = nbt.getIntArray("HeightMap"); - this.sectionCnt = worldheight / 16; - if (nbt.contains("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 */ - ListTag sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - CompoundTag 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.contains("Palette", 9) && sec.contains("BlockStates", 12)) { - ListTag plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - CompoundTag tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.contains("Properties")) { - StringBuilder statestr = new StringBuilder(); - CompoundTag 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; - } - } - - PackedIntegerArray db = null; - WordPackedArray dbp = null; - - int bitsperblock = (statelist.length * 64) / 4096; - int expectedStatelistLength = (4096 + (64 / bitsperblock) - 1) / (64 / bitsperblock); - if (statelist.length == expectedStatelistLength) { - db = new PackedIntegerArray(bitsperblock, 4096, statelist); - } else { - int expectedLegacyStatelistLength = MathHelper.roundUpToMultiple(bitsperblock * 4096, 64) / 64; - if (statelist.length == expectedLegacyStatelistLength) { - dbp = new WordPackedArray(bitsperblock, 4096, statelist); - } else { - throw new StateListException(x, z, statelist.length, expectedStatelistLength, expectedLegacyStatelistLength); - } - } - - if (bitsperblock > 8) { // Not palette - for (int j = 0; j < 4096; j++) { - int v = db != null ? db.get(j) : dbp.get(j); - states[j] = DynmapBlockState.getStateByGlobalIndex(v); - } - } else { - for (int j = 0; j < 4096; j++) { - int v = db != null ? db.get(j) : dbp.get(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.contains("BlockLight")) { - cursect.emitlight = sec.getByteArray("BlockLight"); - } - if (sec.contains("SkyLight")) { - cursect.skylight = sec.getByteArray("SkyLight"); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - if (nbt.contains("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; - } - } 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; - } - } - } - } - } - - 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 int getBiome(int x, int z) { - return biome[z << 4 | x]; - } - - public final long getCaptureFullTime() { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } -} diff --git a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/DynmapPlugin.java b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/DynmapPlugin.java index 1bbc77bd..6ab02b93 100644 --- a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/DynmapPlugin.java +++ b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/DynmapPlugin.java @@ -39,6 +39,7 @@ import org.dynmap.common.BiomeMap; import org.dynmap.common.DynmapCommandSender; import org.dynmap.common.DynmapListenerManager; import org.dynmap.common.DynmapPlayer; +import org.dynmap.common.chunk.GenericChunkCache; import org.dynmap.fabric_1_16_4.command.DmapCommand; import org.dynmap.fabric_1_16_4.command.DmarkerCommand; import org.dynmap.fabric_1_16_4.command.DynmapCommand; @@ -65,7 +66,7 @@ public class DynmapPlugin { DynmapCore core; private PermissionProvider permissions; private boolean core_enabled; - public SnapshotCache sscache; + public GenericChunkCache sscache; public PlayerList playerList; MapManager mapManager; /** @@ -504,7 +505,7 @@ public class DynmapPlugin { } playerList = core.playerList; - sscache = new SnapshotCache(core.getSnapShotCacheSize(), core.useSoftRefInSnapShotCache()); + sscache = new GenericChunkCache(core.getSnapShotCacheSize(), core.useSoftRefInSnapShotCache()); /* Get map manager from core */ mapManager = core.getMapManager(); diff --git a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/FabricMapChunkCache.java b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/FabricMapChunkCache.java index e7f7f84b..09ee2ebc 100644 --- a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/FabricMapChunkCache.java +++ b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/FabricMapChunkCache.java @@ -5,824 +5,32 @@ import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ThreadedAnvilChunkStorage; import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.registry.Registry; import net.minecraft.world.ChunkSerializer; import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.ChunkManager; import net.minecraft.world.chunk.ChunkStatus; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.DynmapWorld; import org.dynmap.Log; -import org.dynmap.common.BiomeMap; -import org.dynmap.hdmap.HDBlockModels; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.renderer.RenderPatchFactory; -import org.dynmap.utils.*; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericMapChunkCache; -import java.lang.reflect.Field; import java.util.*; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class FabricMapChunkCache extends MapChunkCache { - private final DynmapPlugin plugin; - - private static boolean init = false; - private static Field updateEntityTick = null; - /* ChunkManager fields */ - private static Field chunksToRemove = null; // Map - - /* ChunjManager Pending fields */ - private static Field chunkCoord = null; - private static Field nbtTag = null; - +public class FabricMapChunkCache extends GenericMapChunkCache { private World w; - private DynmapWorld dw; private ServerChunkManager cps; - private int nsect; - private List chunks; - private ListIterator iterator; - private int x_min, x_max, z_min, z_max; - private int x_dim; - private boolean biome, biomeraw, highesty, blockdata; - private HiddenChunkStyle hidestyle = HiddenChunkStyle.FILL_AIR; - private List visible_limits = null; - private List hidden_limits = null; - private boolean isempty = true; - private int snapcnt; - private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ - private DynIntHashMap[] snaptile; - private byte[][] sameneighborbiomecnt; - private BiomeMap[][] biomemap; - private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */ - - - private static final BlockStep unstep[] = {BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS, - BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS - }; - - private BiomeMap[] biome_to_bmap; - - private static final int getIndexInChunk(int cx, int cy, int cz) { - return (cy << 8) | (cz << 4) | cx; - } /** * Construct empty cache */ public FabricMapChunkCache(DynmapPlugin plugin) { - this.plugin = plugin; - - Registry biomeRegistry = plugin.getFabricServer().getBiomeRegistry(); - Biome b[] = plugin.getFabricServer().getBiomeList(biomeRegistry); - BiomeMap[] bm = BiomeMap.values(); - biome_to_bmap = new BiomeMap[256]; - - for (int i = 0; i < biome_to_bmap.length; i++) { - biome_to_bmap[i] = BiomeMap.NULL; - } - - for (int i = 0; i < b.length; i++) { - if (b[i] == null) continue; - - //FIXME: This probably not correct. In 1.16.1 it was: b[i].getTranslationKey(); - String bs = biomeRegistry.getId(b[i]).toString(); - - for (int j = 0; j < bm.length; j++) { - if (bm[j].toString().equals(bs)) { - biome_to_bmap[i] = bm[j]; - break; - } - } - } - - init(); - } - - /** - * Iterator for traversing map chunk cache (base is for non-snapshot) - */ - public class OurMapIterator implements MapIterator { - private int x, y, z, chunkindex, bx, bz; - private ChunkSnapshot snap; - private BlockStep laststep; - private DynmapBlockState blk; - private final int worldheight; - private final int x_base; - private final int z_base; - - OurMapIterator(int x0, int y0, int z0) { - x_base = x_min << 4; - z_base = z_min << 4; - - if (biome) { - biomePrep(); - } - - initialize(x0, y0, z0); - worldheight = w.getHeight(); - } - - @Override - public final void initialize(int x0, int y0, int z0) { - this.x = x0; - this.y = y0; - this.z = z0; - this.chunkindex = ((x >> 4) - x_min) + (((z >> 4) - z_min) * x_dim); - this.bx = x & 0xF; - this.bz = z & 0xF; - - if ((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } else { - snap = snaparray[chunkindex]; - } - - laststep = BlockStep.Y_MINUS; - - if ((y >= 0) && (y < worldheight)) { - blk = null; - } else { - blk = DynmapBlockState.AIR; - } - } - - @Override - public int getBlockSkyLight() { - try { - return snap.getBlockSkyLight(bx, y, bz); - } catch (ArrayIndexOutOfBoundsException aioobx) { - return 15; - } - } - - @Override - public final int getBlockEmittedLight() { - try { - return snap.getBlockEmittedLight(bx, y, bz); - } catch (ArrayIndexOutOfBoundsException aioobx) { - return 0; - } - } - - private void biomePrep() { - if (sameneighborbiomecnt != null) { - return; - } - - int x_size = x_dim << 4; - int z_size = (z_max - z_min + 1) << 4; - sameneighborbiomecnt = new byte[x_size][]; - biomemap = new BiomeMap[x_size][]; - - for (int i = 0; i < x_size; i++) { - sameneighborbiomecnt[i] = new byte[z_size]; - biomemap[i] = new BiomeMap[z_size]; - } - - for (int i = 0; i < x_size; i++) { - for (int j = 0; j < z_size; j++) { - if (j == 0) - initialize(i + x_base, 64, z_base); - else - stepPosition(BlockStep.Z_PLUS); - - int bb = snap.getBiome(bx, bz); - BiomeMap bm = BiomeMap.byBiomeID(bb); - - biomemap[i][j] = bm; - int cnt = 0; - - if (i > 0) { - if (bm == biomemap[i - 1][j]) /* Same as one to left */ { - cnt++; - sameneighborbiomecnt[i - 1][j]++; - } - - if ((j > 0) && (bm == biomemap[i - 1][j - 1])) { - cnt++; - sameneighborbiomecnt[i - 1][j - 1]++; - } - - if ((j < (z_size - 1)) && (bm == biomemap[i - 1][j + 1])) { - cnt++; - sameneighborbiomecnt[i - 1][j + 1]++; - } - } - - if ((j > 0) && (biomemap[i][j] == biomemap[i][j - 1])) /* Same as one to above */ { - cnt++; - sameneighborbiomecnt[i][j - 1]++; - } - - sameneighborbiomecnt[i][j] = (byte) cnt; - } - } - } - - @Override - public final BiomeMap getBiome() { - try { - return biomemap[x - x_base][z - z_base]; - } catch (Exception ex) { - return BiomeMap.NULL; - } - } - - @Override - public final int getSmoothGrassColorMultiplier(int[] colormap) { - int mult = 0xFFFFFF; - - try { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte) 8) /* All neighbors same? */ { - mult = bm.getModifiedGrassMultiplier(colormap[bm.biomeLookup()]); - } else { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) { - for (int zoff = -1; zoff < 2; zoff++) { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult = bm.getModifiedGrassMultiplier(colormap[bm.biomeLookup()]); - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } catch (Exception x) { - mult = 0xFFFFFF; - } - - return mult; - } - - @Override - public final int getSmoothFoliageColorMultiplier(int[] colormap) { - int mult = 0xFFFFFF; - - try { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte) 8) /* All neighbors same? */ { - mult = bm.getModifiedFoliageMultiplier(colormap[bm.biomeLookup()]); - } else { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) { - for (int zoff = -1; zoff < 2; zoff++) { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult = bm.getModifiedFoliageMultiplier(colormap[bm.biomeLookup()]); - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } catch (Exception x) { - mult = 0xFFFFFF; - } - - return mult; - } - - @Override - public final int getSmoothColorMultiplier(int[] colormap, int[] swampmap) { - int mult = 0xFFFFFF; - - try { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte) 8) /* All neighbors same? */ { - if (bm == BiomeMap.SWAMPLAND) { - mult = swampmap[bm.biomeLookup()]; - } else { - mult = colormap[bm.biomeLookup()]; - } - } else { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) { - for (int zoff = -1; zoff < 2; zoff++) { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult; - - if (bm == BiomeMap.SWAMPLAND) { - rmult = swampmap[bm.biomeLookup()]; - } else { - rmult = colormap[bm.biomeLookup()]; - } - - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } catch (Exception x) { - mult = 0xFFFFFF; - } - - return mult; - } - - @Override - public final int getSmoothWaterColorMultiplier() { - try { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte) 8) /* All neighbors same? */ { - return bm.getWaterColorMult(); - } - - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) { - for (int zoff = -1; zoff < 2; zoff++) { - bm = biomemap[rx + xoff][rz + zoff]; - int mult = bm.getWaterColorMult(); - raccum += (mult >> 16) & 0xFF; - gaccum += (mult >> 8) & 0xFF; - baccum += mult & 0xFF; - } - } - - return ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } catch (Exception x) { - return 0xFFFFFF; - } - } - - @Override - public final int getSmoothWaterColorMultiplier(int[] colormap) { - int mult = 0xFFFFFF; - - try { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte) 8) /* All neighbors same? */ { - mult = colormap[bm.biomeLookup()]; - } else { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) { - for (int zoff = -1; zoff < 2; zoff++) { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult = colormap[bm.biomeLookup()]; - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } catch (Exception x) { - mult = 0xFFFFFF; - } - - return mult; - } - - /** - * Step current position in given direction - */ - @Override - public final void stepPosition(BlockStep step) { - blk = null; - - switch (step.ordinal()) { - case 0: - x++; - bx++; - - if (bx == 16) /* Next chunk? */ { - bx = 0; - chunkindex++; - if ((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } else { - snap = snaparray[chunkindex]; - } - } - - break; - - case 1: - y++; - - if (y >= worldheight) { - blk = DynmapBlockState.AIR; - } - - break; - - case 2: - z++; - bz++; - - if (bz == 16) /* Next chunk? */ { - bz = 0; - chunkindex += x_dim; - if ((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } else { - snap = snaparray[chunkindex]; - } - } - break; - - case 3: - x--; - bx--; - - if (bx == -1) /* Next chunk? */ { - bx = 15; - chunkindex--; - if ((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } else { - snap = snaparray[chunkindex]; - } - } - - break; - - case 4: - y--; - - if (y < 0) { - blk = DynmapBlockState.AIR; - } - - break; - - case 5: - z--; - bz--; - - if (bz == -1) /* Next chunk? */ { - bz = 15; - chunkindex -= x_dim; - if ((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } else { - snap = snaparray[chunkindex]; - } - } - break; - } - - laststep = step; - } - - /** - * Unstep current position to previous position - */ - @Override - public BlockStep unstepPosition() { - BlockStep ls = laststep; - stepPosition(unstep[ls.ordinal()]); - return ls; - } - - /** - * Unstep current position in oppisite director of given step - */ - @Override - public void unstepPosition(BlockStep s) { - stepPosition(unstep[s.ordinal()]); - } - - @Override - public final void setY(int y) { - if (y > this.y) { - laststep = BlockStep.Y_PLUS; - } else { - laststep = BlockStep.Y_MINUS; - } - - this.y = y; - - if ((y < 0) || (y >= worldheight)) { - blk = DynmapBlockState.AIR; - } else { - blk = null; - } - } - - @Override - public final int getX() { - return x; - } - - @Override - public final int getY() { - return y; - } - - @Override - public final int getZ() { - return z; - } - - @Override - public final DynmapBlockState getBlockTypeAt(BlockStep s) { - if (s == BlockStep.Y_MINUS) { - if (y > 0) { - return snap.getBlockType(bx, y - 1, bz); - } - } else if (s == BlockStep.Y_PLUS) { - if (y < (worldheight - 1)) { - return snap.getBlockType(bx, y + 1, bz); - } - } else { - BlockStep ls = laststep; - stepPosition(s); - DynmapBlockState tid = snap.getBlockType(bx, y, bz); - unstepPosition(); - laststep = ls; - return tid; - } - - return DynmapBlockState.AIR; - } - - @Override - public BlockStep getLastStep() { - return laststep; - } - - @Override - public int getWorldHeight() { - return worldheight; - } - - @Override - public long getBlockKey() { - return (((chunkindex * worldheight) + y) << 8) | (bx << 4) | bz; - } - - @Override - public final boolean isEmptySection() { - try { - return !isSectionNotEmpty[chunkindex][y >> 4]; - } catch (Exception x) { - initSectionData(chunkindex); - return !isSectionNotEmpty[chunkindex][y >> 4]; - } - } - - @Override - public RenderPatchFactory getPatchFactory() { - return HDBlockModels.getPatchDefinitionFactory(); - } - - @Override - public Object getBlockTileEntityField(String fieldId) { - try { - int idx = getIndexInChunk(bx, y, bz); - Object[] vals = (Object[]) snaptile[chunkindex].get(idx); - for (int i = 0; i < vals.length; i += 2) { - if (vals[i].equals(fieldId)) { - return vals[i + 1]; - } - } - } catch (Exception x) { - } - return null; - } - - @Override - public DynmapBlockState getBlockTypeAt(int xoff, int yoff, int zoff) { - int xx = this.x + xoff; - int yy = this.y + yoff; - int zz = this.z + zoff; - int idx = ((xx >> 4) - x_min) + (((zz >> 4) - z_min) * x_dim); - try { - return snaparray[idx].getBlockType(xx & 0xF, yy, zz & 0xF); - } catch (Exception x) { - return DynmapBlockState.AIR; - } - } - - @Override - public Object getBlockTileEntityFieldAt(String fieldId, int xoff, - int yoff, int zoff) { - return null; - } - - @Override - public long getInhabitedTicks() { - try { - return snap.getInhabitedTicks(); - } catch (Exception x) { - return 0; - } - } - - @Override - public DynmapBlockState getBlockType() { - if (blk == null) { - blk = snap.getBlockType(bx, y, bz); - } - return blk; - } - } - - private class OurEndMapIterator extends OurMapIterator { - OurEndMapIterator(int x0, int y0, int z0) { - super(x0, y0, z0); - } - - @Override - public final int getBlockSkyLight() { - return 15; - } - } - - /** - * Chunk cache for representing unloaded chunk (or air) - */ - private static class EmptyChunk extends ChunkSnapshot { - public EmptyChunk() { - super(256, 0, 0, 0, 0); - } - - /* Need these for interface, but not used */ - @Override - public int getX() { - return 0; - } - - @Override - public int getZ() { - return 0; - } - - @Override - public final DynmapBlockState getBlockType(int x, int y, int z) { - return DynmapBlockState.AIR; - } - - @Override - public final int getBlockSkyLight(int x, int y, int z) { - return 15; - } - - @Override - public final int getBlockEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public final int getHighestBlockYAt(int x, int z) { - return 0; - } - - @Override - public int getBiome(int x, int z) { - return -1; - } - - @Override - public boolean isSectionEmpty(int sy) { - return true; - } - } - - /** - * Chunk cache for representing generic stone chunk - */ - private static class PlainChunk extends ChunkSnapshot { - private DynmapBlockState fill; - - PlainChunk(String fill) { - super(256, 0, 0, 0, 0); - this.fill = DynmapBlockState.getBaseStateByName(fill); - } - - /* Need these for interface, but not used */ - @Override - public int getX() { - return 0; - } - - @Override - public int getZ() { - return 0; - } - - @Override - public int getBiome(int x, int z) { - return -1; - } - - @Override - public final DynmapBlockState getBlockType(int x, int y, int z) { - if (y < 64) { - return fill; - } - - return DynmapBlockState.AIR; - } - - @Override - public final int getBlockSkyLight(int x, int y, int z) { - if (y < 64) { - return 0; - } - - return 15; - } - - @Override - public final int getBlockEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public final int getHighestBlockYAt(int x, int z) { - return 64; - } - - @Override - public boolean isSectionEmpty(int sy) { - return (sy < 4); - } - } - - private static final EmptyChunk EMPTY = new EmptyChunk(); - private static final PlainChunk STONE = new PlainChunk(DynmapBlockState.STONE_BLOCK); - private static final PlainChunk OCEAN = new PlainChunk(DynmapBlockState.WATER_BLOCK); - - - public static void init() { - if (!init) { - Field[] f = ServerChunkManager.class.getDeclaredFields(); - - f = ServerWorld.class.getDeclaredFields(); - for (int i = 0; i < f.length; i++) { - if ((updateEntityTick == null) && f[i].getType().isAssignableFrom(int.class)) { - updateEntityTick = f[i]; - //Log.info("Found updateEntityTick - " + f[i].getName()); - updateEntityTick.setAccessible(true); - } - } - - f = ChunkManager.class.getDeclaredFields(); - for (int i = 0; i < f.length; i++) { - if ((chunksToRemove == null) && (f[i].getType().equals(Map.class))) { - chunksToRemove = f[i]; - //Log.info("Found chunksToRemove - " + f[i].getName()); - chunksToRemove.setAccessible(true); - } -// else if((pendingAnvilChunksCoordinates == null) && (f[i].getType().equals(it.unimi.dsi.fastutil.longs.LongSet.class))) { -// //Log.info("Found pendingAnvilChunksCoordinates - " + f[i].getName()); -// pendingAnvilChunksCoordinates = f[i]; -// pendingAnvilChunksCoordinates.setAccessible(true); -// } - } - if (updateEntityTick == null) { - Log.severe("ERROR: cannot find updateEntityTick - dynmap cannot drive entity cleanup when no players are active"); - } - - init = true; - } + super(plugin.sscache); } public void setChunks(FabricWorld dw, List chunks) { - this.dw = dw; this.w = dw.getWorld(); if (dw.isLoaded()) { /* Check if world's provider is ServerChunkManager */ @@ -833,71 +41,19 @@ public class FabricMapChunkCache extends MapChunkCache { } else { Log.severe("Error: world " + dw.getName() + " has unsupported chunk provider"); } - } else { - chunks = new ArrayList(); - } - nsect = dw.worldheight >> 4; - this.chunks = chunks; - - /* Compute range */ - if (chunks.size() == 0) { - this.x_min = 0; - this.x_max = 0; - this.z_min = 0; - this.z_max = 0; - x_dim = 1; - } else { - x_min = x_max = chunks.get(0).x; - z_min = z_max = chunks.get(0).z; - - for (DynmapChunk c : chunks) { - if (c.x > x_max) { - x_max = c.x; - } - - if (c.x < x_min) { - x_min = c.x; - } - - if (c.z > z_max) { - z_max = c.z; - } - - if (c.z < z_min) { - z_min = c.z; - } - } - - x_dim = x_max - x_min + 1; - } - - snapcnt = x_dim * (z_max - z_min + 1); - snaparray = new ChunkSnapshot[snapcnt]; - snaptile = new DynIntHashMap[snapcnt]; - isSectionNotEmpty = new boolean[snapcnt][]; - + } + super.setChunks(dw, chunks); } - private static boolean didError = false; - - public CompoundTag readChunk(int x, int z) { + private CompoundTag readChunk(int x, int z) { try { ThreadedAnvilChunkStorage acl = cps.threadedAnvilChunkStorage; ChunkPos coord = new ChunkPos(x, z); CompoundTag rslt = acl.getNbt(coord); - if (rslt != null) { - rslt = rslt.getCompound("Level"); - // Don't load uncooked chunks - String stat = rslt.getString("Status"); - ChunkStatus cs = ChunkStatus.byId(stat); - if ((stat == null) || - // Needs to be at least lighted - (!cs.isAtLeast(ChunkStatus.LIGHT))) { - rslt = null; - } + if (!isLitChunk(rslt)) { + rslt = null; } - //Log.info(String.format("loadChunk(%d,%d)=%s", x, z, (rslt != null) ? rslt.toString() : "null")); return rslt; } catch (Exception exc) { Log.severe(String.format("Error reading chunk: %s,%d,%d", dw.getName(), x, z), exc); @@ -905,430 +61,47 @@ public class FabricMapChunkCache extends MapChunkCache { } } - private Object getNBTValue(Tag v) { - Object val = null; - switch (v.getType()) { - case 1: // Byte - val = ((ByteTag) v).getByte(); - break; - case 2: // Short - val = ((ShortTag) v).getShort(); - break; - case 3: // Int - val = ((IntTag) v).getInt(); - break; - case 4: // Long - val = ((LongTag) v).getLong(); - break; - case 5: // Float - val = ((FloatTag) v).getFloat(); - break; - case 6: // Double - val = ((DoubleTag) v).getDouble(); - break; - case 7: // Byte[] - val = ((ByteArrayTag) v).getByteArray(); - break; - case 8: // String - val = ((StringTag) v).asString(); - break; - case 9: // List - ListTag tl = (ListTag) v; - ArrayList vlist = new ArrayList(); - int type = tl.getElementType(); - for (int i = 0; i < tl.size(); i++) { - switch (type) { - case 5: - float fv = tl.getFloat(i); - vlist.add(fv); - break; - case 6: - double dv = tl.getDouble(i); - vlist.add(dv); - break; - case 8: - String sv = tl.getString(i); - vlist.add(sv); - break; - case 10: - CompoundTag tc = tl.getCompound(i); - vlist.add(getNBTValue(tc)); - break; - case 11: - int[] ia = tl.getIntArray(i); - vlist.add(ia); - break; - } - } - val = vlist; - break; - case 10: // Map - CompoundTag tc = (CompoundTag) v; - HashMap vmap = new HashMap(); - for (Object t : tc.getKeys()) { - String st = (String) t; - Tag tg = tc.get(st); - vmap.put(st, getNBTValue(tg)); - } - val = vmap; - break; - case 11: // Int[] - val = ((IntArrayTag) v).getIntArray(); - break; - } - return val; - } - - private boolean isChunkVisible(DynmapChunk chunk) { - boolean vis = true; - if (visible_limits != null) { - vis = false; - for (VisibilityLimit limit : visible_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = true; - break; - } + private boolean isLitChunk(CompoundTag nbt) { + if ((nbt != null) && nbt.contains("Level")) { + nbt = nbt.getCompound("Level"); + } + if (nbt != null) { + String stat = nbt.getString("Status"); + ChunkStatus cs = ChunkStatus.byId(stat); + if ((stat != null) && cs.isAtLeast(ChunkStatus.LIGHT)) { // ChunkStatus.LIGHT + return true; } } - if (vis && (hidden_limits != null)) { - for (VisibilityLimit limit : hidden_limits) { - if (limit.doIntersectChunk(chunk.x, chunk.z)) { - vis = false; - break; - } - } - } - return vis; - } - - private boolean tryChunkCache(DynmapChunk chunk, boolean vis) { - /* Check if cached chunk snapshot found */ - ChunkSnapshot ss = null; - SnapshotCache.SnapshotRec ssr = DynmapPlugin.plugin.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if (ssr != null) { - ss = ssr.ss; - if (!vis) { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { - ss = STONE; - } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { - ss = OCEAN; - } else { - ss = EMPTY; - } - } - int idx = (chunk.x - x_min) + (chunk.z - z_min) * x_dim; - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - } - return (ssr != null); - } - - // Prep snapshot and add to cache - private SnapshotCache.SnapshotRec prepChunkSnapshot(DynmapChunk chunk, CompoundTag nbt) throws ChunkSnapshot.StateListException { - ChunkSnapshot ss = new ChunkSnapshot(nbt, dw.worldheight); - DynIntHashMap tileData = new DynIntHashMap(); - - ListTag tiles = nbt.getList("TileEntities", 10); - if (tiles == null) tiles = new ListTag(); - /* Get tile entity data */ - List vals = new ArrayList(); - for (int tid = 0; tid < tiles.size(); tid++) { - CompoundTag tc = tiles.getCompound(tid); - int tx = tc.getInt("x"); - int ty = tc.getInt("y"); - int tz = tc.getInt("z"); - int cx = tx & 0xF; - int cz = tz & 0xF; - DynmapBlockState blk = ss.getBlockType(cx, ty, cz); - String[] te_fields = HDBlockModels.getTileEntityFieldsNeeded(blk); - if (te_fields != null) { - vals.clear(); - for (String id : te_fields) { - Tag v = tc.get(id); /* Get field */ - if (v != null) { - Object val = getNBTValue(v); - if (val != null) { - vals.add(id); - vals.add(val); - } - } - } - if (vals.size() > 0) { - Object[] vlist = vals.toArray(new Object[vals.size()]); - tileData.put(getIndexInChunk(cx, ty, cz), vlist); - } - } - } - SnapshotCache.SnapshotRec ssr = new SnapshotCache.SnapshotRec(); - ssr.ss = ss; - ssr.tileData = tileData; - DynmapPlugin.plugin.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - - return ssr; - } - - /** - * Read NBT data from loaded chunks - needs to be called from server/world thread to be safe - * - * @returns number loaded - */ - public int getLoadedChunks() { - int cnt = 0; - if (!dw.isLoaded()) { - isempty = true; - unloadChunks(); - return 0; - } - ListIterator iter = chunks.listIterator(); - while (iter.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iter.next(); - int chunkindex = (chunk.x - x_min) + (chunk.z - z_min) * x_dim; - if (snaparray[chunkindex] != null) continue; // Skip if already processed - - boolean vis = isChunkVisible(chunk); - - /* Check if cached chunk snapshot found */ - if (tryChunkCache(chunk, vis)) { - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - cnt++; - } - // If chunk is loaded and not being unloaded, we're grabbing its NBT data - else if (cps.isChunkLoaded(chunk.x, chunk.z)) { - ChunkSnapshot ss; - DynIntHashMap tileData; - if (vis) { // If visible - CompoundTag nbt = null; - try { - nbt = ChunkSerializer.serialize((ServerWorld) w, cps.getWorldChunk(chunk.x, chunk.z, false)); - } catch (NullPointerException e) { - // TODO: find out why this is happening and why it only seems to happen since 1.16.2 - Log.severe("ChunkSerializer.serialize threw a NullPointerException", e); - continue; - } - if (nbt != null) nbt = nbt.getCompound("Level"); - try { - SnapshotCache.SnapshotRec ssr = prepChunkSnapshot(chunk, nbt); - ss = ssr.ss; - tileData = ssr.tileData; - } catch (ChunkSnapshot.StateListException e) { - continue; - } - } else { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { - ss = STONE; - } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { - ss = OCEAN; - } else { - ss = EMPTY; - } - tileData = new DynIntHashMap(); - } - snaparray[chunkindex] = ss; - snaptile[chunkindex] = tileData; - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - } - return cnt; - } - - @Override - public int loadChunks(int max_to_load) { - return getLoadedChunks() + readChunks(max_to_load); - - } - - public int readChunks(int max_to_load) { - if (!dw.isLoaded()) { - isempty = true; - unloadChunks(); - return 0; - } - - int cnt = 0; - - if (iterator == null) { - iterator = chunks.listIterator(); - } - - DynmapCore.setIgnoreChunkLoads(true); - - // Load the required chunks. - while ((cnt < max_to_load) && iterator.hasNext()) { - long startTime = System.nanoTime(); - - DynmapChunk chunk = iterator.next(); - - int chunkindex = (chunk.x - x_min) + (chunk.z - z_min) * x_dim; - - if (snaparray[chunkindex] != null) continue; // Skip if already processed - - boolean vis = isChunkVisible(chunk); - - /* Check if cached chunk snapshot found */ - if (tryChunkCache(chunk, vis)) { - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - } else { - CompoundTag nbt = readChunk(chunk.x, chunk.z); - // If read was good - if (nbt != null) { - ChunkSnapshot ss; - DynIntHashMap tileData; - // If hidden - if (!vis) { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { - ss = STONE; - } else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { - ss = OCEAN; - } else { - ss = EMPTY; - } - tileData = new DynIntHashMap(); - } else { - // Prep snapshot - try { - SnapshotCache.SnapshotRec ssr = prepChunkSnapshot(chunk, nbt); - ss = ssr.ss; - tileData = ssr.tileData; - } catch (ChunkSnapshot.StateListException e) { - continue; - } - } - snaparray[chunkindex] = ss; - snaptile[chunkindex] = tileData; - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - } else { - endChunkLoad(startTime, ChunkStats.UNGENERATED_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; - } - - /** - * Test if done loading - */ - public boolean isDoneLoading() { - if (!dw.isLoaded()) { - return true; - } - if (iterator != null) { - return !iterator.hasNext(); - } - return false; - } + } - /** - * Test if all empty blocks - */ - public boolean isEmpty() { - return isempty; - } - - /** - * Unload chunks - */ - public void unloadChunks() { - if (snaparray != null) { - for (int i = 0; i < snaparray.length; i++) { - snaparray[i] = null; + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { + GenericChunk gc = null; + if (cps.isChunkLoaded(chunk.x, chunk.z)) { + CompoundTag nbt = null; + try { + nbt = ChunkSerializer.serialize((ServerWorld) w, cps.getWorldChunk(chunk.x, chunk.z, false)); + } catch (NullPointerException e) { + // TODO: find out why this is happening and why it only seems to happen since 1.16.2 + Log.severe("ChunkSerializer.serialize threw a NullPointerException", e); } - - snaparray = null; - } - } - - private void initSectionData(int idx) { - isSectionNotEmpty[idx] = new boolean[nsect + 1]; - - if (snaparray[idx] != EMPTY) { - for (int i = 0; i < nsect; i++) { - if (snaparray[idx].isSectionEmpty(i) == false) { - isSectionNotEmpty[idx][i] = true; - } - } - } - } - - public boolean isEmptySection(int sx, int sy, int sz) { - int idx = (sx - x_min) + (sz - z_min) * x_dim; - - if (isSectionNotEmpty[idx] == null) { - initSectionData(idx); - } - - return !isSectionNotEmpty[idx][sy]; - } - - /** - * Get cache iterator - */ - public MapIterator getIterator(int x, int y, int z) { - if (dw.getEnvironment().equals("the_end")) { - return new OurEndMapIterator(x, y, z); - } - - return new OurMapIterator(x, y, z); - } - - /** - * Set hidden chunk style (default is FILL_AIR) - */ - public void setHiddenFillStyle(HiddenChunkStyle style) { - this.hidestyle = style; - } - - /** - * Add visible area limit - can be called more than once - * Needs to be set before chunks are loaded - * Coordinates are block coordinates - */ - public void setVisibleRange(VisibilityLimit lim) { - if (visible_limits == null) - visible_limits = new ArrayList(); - visible_limits.add(lim); - } - - /** - * Add hidden area limit - can be called more than once - * Needs to be set before chunks are loaded - * Coordinates are block coordinates - */ - public void setHiddenRange(VisibilityLimit lim) { - if (hidden_limits == null) - hidden_limits = new ArrayList(); - hidden_limits.add(lim); - } - - @Override - public boolean setChunkDataTypes(boolean blockdata, boolean biome, boolean highestblocky, boolean rawbiome) { - this.biome = biome; - this.biomeraw = rawbiome; - this.highesty = highestblocky; - this.blockdata = blockdata; - return true; - } - - @Override - public DynmapWorld getWorld() { - return dw; - } + if (isLitChunk(nbt)) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + } + return gc; + } + + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { + GenericChunk gc = null; + CompoundTag nbt = readChunk(chunk.x, chunk.z); + // If read was good + if (isLitChunk(nbt)) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + return gc; + } } + diff --git a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/NBT.java b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/NBT.java new file mode 100644 index 00000000..eddcf988 --- /dev/null +++ b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/NBT.java @@ -0,0 +1,120 @@ +package org.dynmap.fabric_1_16_4; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import java.util.Set; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.util.collection.PackedIntegerArray; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final CompoundTag obj; + public NBTCompound(CompoundTag t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.getKeys(); + } + @Override + public boolean contains(String s) { + return obj.contains(s); + } + @Override + public boolean contains(String s, int i) { + return obj.contains(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 static class NBTList implements GenericNBTList { + private final ListTag obj; + public NBTList(ListTag 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 static class OurBitStorage implements GenericBitStorage { + private final PackedIntegerArray bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new PackedIntegerArray(bits, count, data); + } + @Override + public int get(int idx) { + return bs.get(idx); + } + } +} diff --git a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/SnapshotCache.java b/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/SnapshotCache.java deleted file mode 100644 index a8376d8c..00000000 --- a/fabric-1.16.4/src/main/java/org/dynmap/fabric_1_16_4/SnapshotCache.java +++ /dev/null @@ -1,201 +0,0 @@ -package org.dynmap.fabric_1_16_4; - -import org.dynmap.utils.DynIntHashMap; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.util.IdentityHashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -public class SnapshotCache { - public static class SnapshotRec { - public ChunkSnapshot ss; - public DynIntHashMap tileData; - } - - private CacheHashMap snapcache; - private ReferenceQueue refqueue; - private long cache_attempts; - private long cache_success; - private boolean softref; - - private static class CacheRec { - Reference ref; - boolean hasbiome; - boolean hasrawbiome; - boolean hasblockdata; - boolean hashighesty; - } - - @SuppressWarnings("serial") - public class CacheHashMap extends LinkedHashMap { - private int limit; - private IdentityHashMap, String> reverselookup; - - public CacheHashMap(int lim) { - super(16, (float) 0.75, true); - limit = lim; - reverselookup = new IdentityHashMap, String>(); - } - - protected boolean removeEldestEntry(Map.Entry last) { - boolean remove = (size() >= limit); - if (remove && (last != null) && (last.getValue() != null)) { - reverselookup.remove(last.getValue().ref); - } - return remove; - } - } - - /** - * Create snapshot cache - */ - public SnapshotCache(int max_size, boolean softref) { - snapcache = new CacheHashMap(max_size); - refqueue = new ReferenceQueue(); - this.softref = softref; - } - - private String getKey(String w, int cx, int cz) { - return w + ":" + cx + ":" + cz; - } - - /** - * Invalidate cached snapshot, if in cache - */ - public void invalidateSnapshot(String w, int x, int y, int z) { - String key = getKey(w, x >> 4, z >> 4); - synchronized (snapcache) { - CacheRec rec = snapcache.remove(key); - if (rec != null) { - snapcache.reverselookup.remove(rec.ref); - rec.ref.clear(); - } - } - //processRefQueue(); - } - - /** - * Invalidate cached snapshot, if in cache - */ - public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1, int z1) { - for (int xx = (x0 >> 4); xx <= (x1 >> 4); xx++) { - for (int zz = (z0 >> 4); zz <= (z1 >> 4); zz++) { - String key = getKey(w, xx, zz); - synchronized (snapcache) { - CacheRec rec = snapcache.remove(key); - if (rec != null) { - snapcache.reverselookup.remove(rec.ref); - rec.ref.clear(); - } - } - } - } - //processRefQueue(); - } - - /** - * Look for chunk snapshot in cache - */ - public SnapshotRec getSnapshot(String w, int chunkx, int chunkz, - boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) { - String key = getKey(w, chunkx, chunkz); - processRefQueue(); - SnapshotRec ss = null; - CacheRec rec; - synchronized (snapcache) { - rec = snapcache.get(key); - if (rec != null) { - ss = rec.ref.get(); - if (ss == null) { - snapcache.reverselookup.remove(rec.ref); - snapcache.remove(key); - } - } - } - if (ss != null) { - if ((blockdata && (!rec.hasblockdata)) || - (biome && (!rec.hasbiome)) || - (biomeraw && (!rec.hasrawbiome)) || - (highesty && (!rec.hashighesty))) { - ss = null; - } - } - cache_attempts++; - if (ss != null) cache_success++; - - return ss; - } - - /** - * Add chunk snapshot to cache - */ - public void putSnapshot(String w, int chunkx, int chunkz, SnapshotRec ss, - boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) { - String key = getKey(w, chunkx, chunkz); - processRefQueue(); - CacheRec rec = new CacheRec(); - rec.hasblockdata = blockdata; - rec.hasbiome = biome; - rec.hasrawbiome = biomeraw; - rec.hashighesty = highesty; - if (softref) - rec.ref = new SoftReference(ss, refqueue); - else - rec.ref = new WeakReference(ss, refqueue); - synchronized (snapcache) { - CacheRec prevrec = snapcache.put(key, rec); - if (prevrec != null) { - snapcache.reverselookup.remove(prevrec.ref); - } - snapcache.reverselookup.put(rec.ref, key); - } - } - - /** - * Process reference queue - */ - private void processRefQueue() { - Reference ref; - while ((ref = refqueue.poll()) != null) { - synchronized (snapcache) { - String k = snapcache.reverselookup.remove(ref); - if (k != null) { - snapcache.remove(k); - } - } - } - } - - /** - * Get hit rate (percent) - */ - public double getHitRate() { - if (cache_attempts > 0) { - return (100.0 * cache_success) / (double) cache_attempts; - } - return 0.0; - } - - /** - * Reset cache stats - */ - public void resetStats() { - cache_attempts = cache_success = 0; - } - - /** - * Cleanup - */ - public void cleanup() { - if (snapcache != null) { - snapcache.clear(); - snapcache.reverselookup.clear(); - snapcache.reverselookup = null; - snapcache = null; - } - } -} diff --git a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ChunkSnapshot.java b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ChunkSnapshot.java deleted file mode 100644 index d0230252..00000000 --- a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ChunkSnapshot.java +++ /dev/null @@ -1,286 +0,0 @@ -package org.dynmap.forge_1_16_5; - -import java.util.Arrays; - -import org.dynmap.Log; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.utils.DataBitsPacked; - -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.util.BitArray; - -/** - * Represents a static, thread-safe snapshot of chunk of blocks - * Purpose is to allow clean, efficient copy of a chunk data to be made, and then handed off for processing in another thread (e.g. map rendering) - */ -public class ChunkSnapshot -{ - private static interface Section { - public DynmapBlockState getBlockType(int x, int y, int z); - public int getBlockSkyLight(int x, int y, int z); - public int getBlockEmittedLight(int x, int y, int z); - public boolean isEmpty(); - } - - private final int x, z; - private final Section[] section; - private final int[] hmap; // Height map - private final int[] biome; - 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 = 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 ChunkSnapshot(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.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 ChunkSnapshot(CompoundNBT 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.contains("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 */ - ListNBT sect = nbt.getList("Sections", 10); - for (int i = 0; i < sect.size(); i++) { - CompoundNBT 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.contains("Palette", 9) && sec.contains("BlockStates", 12)) { - ListNBT plist = sec.getList("Palette", 10); - long[] statelist = sec.getLongArray("BlockStates"); - palette = new DynmapBlockState[plist.size()]; - for (int pi = 0; pi < plist.size(); pi++) { - CompoundNBT tc = plist.getCompound(pi); - String pname = tc.getString("Name"); - if (tc.contains("Properties")) { - StringBuilder statestr = new StringBuilder(); - CompoundNBT prop = tc.getCompound("Properties"); - for (String pid : prop.keySet()) { - if (statestr.length() > 0) statestr.append(','); - statestr.append(pid).append('=').append(prop.get(pid).getString()); - } - 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; - BitArray db = null; - DataBitsPacked dbp = null; - try { - db = new BitArray(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 = (dbp != null) ? dbp.getAt(j) : db.getAt(j); - states[j] = DynmapBlockState.getStateByGlobalIndex(v); - } - } - else { - for (int j = 0; j < 4096; j++) { - int v = (dbp != null) ? dbp.getAt(j) : db.getAt(j); - states[j] = (v < palette.length) ? palette[v] : DynmapBlockState.AIR; - } - } - } - if (sec.contains("BlockLight")) { - cursect.emitlight = sec.getByteArray("BlockLight"); - } - if (sec.contains("SkyLight")) { - cursect.skylight = sec.getByteArray("SkyLight"); - } - } - /* Get biome data */ - this.biome = new int[COLUMNS_PER_CHUNK]; - if (nbt.contains("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; - } - } - 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; - } - } - } - } - } - - 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 int getBiome(int x, int z) - { - return biome[z << 4 | x]; - } - - public final long getCaptureFullTime() - { - return captureFulltime; - } - - public boolean isSectionEmpty(int sy) - { - return section[sy].isEmpty(); - } - - public long getInhabitedTicks() { - return inhabitedTicks; - } -} diff --git a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/DynmapPlugin.java b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/DynmapPlugin.java index 1851898f..249dbb4a 100644 --- a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/DynmapPlugin.java +++ b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/DynmapPlugin.java @@ -107,6 +107,7 @@ import org.dynmap.common.BiomeMap; import org.dynmap.common.DynmapCommandSender; import org.dynmap.common.DynmapPlayer; import org.dynmap.common.DynmapServerInterface; +import org.dynmap.common.chunk.GenericChunkCache; import org.dynmap.common.DynmapListenerManager.EventType; import org.dynmap.debug.Debug; import org.dynmap.forge_1_16_5.DmapCommand; @@ -146,7 +147,7 @@ public class DynmapPlugin private DynmapCore core; private PermissionProvider permissions; private boolean core_enabled; - public SnapshotCache sscache; + public GenericChunkCache sscache; public PlayerList playerList; private MapManager mapManager; private static net.minecraft.server.MinecraftServer server; @@ -1546,7 +1547,7 @@ public class DynmapPlugin } playerList = core.playerList; - sscache = new SnapshotCache(core.getSnapShotCacheSize(), core.useSoftRefInSnapShotCache()); + sscache = new GenericChunkCache(core.getSnapShotCacheSize(), core.useSoftRefInSnapShotCache()); /* Get map manager from core */ mapManager = core.getMapManager(); diff --git a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeMapChunkCache.java b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeMapChunkCache.java index eb761a17..511080d3 100644 --- a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeMapChunkCache.java +++ b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeMapChunkCache.java @@ -1,1489 +1,104 @@ package org.dynmap.forge_1_16_5; -import java.io.DataInputStream; -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.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; -import net.minecraft.nbt.ByteArrayNBT; -import net.minecraft.nbt.ByteNBT; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.DoubleNBT; -import net.minecraft.nbt.FloatNBT; -import net.minecraft.nbt.INBT; -import net.minecraft.nbt.IntArrayNBT; -import net.minecraft.nbt.IntNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.nbt.LongNBT; -import net.minecraft.nbt.ShortNBT; -import net.minecraft.nbt.StringNBT; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.World; -import net.minecraft.world.biome.Biome; import net.minecraft.world.chunk.AbstractChunkProvider; -import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; import net.minecraft.world.chunk.storage.ChunkSerializer; -import net.minecraft.world.chunk.storage.RegionFileCache; -import net.minecraft.world.server.ChunkManager; import net.minecraft.world.server.ServerChunkProvider; import net.minecraft.world.server.ServerWorld; import org.dynmap.DynmapChunk; -import org.dynmap.DynmapCore; -import org.dynmap.DynmapWorld; import org.dynmap.Log; -import org.dynmap.common.BiomeMap; -import org.dynmap.forge_1_16_5.SnapshotCache.SnapshotRec; -import org.dynmap.hdmap.HDBlockModels; -import org.dynmap.renderer.DynmapBlockState; -import org.dynmap.renderer.RenderPatchFactory; -import org.dynmap.utils.DynIntHashMap; -import org.dynmap.utils.MapChunkCache; -import org.dynmap.utils.MapIterator; -import org.dynmap.utils.BlockStep; -import org.dynmap.utils.VisibilityLimit; +import org.dynmap.common.chunk.GenericChunk; +import org.dynmap.common.chunk.GenericChunkCache; +import org.dynmap.common.chunk.GenericMapChunkCache; /** * Container for managing chunks - dependent upon using chunk snapshots, since rendering is off server thread */ -public class ForgeMapChunkCache extends MapChunkCache -{ - private static boolean init = false; - private static Field updateEntityTick = null; - /* ChunkManager fields */ - private static Field chunksToRemove = null; // Map - - /* ChunjManager Pending fields */ - private static Field chunkCoord = null; - private static Field nbtTag = null; - - private World w; - private DynmapWorld dw; +public class ForgeMapChunkCache extends GenericMapChunkCache { + private ServerWorld w; private ServerChunkProvider cps; - private int nsect; - private List chunks; - private ListIterator iterator; - private int x_min, x_max, z_min, z_max; - private int x_dim; - private boolean biome, biomeraw, highesty, blockdata; - private HiddenChunkStyle hidestyle = HiddenChunkStyle.FILL_AIR; - private List visible_limits = null; - private List hidden_limits = null; - private boolean isempty = true; - private int snapcnt; - private ChunkSnapshot[] snaparray; /* Index = (x-x_min) + ((z-z_min)*x_dim) */ - private DynIntHashMap[] snaptile; - private byte[][] sameneighborbiomecnt; - private BiomeMap[][] biomemap; - private boolean[][] isSectionNotEmpty; /* Indexed by snapshot index, then by section index */ - - - private static final BlockStep unstep[] = { BlockStep.X_MINUS, BlockStep.Y_MINUS, BlockStep.Z_MINUS, - BlockStep.X_PLUS, BlockStep.Y_PLUS, BlockStep.Z_PLUS - }; - - private static BiomeMap[] biome_to_bmap; - - private static final int getIndexInChunk(int cx, int cy, int cz) { - return (cy << 8) | (cz << 4) | cx; - } - - /** - * Iterator for traversing map chunk cache (base is for non-snapshot) - */ - public class OurMapIterator implements MapIterator - { - private int x, y, z, chunkindex, bx, bz; - private ChunkSnapshot snap; - private BlockStep laststep; - private DynmapBlockState blk; - private final int worldheight; - private final int x_base; - private final int z_base; - - OurMapIterator(int x0, int y0, int z0) - { - x_base = x_min << 4; - z_base = z_min << 4; - - if (biome) - { - biomePrep(); - } - - initialize(x0, y0, z0); - worldheight = w.getHeight(); - } - @Override - public final void initialize(int x0, int y0, int z0) - { - this.x = x0; - this.y = y0; - this.z = z0; - this.chunkindex = ((x >> 4) - x_min) + (((z >> 4) - z_min) * x_dim); - this.bx = x & 0xF; - this.bz = z & 0xF; - - if((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } - else { - snap = snaparray[chunkindex]; - } - - laststep = BlockStep.Y_MINUS; - - if ((y >= 0) && (y < worldheight)) - { - blk = null; - } - else - { - blk = DynmapBlockState.AIR; - } - } - @Override - public int getBlockSkyLight() - { - try - { - return snap.getBlockSkyLight(bx, y, bz); - } - catch (ArrayIndexOutOfBoundsException aioobx) - { - return 15; - } - } - @Override - public final int getBlockEmittedLight() - { - try - { - return snap.getBlockEmittedLight(bx, y, bz); - } - catch (ArrayIndexOutOfBoundsException aioobx) - { - return 0; - } - } - private void biomePrep() - { - if (sameneighborbiomecnt != null) - { - return; - } - - int x_size = x_dim << 4; - int z_size = (z_max - z_min + 1) << 4; - sameneighborbiomecnt = new byte[x_size][]; - biomemap = new BiomeMap[x_size][]; - - for (int i = 0; i < x_size; i++) - { - sameneighborbiomecnt[i] = new byte[z_size]; - biomemap[i] = new BiomeMap[z_size]; - } - - for (int i = 0; i < x_size; i++) - { - for (int j = 0; j < z_size; j++) - { - if (j == 0) - initialize(i + x_base, 64, z_base); - else - stepPosition(BlockStep.Z_PLUS); - - int bb = snap.getBiome(bx, bz); - BiomeMap bm = BiomeMap.byBiomeID(bb); - - biomemap[i][j] = bm; - int cnt = 0; - - if (i > 0) - { - if (bm == biomemap[i - 1][j]) /* Same as one to left */ - { - cnt++; - sameneighborbiomecnt[i - 1][j]++; - } - - if ((j > 0) && (bm == biomemap[i - 1][j - 1])) - { - cnt++; - sameneighborbiomecnt[i - 1][j - 1]++; - } - - if ((j < (z_size - 1)) && (bm == biomemap[i - 1][j + 1])) - { - cnt++; - sameneighborbiomecnt[i - 1][j + 1]++; - } - } - - if ((j > 0) && (biomemap[i][j] == biomemap[i][j - 1])) /* Same as one to above */ - { - cnt++; - sameneighborbiomecnt[i][j - 1]++; - } - - sameneighborbiomecnt[i][j] = (byte)cnt; - } - } - } - @Override - public final BiomeMap getBiome() - { - try - { - return biomemap[x - x_base][z - z_base]; - } - catch (Exception ex) - { - return BiomeMap.NULL; - } - } - @Override - public final int getSmoothGrassColorMultiplier(int[] colormap) - { - int mult = 0xFFFFFF; - - try - { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte)8) /* All neighbors same? */ - { - mult = bm.getModifiedGrassMultiplier(colormap[bm.biomeLookup()]); - } - else - { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) - { - for (int zoff = -1; zoff < 2; zoff++) - { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult = bm.getModifiedGrassMultiplier(colormap[bm.biomeLookup()]); - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } - catch (Exception x) - { - mult = 0xFFFFFF; - } - - return mult; - } - @Override - public final int getSmoothFoliageColorMultiplier(int[] colormap) - { - int mult = 0xFFFFFF; - - try - { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte)8) /* All neighbors same? */ - { - mult = bm.getModifiedFoliageMultiplier(colormap[bm.biomeLookup()]); - } - else - { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) - { - for (int zoff = -1; zoff < 2; zoff++) - { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult = bm.getModifiedFoliageMultiplier(colormap[bm.biomeLookup()]); - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } - catch (Exception x) - { - mult = 0xFFFFFF; - } - - return mult; - } - @Override - public final int getSmoothColorMultiplier(int[] colormap, int[] swampmap) - { - int mult = 0xFFFFFF; - - try - { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte)8) /* All neighbors same? */ - { - if (bm == BiomeMap.SWAMPLAND) - { - mult = swampmap[bm.biomeLookup()]; - } - else - { - mult = colormap[bm.biomeLookup()]; - } - } - else - { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) - { - for (int zoff = -1; zoff < 2; zoff++) - { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult; - - if (bm == BiomeMap.SWAMPLAND) - { - rmult = swampmap[bm.biomeLookup()]; - } - else - { - rmult = colormap[bm.biomeLookup()]; - } - - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } - catch (Exception x) - { - mult = 0xFFFFFF; - } - - return mult; - } - @Override - public final int getSmoothWaterColorMultiplier() - { - try - { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte)8) /* All neighbors same? */ - { - return bm.getWaterColorMult(); - } - - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) - { - for (int zoff = -1; zoff < 2; zoff++) - { - bm = biomemap[rx + xoff][rz + zoff]; - int mult = bm.getWaterColorMult(); - raccum += (mult >> 16) & 0xFF; - gaccum += (mult >> 8) & 0xFF; - baccum += mult & 0xFF; - } - } - - return ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - catch (Exception x) - { - return 0xFFFFFF; - } - } - @Override - public final int getSmoothWaterColorMultiplier(int[] colormap) - { - int mult = 0xFFFFFF; - - try - { - int rx = x - x_base; - int rz = z - z_base; - BiomeMap bm = biomemap[rx][rz]; - - if (sameneighborbiomecnt[rx][rz] >= (byte)8) /* All neighbors same? */ - { - mult = colormap[bm.biomeLookup()]; - } - else - { - int raccum = 0; - int gaccum = 0; - int baccum = 0; - - for (int xoff = -1; xoff < 2; xoff++) - { - for (int zoff = -1; zoff < 2; zoff++) - { - bm = biomemap[rx + xoff][rz + zoff]; - int rmult = colormap[bm.biomeLookup()]; - raccum += (rmult >> 16) & 0xFF; - gaccum += (rmult >> 8) & 0xFF; - baccum += rmult & 0xFF; - } - } - - mult = ((raccum / 9) << 16) | ((gaccum / 9) << 8) | (baccum / 9); - } - } - catch (Exception x) - { - mult = 0xFFFFFF; - } - - return mult; - } - /** - * Step current position in given direction - */ - @Override - public final void stepPosition(BlockStep step) - { - blk = null; - - switch (step.ordinal()) - { - case 0: - x++; - bx++; - - if (bx == 16) /* Next chunk? */ - { - bx = 0; - chunkindex++; - if((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } - else { - snap = snaparray[chunkindex]; - } - } - - break; - - case 1: - y++; - - if (y >= worldheight) - { - blk = DynmapBlockState.AIR; - } - - break; - - case 2: - z++; - bz++; - - if (bz == 16) /* Next chunk? */ - { - bz = 0; - chunkindex += x_dim; - if((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } - else { - snap = snaparray[chunkindex]; - } - } - break; - - case 3: - x--; - bx--; - - if (bx == -1) /* Next chunk? */ - { - bx = 15; - chunkindex--; - if((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } - else { - snap = snaparray[chunkindex]; - } - } - - break; - - case 4: - y--; - - if (y < 0) - { - blk = DynmapBlockState.AIR; - } - - break; - - case 5: - z--; - bz--; - - if (bz == -1) /* Next chunk? */ - { - bz = 15; - chunkindex -= x_dim; - if((chunkindex >= snapcnt) || (chunkindex < 0)) { - snap = EMPTY; - } - else { - snap = snaparray[chunkindex]; - } - } - break; - } - - laststep = step; - } - /** - * Unstep current position to previous position - */ - @Override - public BlockStep unstepPosition() - { - BlockStep ls = laststep; - stepPosition(unstep[ls.ordinal()]); - return ls; - } - /** - * Unstep current position in oppisite director of given step - */ - @Override - public void unstepPosition(BlockStep s) - { - stepPosition(unstep[s.ordinal()]); - } - @Override - public final void setY(int y) - { - if (y > this.y) - { - laststep = BlockStep.Y_PLUS; - } - else - { - laststep = BlockStep.Y_MINUS; - } - - this.y = y; - - if ((y < 0) || (y >= worldheight)) - { - blk = DynmapBlockState.AIR; - } - else - { - blk = null; - } - } - @Override - public final int getX() - { - return x; - } - @Override - public final int getY() - { - return y; - } - @Override - public final int getZ() - { - return z; - } - @Override - public final DynmapBlockState getBlockTypeAt(BlockStep s) - { - if (s == BlockStep.Y_MINUS) - { - if (y > 0) - { - return snap.getBlockType(bx, y - 1, bz); - } - } - else if (s == BlockStep.Y_PLUS) - { - if (y < (worldheight - 1)) - { - return snap.getBlockType(bx, y + 1, bz); - } - } - else - { - BlockStep ls = laststep; - stepPosition(s); - DynmapBlockState tid = snap.getBlockType(bx, y, bz); - unstepPosition(); - laststep = ls; - return tid; - } - - return DynmapBlockState.AIR; - } - @Override - public BlockStep getLastStep() - { - return laststep; - } - @Override - public int getWorldHeight() - { - return worldheight; - } - @Override - public long getBlockKey() - { - return (((chunkindex * worldheight) + y) << 8) | (bx << 4) | bz; - } - @Override - public final boolean isEmptySection() - { - try - { - return !isSectionNotEmpty[chunkindex][y >> 4]; - } - catch (Exception x) - { - initSectionData(chunkindex); - return !isSectionNotEmpty[chunkindex][y >> 4]; - } - } - @Override - public RenderPatchFactory getPatchFactory() { - return HDBlockModels.getPatchDefinitionFactory(); - } - @Override - public Object getBlockTileEntityField(String fieldId) { - try { - int idx = getIndexInChunk(bx,y,bz); - Object[] vals = (Object[])snaptile[chunkindex].get(idx); - for (int i = 0; i < vals.length; i += 2) { - if (vals[i].equals(fieldId)) { - return vals[i+1]; - } - } - } catch (Exception x) { - } - return null; - } - @Override - public DynmapBlockState getBlockTypeAt(int xoff, int yoff, int zoff) { - int xx = this.x + xoff; - int yy = this.y + yoff; - int zz = this.z + zoff; - int idx = ((xx >> 4) - x_min) + (((zz >> 4) - z_min) * x_dim); - try { - return snaparray[idx].getBlockType(xx & 0xF, yy, zz & 0xF); - } catch (Exception x) { - return DynmapBlockState.AIR; - } - } - @Override - public Object getBlockTileEntityFieldAt(String fieldId, int xoff, - int yoff, int zoff) { - return null; - } - @Override - public long getInhabitedTicks() { - try { - return snap.getInhabitedTicks(); - } catch (Exception x) { - return 0; - } - } - @Override - public DynmapBlockState getBlockType() { - if (blk == null) { - blk = snap.getBlockType(bx, y, bz); - } - return blk; - } - } - - private class OurEndMapIterator extends OurMapIterator - { - OurEndMapIterator(int x0, int y0, int z0) - { - super(x0, y0, z0); - } - @Override - public final int getBlockSkyLight() - { - return 15; - } - } - /** - * Chunk cache for representing unloaded chunk (or air) - */ - private static class EmptyChunk extends ChunkSnapshot - { - public EmptyChunk() - { - super(256, 0, 0, 0, 0); - } - /* Need these for interface, but not used */ - @Override - public int getX() - { - return 0; - } - @Override - public int getZ() - { - return 0; - } - @Override - public final DynmapBlockState getBlockType(int x, int y, int z) - { - return DynmapBlockState.AIR; - } - @Override - public final int getBlockSkyLight(int x, int y, int z) - { - return 15; - } - @Override - public final int getBlockEmittedLight(int x, int y, int z) - { - return 0; - } - @Override - public final int getHighestBlockYAt(int x, int z) - { - return 0; - } - @Override - public int getBiome(int x, int z) - { - return -1; - } - @Override - public boolean isSectionEmpty(int sy) - { - return true; - } - } - - /** - * Chunk cache for representing generic stone chunk - */ - private static class PlainChunk extends ChunkSnapshot - { - private DynmapBlockState fill; - - PlainChunk(String fill) - { - super(256, 0, 0, 0, 0); - this.fill = DynmapBlockState.getBaseStateByName(fill); - } - /* Need these for interface, but not used */ - @Override - public int getX() - { - return 0; - } - @Override - public int getZ() - { - return 0; - } - @Override - public int getBiome(int x, int z) - { - return -1; - } - @Override - public final DynmapBlockState getBlockType(int x, int y, int z) - { - if (y < 64) - { - return fill; - } - - return DynmapBlockState.AIR; - } - @Override - public final int getBlockSkyLight(int x, int y, int z) - { - if (y < 64) - { - return 0; - } - - return 15; - } - @Override - public final int getBlockEmittedLight(int x, int y, int z) - { - return 0; - } - @Override - public final int getHighestBlockYAt(int x, int z) - { - return 64; - } - @Override - public boolean isSectionEmpty(int sy) - { - return (sy < 4); - } - } - - private static final EmptyChunk EMPTY = new EmptyChunk(); - private static final PlainChunk STONE = new PlainChunk(DynmapBlockState.STONE_BLOCK); - private static final PlainChunk OCEAN = new PlainChunk(DynmapBlockState.WATER_BLOCK); - - - public static void init() { - if (!init) - { - Field[] f = ServerChunkProvider.class.getDeclaredFields(); - - f = ServerWorld.class.getDeclaredFields(); - for(int i = 0; i < f.length; i++) { - if((updateEntityTick == null) && f[i].getType().isAssignableFrom(int.class)) { - updateEntityTick = f[i]; - //Log.info("Found updateEntityTick - " + f[i].getName()); - updateEntityTick.setAccessible(true); - } - } - - f = ChunkManager.class.getDeclaredFields(); - for(int i = 0; i < f.length; i++) { - if((chunksToRemove == null) && (f[i].getType().equals(Map.class))) { - chunksToRemove = f[i]; - //Log.info("Found chunksToRemove - " + f[i].getName()); - chunksToRemove.setAccessible(true); - } -// else if((pendingAnvilChunksCoordinates == null) && (f[i].getType().equals(it.unimi.dsi.fastutil.longs.LongSet.class))) { -// //Log.info("Found pendingAnvilChunksCoordinates - " + f[i].getName()); -// pendingAnvilChunksCoordinates = f[i]; -// pendingAnvilChunksCoordinates.setAccessible(true); -// } - } - if (updateEntityTick == null) { - Log.severe("ERROR: cannot find updateEntityTick - dynmap cannot drive entity cleanup when no players are active"); - } - - init = true; + /** + * Construct empty cache + */ + public ForgeMapChunkCache(GenericChunkCache cc) { + super(cc); + init(); + } + + private boolean isLitChunk(CompoundNBT nbt) { + if ((nbt != null) && nbt.contains("Level")) { + nbt = nbt.getCompound("Level"); } - } + if (nbt != null) { + String stat = nbt.getString("Status"); + ChunkStatus cs = ChunkStatus.byName(stat); + if ((stat != null) && cs.isAtLeast(ChunkStatus.LIGHT)) { // ChunkStatus.LIGHT + return true; + } + } + return false; + } - /** - * Construct empty cache - */ - public ForgeMapChunkCache() - { - init(); - } - - public void setChunks(ForgeWorld dw, List chunks) - { - this.dw = dw; - this.w = dw.getWorld(); - if(dw.isLoaded()) { + // Load generic chunk from existing and already loaded chunk + protected GenericChunk getLoadedChunk(DynmapChunk chunk) { + GenericChunk gc = null; + IChunk ch = cps.getChunk(chunk.x, chunk.z, ChunkStatus.FULL, false); + if (ch != null) { + CompoundNBT nbt = ChunkSerializer.write(w, ch); + if (isLitChunk(nbt)) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + } + return gc; + } + // Load generic chunk from unloaded chunk + protected GenericChunk loadChunk(DynmapChunk chunk) { + GenericChunk gc = null; + CompoundNBT nbt = readChunk(chunk.x, chunk.z); + // If read was good + if (isLitChunk(nbt)) { + gc = parseChunkFromNBT(new NBT.NBTCompound(nbt)); + } + return gc; + } + + public void setChunks(ForgeWorld dw, List chunks) { + this.w = (ServerWorld) dw.getWorld(); + if (dw.isLoaded()) { /* Check if world's provider is ServerChunkProvider */ AbstractChunkProvider cp = this.w.getChunkProvider(); - if (cp instanceof ServerChunkProvider) - { + if (cp instanceof ServerChunkProvider) { cps = (ServerChunkProvider)cp; } - else - { + else { Log.severe("Error: world " + dw.getName() + " has unsupported chunk provider"); } - } - else { - chunks = new ArrayList(); - } - nsect = dw.worldheight >> 4; - this.chunks = chunks; + } + super.setChunks(dw, chunks); + } - /* Compute range */ - if (chunks.size() == 0) - { - this.x_min = 0; - this.x_max = 0; - this.z_min = 0; - this.z_max = 0; - x_dim = 1; - } - else - { - x_min = x_max = chunks.get(0).x; - z_min = z_max = chunks.get(0).z; - - for (DynmapChunk c : chunks) - { - if (c.x > x_max) - { - x_max = c.x; - } - - if (c.x < x_min) - { - x_min = c.x; - } - - if (c.z > z_max) - { - z_max = c.z; - } - - if (c.z < z_min) - { - z_min = c.z; - } - } - - x_dim = x_max - x_min + 1; - } - - snapcnt = x_dim * (z_max-z_min+1); - snaparray = new ChunkSnapshot[snapcnt]; - snaptile = new DynIntHashMap[snapcnt]; - isSectionNotEmpty = new boolean[snapcnt][]; - - } - - private static boolean didError = false; - - public CompoundNBT readChunk(int x, int z) { - try { - ChunkManager acl = cps.chunkManager; - - ChunkPos coord = new ChunkPos(x, z); - CompoundNBT rslt = acl.readChunk(coord); - if(rslt != null) { - rslt = rslt.getCompound("Level"); - // Don't load uncooked chunks - String stat = rslt.getString("Status"); - ChunkStatus cs = ChunkStatus.byName(stat); - if ((stat == null) || - // Needs to be at least lighted - (!cs.isAtLeast(ChunkStatus.LIGHT))) { - rslt = null; - } - } - //Log.info(String.format("loadChunk(%d,%d)=%s", x, z, (rslt != null) ? rslt.toString() : "null")); - return rslt; - } catch (Exception exc) { - Log.severe(String.format("Error reading chunk: %s,%d,%d", dw.getName(), x, z), exc); - return null; - } - } - - private Object getNBTValue(INBT v) { - Object val = null; - switch(v.getId()) { - case 1: // Byte - val = Byte.valueOf(((ByteNBT)v).getByte()); - break; - case 2: // Short - val = Short.valueOf(((ShortNBT)v).getShort()); - break; - case 3: // Int - val = Integer.valueOf(((IntNBT)v).getInt()); - break; - case 4: // Long - val = Long.valueOf(((LongNBT)v).getLong()); - break; - case 5: // Float - val = Float.valueOf(((FloatNBT)v).getFloat()); - break; - case 6: // Double - val = Double.valueOf(((DoubleNBT)v).getDouble()); - break; - case 7: // Byte[] - val = ((ByteArrayNBT)v).getByteArray(); - break; - case 8: // String - val = ((StringNBT)v).getString(); - break; - case 9: // List - ListNBT tl = (ListNBT) v; - ArrayList vlist = new ArrayList(); - int type = tl.getTagType(); - for (int i = 0; i < tl.size(); i++) { - switch (type) { - case 5: - float fv = tl.getFloat(i); - vlist.add(fv); - break; - case 6: - double dv = tl.getDouble(i); - vlist.add(dv); - break; - case 8: - String sv = tl.getString(i); - vlist.add(sv); - break; - case 10: - CompoundNBT tc = tl.getCompound(i); - vlist.add(getNBTValue(tc)); - break; - case 11: - int[] ia = tl.getIntArray(i); - vlist.add(ia); - break; - } - } - val = vlist; - break; - case 10: // Map - CompoundNBT tc = (CompoundNBT) v; - HashMap vmap = new HashMap(); - for (Object t : tc.keySet()) { - String st = (String) t; - INBT tg = tc.get(st); - vmap.put(st, getNBTValue(tg)); - } - val = vmap; - break; - case 11: // Int[] - val = ((IntArrayNBT)v).getIntArray(); - break; - } - return val; - } - - private boolean isChunkVisible(DynmapChunk chunk) { - 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; - } - } - } - return vis; - } - - private boolean tryChunkCache(DynmapChunk chunk, boolean vis) { - /* Check if cached chunk snapshot found */ - ChunkSnapshot ss = null; - SnapshotRec ssr = DynmapPlugin.plugin.sscache.getSnapshot(dw.getName(), chunk.x, chunk.z, blockdata, biome, biomeraw, highesty); - if(ssr != null) { - ss = ssr.ss; - if (!vis) - { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) - { - ss = STONE; - } - else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) - { - ss = OCEAN; - } - else - { - ss = EMPTY; - } - } - int idx = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - snaparray[idx] = ss; - snaptile[idx] = ssr.tileData; - } - return (ssr != null); - } - - // Prep snapshot and add to cache - private SnapshotRec prepChunkSnapshot(DynmapChunk chunk, CompoundNBT nbt) { - ChunkSnapshot ss = new ChunkSnapshot(nbt, dw.worldheight); - DynIntHashMap tileData = new DynIntHashMap(); - - ListNBT tiles = nbt.getList("TileEntities", 10); - if(tiles == null) tiles = new ListNBT(); - /* Get tile entity data */ - List vals = new ArrayList(); - for(int tid = 0; tid < tiles.size(); tid++) { - CompoundNBT tc = tiles.getCompound(tid); - int tx = tc.getInt("x"); - int ty = tc.getInt("y"); - int tz = tc.getInt("z"); - int cx = tx & 0xF; - int cz = tz & 0xF; - DynmapBlockState blk = ss.getBlockType(cx, ty, cz); - String[] te_fields = HDBlockModels.getTileEntityFieldsNeeded(blk); - if(te_fields != null) { - vals.clear(); - for(String id: te_fields) { - INBT v = tc.get(id); /* Get field */ - if(v != null) { - Object val = getNBTValue(v); - if(val != null) { - vals.add(id); - vals.add(val); - } - } - } - if(vals.size() > 0) { - Object[] vlist = vals.toArray(new Object[vals.size()]); - tileData.put(getIndexInChunk(cx, ty, cz), vlist); - } - } - } - SnapshotRec ssr = new SnapshotRec(); - ssr.ss = ss; - ssr.tileData = tileData; - DynmapPlugin.plugin.sscache.putSnapshot(dw.getName(), chunk.x, chunk.z, ssr, blockdata, biome, biomeraw, highesty); - - return ssr; - } - - /** - * Read NBT data from loaded chunks - needs to be called from server/world thread to be safe - * @returns number loaded - */ - public int getLoadedChunks() { - int cnt = 0; - if(!dw.isLoaded()) { - isempty = true; - unloadChunks(); - return 0; - } - ListIterator iter = chunks.listIterator(); - while (iter.hasNext()) { - long startTime = System.nanoTime(); - DynmapChunk chunk = iter.next(); - int chunkindex = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - if (snaparray[chunkindex] != null) continue; // Skip if already processed - - boolean vis = isChunkVisible(chunk); - - /* Check if cached chunk snapshot found */ - if (tryChunkCache(chunk, vis)) { - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - cnt++; - } - // If chunk is loaded and not being unloaded, we're grabbing its NBT data - else if (cps.chunkExists(chunk.x, chunk.z)) { - ChunkSnapshot ss; - DynIntHashMap tileData; - if (vis) { // If visible - CompoundNBT nbt = ChunkSerializer.write((ServerWorld)w, cps.getChunk(chunk.x, chunk.z, false)); - if (nbt != null) nbt = nbt.getCompound("Level"); - SnapshotRec ssr = prepChunkSnapshot(chunk, nbt); - ss = ssr.ss; - tileData = ssr.tileData; - } - else { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { - ss = STONE; - } - else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { - ss = OCEAN; - } - else { - ss = EMPTY; - } - tileData = new DynIntHashMap(); - } - snaparray[chunkindex] = ss; - snaptile[chunkindex] = tileData; - endChunkLoad(startTime, ChunkStats.LOADED_CHUNKS); - cnt++; - } - } - return cnt; - } - - @Override - public int loadChunks(int max_to_load) - { - return getLoadedChunks() + readChunks(max_to_load); - - } - - public int readChunks(int max_to_load) - { - if(!dw.isLoaded()) { - isempty = true; - unloadChunks(); - return 0; - } - - int cnt = 0; - - if (iterator == null) - { - iterator = chunks.listIterator(); - } - - DynmapCore.setIgnoreChunkLoads(true); - - // Load the required chunks. - while ((cnt < max_to_load) && iterator.hasNext()) - { - long startTime = System.nanoTime(); - - DynmapChunk chunk = iterator.next(); - - int chunkindex = (chunk.x-x_min) + (chunk.z - z_min)*x_dim; - - if (snaparray[chunkindex] != null) continue; // Skip if already processed - - boolean vis = isChunkVisible(chunk); - - /* Check if cached chunk snapshot found */ - if (tryChunkCache(chunk, vis)) { - endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT); - } - else { - CompoundNBT nbt = readChunk(chunk.x, chunk.z); - // If read was good - if (nbt != null) { - ChunkSnapshot ss; - DynIntHashMap tileData; - // If hidden - if (!vis) { - if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) { - ss = STONE; - } - else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) { - ss = OCEAN; - } - else { - ss = EMPTY; - } - tileData = new DynIntHashMap(); - } - else { - // Prep snapshot - SnapshotRec ssr = prepChunkSnapshot(chunk, nbt); - ss = ssr.ss; - tileData = ssr.tileData; - } - snaparray[chunkindex] = ss; - snaptile[chunkindex] = tileData; - endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS); - } - else { - endChunkLoad(startTime, ChunkStats.UNGENERATED_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; - } - /** - * Test if done loading - */ - public boolean isDoneLoading() - { - if(!dw.isLoaded()) { - return true; - } - if (iterator != null) - { - return !iterator.hasNext(); - } - - return false; - } - /** - * Test if all empty blocks - */ - public boolean isEmpty() - { - return isempty; - } - /** - * Unload chunks - */ - public void unloadChunks() - { - if (snaparray != null) - { - for (int i = 0; i < snaparray.length; i++) - { - snaparray[i] = null; - } - - snaparray = null; - } - } - private void initSectionData(int idx) - { - isSectionNotEmpty[idx] = new boolean[nsect + 1]; - - if (snaparray[idx] != EMPTY) - { - for (int i = 0; i < nsect; i++) - { - if (snaparray[idx].isSectionEmpty(i) == false) - { - isSectionNotEmpty[idx][i] = true; - } - } - } - } - public boolean isEmptySection(int sx, int sy, int sz) - { - int idx = (sx - x_min) + (sz - z_min) * x_dim; - - if (isSectionNotEmpty[idx] == null) - { - initSectionData(idx); - } - - return !isSectionNotEmpty[idx][sy]; - } - - /** - * Get cache iterator - */ - public MapIterator getIterator(int x, int y, int z) - { - if (dw.getEnvironment().equals("the_end")) - { - return new OurEndMapIterator(x, y, z); - } - - return new OurMapIterator(x, y, z); - } - /** - * Set hidden chunk style (default is FILL_AIR) - */ - public void setHiddenFillStyle(HiddenChunkStyle style) - { - this.hidestyle = style; - } - /** - * Add visible area limit - can be called more than once - * Needs to be set before chunks are loaded - * Coordinates are block coordinates - */ - public void setVisibleRange(VisibilityLimit lim) { - if(visible_limits == null) - visible_limits = new ArrayList(); - visible_limits.add(lim); - } - /** - * Add hidden area limit - can be called more than once - * Needs to be set before chunks are loaded - * Coordinates are block coordinates - */ - public void setHiddenRange(VisibilityLimit lim) { - if(hidden_limits == null) - hidden_limits = new ArrayList(); - hidden_limits.add(lim); - } - @Override - public boolean setChunkDataTypes(boolean blockdata, boolean biome, boolean highestblocky, boolean rawbiome) - { - this.biome = biome; - this.biomeraw = rawbiome; - this.highesty = highestblocky; - this.blockdata = blockdata; - return true; - } - @Override - public DynmapWorld getWorld() - { - return dw; - } - - static - { - Biome b[] = DynmapPlugin.getBiomeList(); - BiomeMap[] bm = BiomeMap.values(); - biome_to_bmap = new BiomeMap[256]; - - for (int i = 0; i < biome_to_bmap.length; i++) - { - biome_to_bmap[i] = BiomeMap.NULL; - } - - for (int i = 0; i < b.length; i++) - { - if(b[i] == null) continue; - - String bs = b[i].toString(); - - for (int j = 0; j < bm.length; j++) - { - if (bm[j].toString().equals(bs)) - { - biome_to_bmap[i] = bm[j]; - break; - } - } - } - } + private CompoundNBT readChunk(int x, int z) { + try { + CompoundNBT rslt = cps.chunkManager.readChunk(new ChunkPos(x, z)); + if (rslt != null) { + if (rslt.contains("Level")) { + rslt = rslt.getCompound("Level"); + } + } + if (!isLitChunk(rslt)) { + rslt = null; + } + return rslt; + } catch (Exception exc) { + Log.severe(String.format("Error reading chunk: %s,%d,%d", dw.getName(), x, z), exc); + return null; + } + } } diff --git a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeWorld.java b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeWorld.java index b7a881d0..e3487118 100644 --- a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeWorld.java +++ b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/ForgeWorld.java @@ -8,7 +8,6 @@ import net.minecraft.util.RegistryKey; import net.minecraft.util.math.BlockPos; import net.minecraft.world.gen.Heightmap.Type; import net.minecraft.world.IServerWorld; -import net.minecraft.world.IWorld; import net.minecraft.world.LightType; import net.minecraft.world.World; import net.minecraft.world.border.WorldBorder; @@ -206,7 +205,7 @@ public class ForgeWorld extends DynmapWorld public MapChunkCache getChunkCache(List chunks) { if(world != null) { - ForgeMapChunkCache c = new ForgeMapChunkCache(); + ForgeMapChunkCache c = new ForgeMapChunkCache(DynmapPlugin.plugin.sscache); c.setChunks(this, chunks); return c; } diff --git a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/NBT.java b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/NBT.java new file mode 100644 index 00000000..a3eb249c --- /dev/null +++ b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/NBT.java @@ -0,0 +1,120 @@ +package org.dynmap.forge_1_16_5; + +import org.dynmap.common.chunk.GenericBitStorage; +import org.dynmap.common.chunk.GenericNBTCompound; +import org.dynmap.common.chunk.GenericNBTList; + +import java.util.Set; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.BitArray; + +public class NBT { + + public static class NBTCompound implements GenericNBTCompound { + private final CompoundNBT obj; + public NBTCompound(CompoundNBT t) { + this.obj = t; + } + @Override + public Set getAllKeys() { + return obj.keySet(); + } + @Override + public boolean contains(String s) { + return obj.contains(s); + } + @Override + public boolean contains(String s, int i) { + return obj.contains(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).getString(); + } + @Override + public GenericBitStorage makeBitStorage(int bits, int count, long[] data) { + return new OurBitStorage(bits, count, data); + } + } + public static class NBTList implements GenericNBTList { + private final ListNBT obj; + public NBTList(ListNBT 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 static class OurBitStorage implements GenericBitStorage { + private final BitArray bs; + public OurBitStorage(int bits, int count, long[] data) { + bs = new BitArray(bits, count, data); + } + @Override + public int get(int idx) { + return bs.getAt(idx); + } + } +} diff --git a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/SnapshotCache.java b/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/SnapshotCache.java deleted file mode 100644 index fbc97489..00000000 --- a/forge-1.16.5/src/main/java/org/dynmap/forge_1_16_5/SnapshotCache.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.dynmap.forge_1_16_5; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.lang.ref.SoftReference; -import java.util.IdentityHashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.dynmap.utils.DynIntHashMap; - -public class SnapshotCache { - public static class SnapshotRec { - public ChunkSnapshot ss; - public DynIntHashMap tileData; - }; - - private CacheHashMap snapcache; - private ReferenceQueue refqueue; - private long cache_attempts; - private long cache_success; - private boolean softref; - - private static class CacheRec { - Reference ref; - boolean hasbiome; - boolean hasrawbiome; - boolean hasblockdata; - boolean hashighesty; - } - - @SuppressWarnings("serial") - public class CacheHashMap extends LinkedHashMap { - private int limit; - private IdentityHashMap, String> reverselookup; - - public CacheHashMap(int lim) { - super(16, (float)0.75, true); - limit = lim; - reverselookup = new IdentityHashMap, String>(); - } - protected boolean removeEldestEntry(Map.Entry last) { - boolean remove = (size() >= limit); - if(remove && (last != null) && (last.getValue() != null)) { - reverselookup.remove(last.getValue().ref); - } - return remove; - } - } - - /** - * Create snapshot cache - */ - public SnapshotCache(int max_size, boolean softref) { - snapcache = new CacheHashMap(max_size); - refqueue = new ReferenceQueue(); - this.softref = softref; - } - private String getKey(String w, int cx, int cz) { - return w + ":" + cx + ":" + cz; - } - /** - * Invalidate cached snapshot, if in cache - */ - public void invalidateSnapshot(String w, int x, int y, int z) { - String key = getKey(w, x>>4, z>>4); - synchronized(snapcache) { - CacheRec rec = snapcache.remove(key); - if(rec != null) { - snapcache.reverselookup.remove(rec.ref); - rec.ref.clear(); - } - } - //processRefQueue(); - } - /** - * Invalidate cached snapshot, if in cache - */ - public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1, int z1) { - for(int xx = (x0>>4); xx <= (x1>>4); xx++) { - for(int zz = (z0>>4); zz <= (z1>>4); zz++) { - String key = getKey(w, xx, zz); - synchronized(snapcache) { - CacheRec rec = snapcache.remove(key); - if(rec != null) { - snapcache.reverselookup.remove(rec.ref); - rec.ref.clear(); - } - } - } - } - //processRefQueue(); - } - /** - * Look for chunk snapshot in cache - */ - public SnapshotRec getSnapshot(String w, int chunkx, int chunkz, - boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) { - String key = getKey(w, chunkx, chunkz); - processRefQueue(); - SnapshotRec ss = null; - CacheRec rec; - synchronized(snapcache) { - rec = snapcache.get(key); - if(rec != null) { - ss = rec.ref.get(); - if(ss == null) { - snapcache.reverselookup.remove(rec.ref); - snapcache.remove(key); - } - } - } - if(ss != null) { - if((blockdata && (!rec.hasblockdata)) || - (biome && (!rec.hasbiome)) || - (biomeraw && (!rec.hasrawbiome)) || - (highesty && (!rec.hashighesty))) { - ss = null; - } - } - cache_attempts++; - if(ss != null) cache_success++; - - return ss; - } - /** - * Add chunk snapshot to cache - */ - public void putSnapshot(String w, int chunkx, int chunkz, SnapshotRec ss, - boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) { - String key = getKey(w, chunkx, chunkz); - processRefQueue(); - CacheRec rec = new CacheRec(); - rec.hasblockdata = blockdata; - rec.hasbiome = biome; - rec.hasrawbiome = biomeraw; - rec.hashighesty = highesty; - if (softref) - rec.ref = new SoftReference(ss, refqueue); - else - rec.ref = new WeakReference(ss, refqueue); - synchronized(snapcache) { - CacheRec prevrec = snapcache.put(key, rec); - if(prevrec != null) { - snapcache.reverselookup.remove(prevrec.ref); - } - snapcache.reverselookup.put(rec.ref, key); - } - } - /** - * Process reference queue - */ - private void processRefQueue() { - Reference ref; - while((ref = refqueue.poll()) != null) { - synchronized(snapcache) { - String k = snapcache.reverselookup.remove(ref); - if(k != null) { - snapcache.remove(k); - } - } - } - } - /** - * Get hit rate (percent) - */ - public double getHitRate() { - if(cache_attempts > 0) { - return (100.0*cache_success)/(double)cache_attempts; - } - return 0.0; - } - /** - * Reset cache stats - */ - public void resetStats() { - cache_attempts = cache_success = 0; - } - /** - * Cleanup - */ - public void cleanup() { - if(snapcache != null) { - snapcache.clear(); - snapcache.reverselookup.clear(); - snapcache.reverselookup = null; - snapcache = null; - } - } -}