Merge remote-tracking branch 'origin/sprint-31/client'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate client/data/star_map_data.json from star-map.json + systems.db.
|
||||
"""Generate client/data/star_map_data.json from star-map.json + systems.db + wiki.
|
||||
|
||||
Run from any directory — paths are resolved relative to this script's location:
|
||||
python3 tooling/generate-star-map-data.py
|
||||
@@ -8,6 +8,7 @@ Run from any directory — paths are resolved relative to this script's location
|
||||
Sources:
|
||||
docs/design/star-map.json — graph topology (nodes + edges)
|
||||
server/server/data/systems.db — proper names, geographic sectors
|
||||
wiki/star-systems/ — star type, bodies, population, GTTR excerpt
|
||||
|
||||
Output:
|
||||
client/data/star_map_data.json — self-contained client data for the star map UI
|
||||
@@ -15,6 +16,7 @@ Output:
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -31,9 +33,95 @@ _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")
|
||||
WIKI_PATH = os.path.join(_PROJECT_ROOT, "wiki", "star-systems")
|
||||
OUTPUT_PATH = os.path.join(_PROJECT_ROOT, "client", "data", "star_map_data.json")
|
||||
|
||||
|
||||
def system_id_to_wiki_slug(system_id: str) -> str:
|
||||
"""Convert system_id to wiki folder slug. 'GJ 71' → 'GJ-71'."""
|
||||
return system_id.replace(" ", "-")
|
||||
|
||||
|
||||
def parse_wiki_index(system_id: str) -> dict:
|
||||
"""Extract star type, bodies summary, and population from index.md.
|
||||
|
||||
Returns dict with keys: star_type, bodies, population (all strings, may be empty).
|
||||
"""
|
||||
slug = system_id_to_wiki_slug(system_id)
|
||||
path = os.path.join(WIKI_PATH, slug, "index.md")
|
||||
result = {"star_type": "", "bodies": "", "population": ""}
|
||||
if not os.path.exists(path):
|
||||
return result
|
||||
with open(path, encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
# Star row: | **Star** | G8V · 11.9 ly |
|
||||
m = re.search(r"\|\s*\*\*Star\*\*\s*\|\s*([^|]+?)\s*\|", content)
|
||||
if m:
|
||||
raw = m.group(1).strip()
|
||||
# Extract spectral class — everything before " ·" or end of string
|
||||
star_type = raw.split("·")[0].strip()
|
||||
result["star_type"] = star_type
|
||||
|
||||
# Bodies row: | **Bodies** | 2 habitable · 3 inhabited |
|
||||
m = re.search(r"\|\s*\*\*Bodies\*\*\s*\|\s*([^|]+?)\s*\|", content)
|
||||
if m:
|
||||
result["bodies"] = m.group(1).strip()
|
||||
|
||||
# Population row: | **Population** | 1,200,000,000 |
|
||||
m = re.search(r"\|\s*\*\*Population\*\*\s*\|\s*([^|]+?)\s*\|", content)
|
||||
if m:
|
||||
result["population"] = m.group(1).strip()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def parse_gttr_excerpt(system_id: str) -> str:
|
||||
"""Extract the first body paragraph from gttr.md as the GTTR excerpt."""
|
||||
slug = system_id_to_wiki_slug(system_id)
|
||||
path = os.path.join(WIKI_PATH, slug, "gttr.md")
|
||||
if not os.path.exists(path):
|
||||
return ""
|
||||
with open(path, encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# Skip the H1 heading line, then find the first non-empty paragraph
|
||||
in_content = False
|
||||
paragraph_lines = []
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if not in_content:
|
||||
# Skip heading and blank lines at start
|
||||
if stripped.startswith("# "):
|
||||
in_content = True
|
||||
continue
|
||||
if not stripped:
|
||||
# Blank line ends the paragraph if we've collected lines
|
||||
if paragraph_lines:
|
||||
break
|
||||
else:
|
||||
if not stripped.startswith("#"):
|
||||
paragraph_lines.append(stripped)
|
||||
|
||||
return " ".join(paragraph_lines)
|
||||
|
||||
|
||||
def build_adjacency(edges: list) -> dict:
|
||||
"""Build a map from system_id to list of adjacent system_ids from edges."""
|
||||
adj: dict = {}
|
||||
for edge in edges:
|
||||
if len(edge) < 2:
|
||||
continue
|
||||
a, b = edge[0], edge[1]
|
||||
adj.setdefault(a, [])
|
||||
adj.setdefault(b, [])
|
||||
if b not in adj[a]:
|
||||
adj[a].append(b)
|
||||
if a not in adj[b]:
|
||||
adj[b].append(a)
|
||||
return adj
|
||||
|
||||
|
||||
def generate() -> dict:
|
||||
"""Generate the enriched star map data dict."""
|
||||
if not os.path.exists(STAR_MAP_PATH):
|
||||
@@ -56,10 +144,21 @@ def generate() -> dict:
|
||||
db_lookup = {row["system_id"]: dict(row) for row in cur.fetchall()}
|
||||
conn.close()
|
||||
|
||||
adjacency = build_adjacency(star_map["edges"])
|
||||
|
||||
nodes = []
|
||||
wiki_hits = 0
|
||||
gttr_hits = 0
|
||||
for n in star_map["nodes"]:
|
||||
sid = n["system_id"]
|
||||
db = db_lookup.get(sid, {})
|
||||
wiki = parse_wiki_index(sid)
|
||||
gttr = parse_gttr_excerpt(sid)
|
||||
if wiki["star_type"]:
|
||||
wiki_hits += 1
|
||||
if gttr:
|
||||
gttr_hits += 1
|
||||
|
||||
entry = {
|
||||
"system_id": sid,
|
||||
"proper_name": db.get("proper_name", ""),
|
||||
@@ -69,16 +168,28 @@ def generate() -> dict:
|
||||
"aperture_count": n["aperture_count"],
|
||||
"gate_connections": n["gate_connections"],
|
||||
"hop_distance": n["hop_distance_from_gateway"],
|
||||
"adjacent_systems": adjacency.get(sid, []),
|
||||
}
|
||||
if wiki["star_type"]:
|
||||
entry["star_type"] = wiki["star_type"]
|
||||
if wiki["bodies"]:
|
||||
entry["bodies"] = wiki["bodies"]
|
||||
if wiki["population"]:
|
||||
entry["population"] = wiki["population"]
|
||||
if gttr:
|
||||
entry["gttr_excerpt"] = gttr
|
||||
if n.get("is_gateway"):
|
||||
entry["is_gateway"] = True
|
||||
nodes.append(entry)
|
||||
|
||||
nodes.sort(key=lambda x: (x["hop_distance"], x["system_id"]))
|
||||
|
||||
print(f" Wiki index data: {wiki_hits}/{len(nodes)} systems")
|
||||
print(f" GTTR excerpts: {gttr_hits}/{len(nodes)} systems")
|
||||
|
||||
return {
|
||||
"_meta": {
|
||||
"generated_from": "star-map.json + systems.db",
|
||||
"generated_from": "star-map.json + systems.db + wiki/star-systems",
|
||||
"system_count": len(nodes),
|
||||
"edge_count": len(star_map["edges"]),
|
||||
"note": "Client-side star map data. Regenerate with: tooling/generate-star-map-data.py",
|
||||
|
||||
Reference in New Issue
Block a user