feat(ui): star map insert module — concentric hop-ring view (#674)
New StarMapRenderer: 301 systems in concentric hop-rings from player location, sector-colored, click-to-select with info panel, pan/zoom. Integrated into HUD (hidden by default), insert state propagation wired in main.gd. Data enriched from systems.db + star-map.json via tooling/generate-star-map-data.py regeneration script. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate client/data/star_map_data.json from star-map.json + systems.db.
|
||||
|
||||
Run from the project root (any worktree):
|
||||
python3 tooling/generate-star-map-data.py
|
||||
|
||||
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
|
||||
|
||||
|
||||
def find_file(candidates: list[str]) -> str | None:
|
||||
for p in candidates:
|
||||
if os.path.exists(p):
|
||||
return p
|
||||
return None
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Find star-map.json
|
||||
star_map_path = find_file([
|
||||
"docs/design/star-map.json",
|
||||
"../docs/design/star-map.json",
|
||||
"../../docs/design/star-map.json",
|
||||
])
|
||||
if not star_map_path:
|
||||
print("ERROR: docs/design/star-map.json not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Find systems.db
|
||||
db_path = find_file([
|
||||
"server/server/data/systems.db",
|
||||
"../server/server/data/systems.db",
|
||||
"../../server/server/data/systems.db",
|
||||
])
|
||||
if not db_path:
|
||||
print("ERROR: server/server/data/systems.db not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Load star map topology
|
||||
with open(star_map_path) as f:
|
||||
star_map = json.load(f)
|
||||
|
||||
# Load DB data
|
||||
conn = sqlite3.connect(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()
|
||||
|
||||
# Merge
|
||||
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"]))
|
||||
|
||||
output = {
|
||||
"_meta": {
|
||||
"generated_from": f"{star_map_path} + {db_path}",
|
||||
"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"],
|
||||
}
|
||||
|
||||
# Write output
|
||||
out_path = find_file(["client/data"]) or "client/data"
|
||||
os.makedirs(out_path, exist_ok=True)
|
||||
out_file = os.path.join(out_path, "star_map_data.json")
|
||||
with open(out_file, "w") as f:
|
||||
json.dump(output, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"Generated {out_file}")
|
||||
print(f" Nodes: {len(nodes)}, Edges: {len(star_map['edges'])}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user