Star map (W1-W3, S3): - _process visibility guard + dirty flag (no redraw when hidden/unchanged) - _system_hash masked to 31-bit positive range - Extracted _find_nearest_system() shared helper game_state.gd (W4): - Inline load() in apply_snapshot() replaces per-tick overhead; safe at runtime because script is already in resource cache Data pipeline (W5-W6): - Script-relative path resolution via __file__ - --check mode + make check-star-map staleness target Minor (S1-S2, S5): - Removed redundant bone_idx assignment - Simplified double-negative test assertion - Documented autoload parse-order convention in CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
129 lines
4.5 KiB
Python
Executable File
129 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Generate client/data/star_map_data.json from star-map.json + systems.db.
|
|
|
|
Run from any directory — paths are resolved relative to this script's location:
|
|
python3 tooling/generate-star-map-data.py
|
|
python3 tooling/generate-star-map-data.py --check # exit 1 if committed JSON is stale
|
|
|
|
Sources:
|
|
docs/design/star-map.json — graph topology (nodes + edges)
|
|
server/server/data/systems.db — proper names, geographic sectors
|
|
|
|
Output:
|
|
client/data/star_map_data.json — self-contained client data for the star map UI
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sqlite3
|
|
import sys
|
|
import tempfile
|
|
|
|
# Resolve project root from this script's location: tooling/ is one level below root.
|
|
# Works regardless of cwd — no fragile relative path guessing.
|
|
_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
_PROJECT_ROOT = os.path.dirname(_SCRIPT_DIR)
|
|
|
|
# Worktree layout: settled-reach/{client,server,main}/
|
|
# This script lives in client/tooling/, so _PROJECT_ROOT = client/.
|
|
# The parent of _PROJECT_ROOT is the worktree parent where sibling dirs live.
|
|
_WORKTREE_PARENT = os.path.dirname(_PROJECT_ROOT)
|
|
|
|
STAR_MAP_PATH = os.path.join(_PROJECT_ROOT, "docs", "design", "star-map.json")
|
|
SYSTEMS_DB_PATH = os.path.join(_WORKTREE_PARENT, "server", "server", "data", "systems.db")
|
|
OUTPUT_PATH = os.path.join(_PROJECT_ROOT, "client", "data", "star_map_data.json")
|
|
|
|
|
|
def generate() -> dict:
|
|
"""Generate the enriched star map data dict."""
|
|
if not os.path.exists(STAR_MAP_PATH):
|
|
print(f"ERROR: star-map.json not found at {STAR_MAP_PATH}", file=sys.stderr)
|
|
sys.exit(1)
|
|
if not os.path.exists(SYSTEMS_DB_PATH):
|
|
print(f"ERROR: systems.db not found at {SYSTEMS_DB_PATH}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
with open(STAR_MAP_PATH) as f:
|
|
star_map = json.load(f)
|
|
|
|
conn = sqlite3.connect(SYSTEMS_DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
cur = conn.cursor()
|
|
cur.execute(
|
|
"SELECT system_id, proper_name, geographic_sector, geographic_band "
|
|
"FROM star_systems"
|
|
)
|
|
db_lookup = {row["system_id"]: dict(row) for row in cur.fetchall()}
|
|
conn.close()
|
|
|
|
nodes = []
|
|
for n in star_map["nodes"]:
|
|
sid = n["system_id"]
|
|
db = db_lookup.get(sid, {})
|
|
entry = {
|
|
"system_id": sid,
|
|
"proper_name": db.get("proper_name", ""),
|
|
"geographic_sector": db.get("geographic_sector", "unknown"),
|
|
"geographic_band": db.get("geographic_band", ""),
|
|
"gate_topology": n["gate_topology"],
|
|
"aperture_count": n["aperture_count"],
|
|
"gate_connections": n["gate_connections"],
|
|
"hop_distance": n["hop_distance_from_gateway"],
|
|
}
|
|
if n.get("is_gateway"):
|
|
entry["is_gateway"] = True
|
|
nodes.append(entry)
|
|
|
|
nodes.sort(key=lambda x: (x["hop_distance"], x["system_id"]))
|
|
|
|
return {
|
|
"_meta": {
|
|
"generated_from": "star-map.json + systems.db",
|
|
"system_count": len(nodes),
|
|
"edge_count": len(star_map["edges"]),
|
|
"note": "Client-side star map data. Regenerate with: tooling/generate-star-map-data.py",
|
|
},
|
|
"nodes": nodes,
|
|
"edges": star_map["edges"],
|
|
}
|
|
|
|
|
|
def write_output(data: dict, path: str) -> None:
|
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
with open(path, "w") as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
f.write("\n")
|
|
|
|
|
|
def main() -> None:
|
|
check_mode = "--check" in sys.argv
|
|
|
|
data = generate()
|
|
|
|
if check_mode:
|
|
# Generate to temp file and compare against committed JSON
|
|
if not os.path.exists(OUTPUT_PATH):
|
|
print(f"STALE: {OUTPUT_PATH} does not exist — run without --check to generate")
|
|
sys.exit(1)
|
|
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tmp:
|
|
json.dump(data, tmp, indent=2, ensure_ascii=False)
|
|
tmp.write("\n")
|
|
tmp_path = tmp.name
|
|
try:
|
|
with open(tmp_path) as a, open(OUTPUT_PATH) as b:
|
|
if a.read() != b.read():
|
|
print(f"STALE: {OUTPUT_PATH} differs from generated output")
|
|
print("Run: python3 tooling/generate-star-map-data.py")
|
|
sys.exit(1)
|
|
print(f"OK: {OUTPUT_PATH} is up to date")
|
|
finally:
|
|
os.unlink(tmp_path)
|
|
else:
|
|
write_output(data, OUTPUT_PATH)
|
|
print(f"Generated {OUTPUT_PATH}")
|
|
print(f" Nodes: {data['_meta']['system_count']}, Edges: {data['_meta']['edge_count']}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|