#!/usr/bin/env python3 """KQ4 Room Navigator — BFS pathfinding + MCP runtime navigation. Uses file parsing to build a room adjacency graph, finds shortest paths via BFS, then optionally uses the Godot MCP server (port 9090) to execute the navigation step by step with click coordinates computed from TransitionPiece polygons. Usage: # Just print the path plan: python tools/kq4_room_navigator.py --from kq4_001_beach --to kq4_092_lolottes_throne_room # Navigate with MCP (game must be running): python tools/kq4_room_navigator.py --from kq4_003_fountain_pool --to kq4_010_forest_path --navigate # Just print graph summary: python tools/kq4_room_navigator.py --summary """ import argparse import json import sys import time from pathlib import Path # Add project root to path for imports _project_root = Path(__file__).resolve().parent.parent sys.path.insert(0, str(_project_root)) sys.path.insert(0, str(_project_root / "tools")) sys.path.insert(0, str(_project_root / "scripts")) from build_room_graph import ( NavigationStep, build_graph, find_path, find_and_print_path, ) BACKGROOM_PATH = "/root/Node2D/SceneViewport/background" class NavigationError(Exception): pass def main() -> None: parser = argparse.ArgumentParser( description="KQ4 Room Navigator — plan and execute room-to-room navigation" ) parser.add_argument("--from", dest="from_room", help="Starting room name (e.g., kq4_003_fountain_pool)") parser.add_argument("--to", dest="to_room", help="Destination room name") parser.add_argument("--summary", action="store_true", help="Print room graph summary") args = parser.parse_args() scenes_dir = _project_root / "scenes" if not scenes_dir.exists(): print(f"ERROR: Scenes directory not found at {scenes_dir}", file=sys.stderr) sys.exit(1) graph = build_graph(scenes_dir) if args.summary: from build_room_graph import print_graph_summary print_graph_summary(graph) return if not (args.from_room and args.to_room): parser.print_help() return steps = find_path(graph, args.from_room, args.to_room) if steps is None: from build_room_graph import find_and_print_path find_and_print_path(graph, args.from_room, args.to_room) sys.exit(1) # Print path plan print(f"\nPath: {args.from_room} → {args.to_room} ({len(steps)} steps)\n") for i, step in enumerate(steps): cx, cy = step.viewport_centroid() coord_note = f" (click at: {cx:.0f}, {cy:.0f})" if step.polygon else "" print( f" {i + 1}. Click '{step.exit_node_name}' " f"in {step.from_room} → {step.to_room} [{step.label}]{coord_note}" ) if __name__ == "__main__": main()