Files
Bryce c24709d02d docs: update room navigator skill with correct get_current_room_name method
Replace raw eval JSON with godot_game_call_method for checking current room,
matching the actual Godot MCP tool interface used in practice.
2026-04-29 16:18:02 -07:00

8.4 KiB

name: kq4-room-navigator description: Navigate between KQ4 rooms using the Godot MCP server. BFS pathfinds through room transition graph, then the agent navigates McpInteractionServer (port 9090). Use when planning navigation between any two rooms or simulating player movement through the game world at runtime. Trigger phrases: "navigate from", "go to room", "path from X to Y", "walk to", "how do I get to room", "room navigation".

KQ4 Room Navigator

Overview

This skill finds shortest paths between rooms and can execute them through the running game using Godot's MCP server. It combines offline .tscn file parsing for graph construction with runtime interaction via McpInteractionServer (TCP port 9090).

The room transition system uses TransitionPiece nodes: each has an exit_node_name (destination), a polygon, and connects rooms typically bidirectionally. Clicking a TransitionPiece triggers a 3-step animation (walk → fade/swap scenes → walk to entrance in new room).

When to Use

  • Planning multi-room navigation paths
  • Verifying room connectivity
  • Debugging why a path can't be traversed
  • Automating room transitions during testing

How It Works

.scenes/*.tscn files → adjacency graph (96 rooms, 233 exits) → BFS pathfinding  → use MCP for execution

Room identification at runtime:

  • Game node tree: /root/Node2D/SceneViewport/background (always named "background")
  • Room identity comes from background.get_script().resource_path (e.g., res://scenes/kq4_010_forest_path/kq4_010_forest_path.gd)
  • TransitionPiece children have .target UIDs and .label strings for cross-referencing

Getting the current room name at runtime

The canonical way is via MainGame.get_current_room_name():

Use godot_game_call_method to call it directly on the node path:

Call method get_current_room_name on /root/Node2D

Returns a string like "kq4_010_forest_path". The implementation extracts the filename from the scene script's resource path (script_path.trim_suffix(".gd").get_file()), NOT the node name (which is always "background").

Quick Start

Step 1 — Make a plan:

python tools/kq4_room_navigator.py --from kq4_003_fountain_pool --to kq4_011_enchanted_grove

Output:

Path: kq4_003_fountain_pool → kq4_011_enchanted_grove (3 steps)
  1. Click 'kq4_004_ogres_cottage' in kq4_003_fountain_pool → kq4_004_ogres_cottage [Ogre's Cottage] (click at: 1874, 714)
  2. Click 'kq4_010_forest_path' in kq4_004_ogres_cottage → kq4_010_forest_path [Forest Path] (click at: 1042, 1078)
  3. Click 'kq4_011_enchanted_grove' in kq4_010_forest_path → kq4_011_enchanted_grove [Enchanted Grove] (click at: 1898, 610)

The click coordinates are not used — the exit_node_name is what matters.

Step 2 — Launch and navigate

  1. Use the Godot MCP to start the game (godot_run_project)
  2. Poll room name to verify starting room:
    get_tree().root.get_node('Node2D').get_current_room_name()
    
  3. For each step, call mock_interact(0) on the TransitionPiece node (see exact method name below)
  4. Wait and poll until get_current_room_name() returns the expected destination
  5. Repeat for next step

Detailed Navigation Protocol

Identify current room

{"command": "eval", "params": {"code": "get_tree().root.get_node('Node2D').get_current_room_name()"}}

Returns "kq4_0xx_room_name", confirming both MCP connectivity and which room you're in.

Discover available exits from current room

Use the set-piece group to find all interactive polygons (TransitionPieces are automatically added):

{"command": "get_nodes_in_group", "params": {"group": "set-piece"}}

Filter results for node names starting with kq4_0 — these are transition exits.

Trigger a room transition

Critical: The method name is mock_interact, NOT mock_interaction.

Use godot_game_call_method to call it directly on the node path:

Call method mock_interact(0) on /root/Node2D/SceneViewport/background/<exit_node_name>

Argument 0 = ActionState.Action.WALK (1=LOOK, 2=TOUCH, 3=TALK).

Waiting — MCP busy protocol

IMPORTANT: Walk animations block the McpInteractionServer for ~30 seconds. During this time:

  • eval, wait, call_method all fail with "timed out after 30s"
  • The server has a built-in _busy flag auto-reset after ~30s ("_busy flag stuck for 30.Xs, force-resetting")

Robust polling pattern:

  1. Call mock_interact(0) on the target node (returns immediately, animation starts)
  2. Try wait(frames=30) then poll room name
  3. If both timeout (~30s elapsed), retry the room name poll once more
  4. The server will auto-reset and the next poll will succeed

Expected timing per transition: ~45-75 seconds total (walk ~15s, MCP block ~30s, fade-in ~5s, confirm ~2s)

Finding transitions by script handler

In room .gd files, handlers like _on_ogres_cottage_interacted() reference the TransitionPiece node ($kq4_004_ogres_cottage.default_script(self)). The handler's parameter name matches the node name you need to call mock_interact(0) on.

Room Graph Structure

The graph currently has:

  • 96 rooms across 23 connected components
  • Largest component: 36 rooms (starting from room 3 Fountain Pool)
  • Second largest: 17 rooms (room 1 Beach area)
  • Two additional 36-room components that are disconnected due to UID mismatches

Use python scripts/build_room_graph.py --from A --to B to find a path. If "no path" is returned but rooms feel like they should connect, the cause is likely a stale UID (see Common Issues).

UID mismatch example

Room kq4_018_cemetery has UID uid://b3fjmiaribbrl, but nearby rooms point to it with stale UIDs (uid://35amqvpjgpf2x). Runtime navigation works fine (Transitions use file paths), but the graph can't find the connection.

Common Issues

Problem Diagnosis Fix
mock_interaction method not found Wrong method name Use mock_interact(0) — no trailing "tion"
MCP commands time out during transition Walk animation blocks server (~30s) Wait and retry; server auto-resets after ~30s
"No path" between adjacent rooms at graph level Target UID in source .tscn doesn't match destination room's .uid file Runtime still works. Fix the target uid in the source tscn or update the destination room's .uid
get_current_room_name() returns "background" Old implementation used scene.name Updated to use script_path.trim_suffix(".gd").get_file()

Verified Navigation Example

Successfully tested navigating from kq4_003_fountain_pool to kq4_018_cemetery via 5 transitions:

kq4_003_fountain_pool     → mock_interact(kq4_004_ogres_cottage)      → kq4_004_ogres_cottage       ✓
kq4_004_ogres_cottage     → mock_interact(kq4_010_forest_path)        → kq4_010_forest_path         ✓
kq4_010_forest_path       → mock_interact(kq4_011_enchanted_grove)    → kq4_011_enchanted_grove     ✓
kq4_011_enchanted_grove   → mock_interact(kq4_017_spooky_house_exterior) → kq4_017_spooky_house_exterior ✓
kq4_017_spooky_house_exterior → mock_interact(kq4_018_cemetery)        → kq4_018_cemetery           ✓

API Reference

build_room_graph.py module

from pathlib import Path
from scripts.build_room_graph import build_graph, find_path, NavigationStep

graph = build_graph(Path('scenes'))                         # RoomInfo dict keyed by room name
steps = find_path(graph, "kq4_003_fountain_pool", "kq4_018_cemetery")  # List[NavigationStep] or None
step.from_room          # Source room name
step.exit_node_name     # TransitionPiece node to call mock_interact(0) on
step.to_room            # Destination room name
step.label              # Human-readable label (e.g., "Ogre's Cottage")

kq4_room_navigator.py CLI

python tools/kq4_room_navigator.py --from ROOM --to ROOM
# For graph summary:
python tools/kq4_room_navigator.py summary

Key Files

File Purpose
MainGame.gd Root game node; get_current_room_name() returns room from script path
tools/kq4_room_navigator.py CLI combining graph + BFS + MCP navigation
scripts/build_room_graph.py Room adjacency graph builder + BFS pathfinding
TransitionPiece.gd Exit nodes; mock_interact(action) triggers default_script()
SetPiece_.gd Base interactive polygon class (class_name SetPiece)
.opencode/skills/kq4-room-creator/SKILL.md Related: creating new rooms with transitions