"""Minimal reader for gzipped NBT structure templates (data/*/structure/*.nbt). Only what the field guide needs: the palette, block-entity strings (loot tables, jigsaw pools) and entity ids. Returns plain Python values. """ import gzip import io import struct def _read(f, tag): if tag == 1: return struct.unpack(">b", f.read(1))[0] if tag == 2: return struct.unpack(">h", f.read(2))[0] if tag == 3: return struct.unpack(">i", f.read(4))[0] if tag == 4: return struct.unpack(">q", f.read(8))[0] if tag == 5: return struct.unpack(">f", f.read(4))[0] if tag == 6: return struct.unpack(">d", f.read(8))[0] if tag == 7: return f.read(struct.unpack(">i", f.read(4))[0]) if tag == 8: return f.read(struct.unpack(">H", f.read(2))[0]).decode("utf-8", "replace") if tag == 9: inner, n = struct.unpack(">bi", f.read(5)) return [_read(f, inner) for _ in range(n)] if tag == 10: out = {} while True: t = f.read(1)[0] if t == 0: return out name = f.read(struct.unpack(">H", f.read(2))[0]).decode("utf-8", "replace") out[name] = _read(f, t) if tag == 11: n = struct.unpack(">i", f.read(4))[0] return list(struct.unpack(f">{n}i", f.read(4 * n))) if tag == 12: n = struct.unpack(">i", f.read(4))[0] return list(struct.unpack(f">{n}q", f.read(8 * n))) raise ValueError(f"bad NBT tag {tag}") def load(raw): data = gzip.decompress(raw) if raw[:2] == b"\x1f\x8b" else raw f = io.BytesIO(data) tag = f.read(1)[0] f.read(struct.unpack(">H", f.read(2))[0]) return _read(f, tag) def strings(value): """Every string inside a decoded NBT value.""" if isinstance(value, str): yield value elif isinstance(value, dict): for v in value.values(): yield from strings(v) elif isinstance(value, list): for v in value: yield from strings(v)