Files
logan 60e10b35a3 fix(bench): reset instance JVM settings for sessions without --jvm
apply_jvm wrote instance.cfg and never restored it, so B5-B12a in run 1
ran on B4's last set (Shenandoah, 6 GB). Within-block verdicts hold
(same JVM on both sides); B7's no-shader baseline is re-run in run 2.

Also: B14 spawn-count automation (b14/: fresh seeded world per run,
offline-located biome sites, datapack entity counts, journaled config
variants) and RESULTS-proxy.md with run-1 verdicts.
2026-10-17 22:28:20 -04:00

163 lines
5.0 KiB
Python

"""Minimal read-only NBT / Anvil region reader (stdlib only) for B14 site finding.
Enough of the format to read level.dat and 1.18+ chunk biomes + heightmaps:
https://minecraft.wiki/w/NBT_format, /Region_file_format, /Chunk_format.
"""
import gzip
import io
import math
import struct
import zlib
END, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, BYTE_ARRAY, STRING, LIST, COMPOUND, \
INT_ARRAY, LONG_ARRAY = range(13)
class _Reader:
def __init__(self, data):
self.b, self.i = data, 0
def take(self, n):
s = self.b[self.i:self.i + n]
if len(s) != n:
raise ValueError("truncated NBT")
self.i += n
return s
def unpack(self, fmt):
size = struct.calcsize(fmt)
return struct.unpack(fmt, self.take(size))
def string(self):
(n,) = self.unpack(">H")
return self.take(n).decode("utf-8", "replace")
def payload(self, t):
if t == BYTE:
return self.unpack(">b")[0]
if t == SHORT:
return self.unpack(">h")[0]
if t == INT:
return self.unpack(">i")[0]
if t == LONG:
return self.unpack(">q")[0]
if t == FLOAT:
return self.unpack(">f")[0]
if t == DOUBLE:
return self.unpack(">d")[0]
if t == BYTE_ARRAY:
(n,) = self.unpack(">i")
return self.take(n)
if t == STRING:
return self.string()
if t == LIST:
et, n = self.unpack(">bi")
return [self.payload(et) for _ in range(max(0, n))]
if t == COMPOUND:
out = {}
while True:
(ct,) = self.unpack(">b")
if ct == END:
return out
name = self.string()
out[name] = self.payload(ct)
if t == INT_ARRAY:
(n,) = self.unpack(">i")
return list(struct.unpack(f">{n}i", self.take(4 * n)))
if t == LONG_ARRAY:
(n,) = self.unpack(">i")
return list(struct.unpack(f">{n}q", self.take(8 * n)))
raise ValueError(f"bad NBT tag type {t}")
def loads(data):
"""Parse an uncompressed NBT blob -> (root name, root compound)."""
r = _Reader(data)
(t,) = r.unpack(">b")
if t != COMPOUND:
raise ValueError("NBT root is not a compound")
name = r.string()
return name, r.payload(COMPOUND)
def load_gzip(data):
"""level.dat style (gzip) NBT."""
return loads(gzip.decompress(data))
def region_chunks(data):
"""Yield (local_x, local_z, chunk_compound) for every chunk in an .mca blob."""
if len(data) < 8192:
return
for idx in range(1024):
off = int.from_bytes(data[idx * 4:idx * 4 + 3], "big")
if off == 0:
continue
start = off * 4096
if start + 5 > len(data):
continue
length = int.from_bytes(data[start:start + 4], "big")
comp = data[start + 4]
blob = data[start + 5:start + 4 + length]
try:
if comp == 2:
raw = zlib.decompress(blob)
elif comp == 1:
raw = gzip.GzipFile(fileobj=io.BytesIO(blob)).read()
elif comp == 3:
raw = blob
else: # 4 = lz4 (not in vanilla defaults) / 128+ = external .mcc
continue
_, chunk = loads(raw)
except (ValueError, zlib.error, OSError, struct.error):
continue
yield idx % 32, idx // 32, chunk
def _unsigned(v):
return v & 0xFFFFFFFFFFFFFFFF
def unpack_packed(longs, bits, count):
"""1.16+ packed array: entries never span longs."""
per = 64 // bits
mask = (1 << bits) - 1
out = []
for i in range(count):
word = _unsigned(longs[i // per])
out.append((word >> ((i % per) * bits)) & mask)
return out
def section_biome_grid(section):
"""64 biome ids (index = (y4*4 + z4)*4 + x4) for one chunk section, or None."""
b = section.get("biomes")
if not b or not b.get("palette"):
return None
pal = b["palette"]
if len(pal) == 1 or "data" not in b:
return [pal[0]] * 64
bits = max(1, math.ceil(math.log2(len(pal))))
return [pal[i] if i < len(pal) else pal[0] for i in unpack_packed(b["data"], bits, 64)]
def heightmap(chunk, kind="MOTION_BLOCKING_NO_LEAVES", min_y=-64, height=384):
"""256 world-y values (first free block above the top matching block), idx = z*16+x."""
hm = (chunk.get("Heightmaps") or {}).get(kind)
if not hm:
return None
bits = math.ceil(math.log2(height + 1))
return [v + min_y for v in unpack_packed(hm, bits, 256)]
def biome_at(chunk, x, y, z):
"""Biome id at block (x, y, z) in this chunk (x, z may be world coords)."""
sy = y >> 4
for s in chunk.get("sections", []):
if s.get("Y") == sy:
grid = section_biome_grid(s)
if grid is None:
return None
return grid[(((y & 15) >> 2) * 4 + ((z & 15) >> 2)) * 4 + ((x & 15) >> 2)]
return None