SciCraft/tools/gen_story.py

92 lines
No EOL
3 KiB
Python
Executable file

#!/usr/bin/env python3
"""SCICRAFT — story generator.
Reads STORY/*.md, merges every ```lang JSON block (in filename order) into
en_us.json, writes it to BOTH packs, and validates that every lang key
referenced from the KubeJS scripts and advancement JSONs resolves.
Usage:
python tools/gen_story.py
Edit the story by editing STORY/*.md, then run this script. Never hand-edit
en_us.json — it is a generated artifact.
"""
import json
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
STORY_DIR = ROOT / "STORY"
LANGS = [
ROOT / "server_pack" / "kubejs" / "assets" / "scicraft" / "lang" / "en_us.json",
ROOT / "client_pack" / "kubejs" / "assets" / "scicraft" / "lang" / "en_us.json",
]
KUBEJS_DIRS = [ROOT / "server_pack" / "kubejs"]
ADVANCEMENT_DIR = ROOT / "server_pack" / "kubejs" / "data" / "scicraft" / "advancements"
LANG_BLOCK = re.compile(r"```lang\s*\n(.*?)```", re.S)
def load_lang_files():
merged = {}
order = []
for path in sorted(STORY_DIR.glob("*.md")):
text = path.read_text(encoding="utf-8")
for i, match in enumerate(LANG_BLOCK.finditer(text)):
try:
data = json.loads(match.group(1))
except json.JSONDecodeError as e:
sys.exit(f"BAD JSON in {path.name} block #{i + 1}: {e}")
for key, value in data.items():
if key in merged:
print(f"WARN: duplicate key {key!r} ({path.name} overrides)")
merged[key] = value
order.append(key)
return merged, order
def write_lang(merged, order):
payload = {k: merged[k] for k in order}
for target in LANGS:
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(
json.dumps(payload, ensure_ascii=False, indent="\t") + "\n",
encoding="utf-8",
)
print(f"wrote {target.relative_to(ROOT)} ({len(payload)} keys)")
def validate(merged):
missing = set()
def check_key(key, source):
if key not in merged:
missing.add((key, source))
for root_dir in KUBEJS_DIRS:
for script in root_dir.rglob("*.js"):
for key in re.findall(r"Text\.translate\(\s*['\"]([^'\"]+)['\"]\s*(?:\+|\))", script.read_text(encoding="utf-8")):
# Keys followed by ` + msg` are dynamic templates — skip.
if key.endswith("."):
continue
check_key(key, str(script.relative_to(ROOT)))
if ADVANCEMENT_DIR.exists():
for jf in ADVANCEMENT_DIR.rglob("*.json"):
for key in re.findall(r'"translate"\s*:\s*"([^"]+)"', jf.read_text(encoding="utf-8")):
check_key(key, str(jf.relative_to(ROOT)))
if missing:
print("\nMISSING LANG KEYS:")
for key, source in sorted(missing):
print(f" {key} (used in {source})")
sys.exit(1)
print("all referenced lang keys resolve")
if __name__ == "__main__":
merged, order = load_lang_files()
write_lang(merged, order)
validate(merged)