Free NeoForge 1.21.1 modpack on Cobblemon 1.8.4 built with packwiz, plus the Kotlin companion mod (cobblesurvival) and its built-in data pack. - Phase 0: packwiz pack with Modrinth/CurseForge cross-links, build and export tooling, Prism instance sync, test server with smoke checks. - Phase 1: Poke Ball shaped island (WorldGen Editor preset, seed isle-26), Adrian's biome list, no natural ore, structures without ore or vanilla mobs, no Nether portals, world template builder and world report. - Phase 2: permadeath (CobbleHardcoreMon plus the companion mod's gap fixes), Revival Charm, expensive Healing Machine, Lootr refreshing loot, in-game self-tests on Minecraft's GameTest framework. - Phase 3 so far: 14 zones with their own spawn pools and level bands (tools/zone_layout.py, tools/zone_spawns.py, "zone" spawn condition), Cold Sweat heat and cold as gates with boss-drop insulation recipes, spawn survey and hazard self-tests in tools/quick_check.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
2.0 KiB
Python
66 lines
2.0 KiB
Python
"""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)
|