Files
cobblemon-survival-pack/tools/fieldguide/nbt.py
T
claudeandClaude Opus 5.5 398301f0be Cobblemon Survival Pack: phases 0-2 and Phase 3 zones and hazards
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>
2026-10-29 19:01:21 +01:00

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)