diff --git a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/ChunkSnapshot.java b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/ChunkSnapshot.java index 688e7904..8171918a 100644 --- a/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/ChunkSnapshot.java +++ b/fabric-1.18/src/main/java/org/dynmap/fabric_1_18/ChunkSnapshot.java @@ -6,7 +6,9 @@ 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.common.BiomeMap; import org.dynmap.renderer.DynmapBlockState; +import net.fabricmc.fabric.api.util.NbtType; import java.util.Arrays; import java.util.LinkedList; @@ -24,18 +26,20 @@ public class ChunkSnapshot { public int getBlockEmittedLight(int x, int y, int z); public boolean isEmpty(); + + public int getBiome(int x, int y, int z); } private final int x, z; private final Section[] section; private final int sectionOffset; 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 BIOMES_PER_SECTION = 4 * 4 * 4; 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]; @@ -64,17 +68,25 @@ public class ChunkSnapshot { public boolean isEmpty() { return true; } + + @Override + public int getBiome(int x, int y, int z) { + return BiomeMap.PLAINS.getBiomeID(); + } } private static final EmptySection empty_section = new EmptySection(); private static class StdSection implements Section { DynmapBlockState[] states; + int[] biomes; byte[] skylight; byte[] emitlight; public StdSection() { states = new DynmapBlockState[BLOCKS_PER_SECTION]; + biomes = new int[BIOMES_PER_SECTION]; + Arrays.fill(biomes, BiomeMap.PLAINS.getBiomeID()); Arrays.fill(states, DynmapBlockState.AIR); skylight = emptyData; emitlight = emptyData; @@ -101,6 +113,12 @@ public class ChunkSnapshot { public boolean isEmpty() { return false; } + + @Override + public int getBiome(int x, int y, int z) { + int off = (((y & 0xF) >> 2) << 4) | ((z >> 2) << 2) | (x >> 2); + return biomes[off]; + } } /** @@ -113,10 +131,9 @@ public class ChunkSnapshot { 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]; + this.section = new Section[this.sectionCnt + 1]; this.sectionOffset = 0; /* Fill with empty data */ for (int i = 0; i <= this.sectionCnt; i++) { @@ -124,7 +141,7 @@ public class ChunkSnapshot { } /* Create empty height map */ - this.hmap = new int[16 * 16]; + this.hmap = new int[COLUMNS_PER_CHUNK]; this.inhabitedTicks = inhabitedTime; } @@ -148,16 +165,25 @@ public class ChunkSnapshot { 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; } + this.hmap = new int[COLUMNS_PER_CHUNK]; + if (nbt.contains("Heightmaps")) { + NbtCompound hmaps = nbt.getCompound("Heightmaps"); + long[] phmap = hmaps.getLongArray("WORLD_SURFACE"); + PackedIntegerArray hmap = new PackedIntegerArray((phmap.length * 64) / COLUMNS_PER_CHUNK, COLUMNS_PER_CHUNK, + phmap); + for (int i = 0; i < this.hmap.length; i++) { + this.hmap[i] = hmap.get(i); + } + } /* Allocate arrays indexed by section */ LinkedList
sections = new LinkedList
(); - int sectoff = 0; // Default to zero + int sectoff = 0; // Default to zero int sectcnt = 0; /* Fill with empty data */ for (int i = 0; i <= this.sectionCnt; i++) { @@ -186,11 +212,12 @@ public class ChunkSnapshot { sections.set(secnum + sectoff, cursect); DynmapBlockState[] states = cursect.states; DynmapBlockState[] palette = null; - NbtCompound block_states = sec.getCompound("block_states"); - // If we've block state data, process non-empty section - if (block_states.contains("data", 12)) { - long[] statelist = block_states.getLongArray("data"); - NbtList plist = block_states.getList("palette", 10); + int[] biomes = cursect.biomes; + // If we've got palette and block states list, process non-empty section + if (sec.contains("block_states", NbtType.COMPOUND)) { + NbtCompound bstat = sec.getCompound("block_states"); + NbtList plist = bstat.getList("palette", 10); + long[] statelist = bstat.getLongArray("data"); palette = new DynmapBlockState[plist.size()]; for (int pi = 0; pi < plist.size(); pi++) { NbtCompound tc = plist.getCompound(pi); @@ -212,31 +239,34 @@ public class ChunkSnapshot { } } - PackedIntegerArray db = null; - WordPackedArray dbp = null; + if (statelist.length > 0) { + 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); + 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 { - throw new StateListException(x, z, statelist.length, expectedStatelistLength, expectedLegacyStatelistLength); + 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 (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; + } } } } @@ -246,28 +276,16 @@ public class ChunkSnapshot { if (sec.contains("SkyLight")) { cursect.skylight = sec.getByteArray("SkyLight"); } - } - /* Get biome data */ - // TODO: Update to new 1.18 format (3D biomes, sectioned): - 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; - } + if (sec.contains("biomes")) { + NbtCompound nbtbiomes = sec.getCompound("biomes"); + long[] bdataPacked = nbtbiomes.getLongArray("data"); + NbtList bpalette = nbtbiomes.getList("palette", NbtType.STRING); + PackedIntegerArray bdata = null; + if (bdataPacked.length > 0) + bdata = new PackedIntegerArray(bdataPacked.length, 64, bdataPacked); + for (int j = 0; j < 64; j++) { + int b = bdata != null ? bdata.get(j) : 0; + biomes[j] = b < bpalette.size() ? BiomeMap.byBiomeName(bpalette.getString(b)).getBiomeID() : -1; } } } @@ -310,7 +328,11 @@ public class ChunkSnapshot { } public int getBiome(int x, int z) { - return biome[z << 4 | x]; + int y = getHighestBlockYAt(x, z); + final int idx = (y >> 4) + sectionOffset; + if ((idx < 0) || (idx >= section.length)) + return 0; + return section[idx].getBiome(x % 16, y % 16, z % 16); } public final long getCaptureFullTime() {