diff --git a/client/scripts/main.gd b/client/scripts/main.gd index 57bc70b..bfe9e7a 100644 --- a/client/scripts/main.gd +++ b/client/scripts/main.gd @@ -67,3 +67,28 @@ func _on_move_rejected(reason_code: String) -> void: _move_reject_label.text = "", CONNECT_ONE_SHOT ) + + +## Dev smoke (NEON-28 occluder purge): **F9** frees `Obstacle` while testing; remove when no longer needed. +## After removing nav source geometry, we **rebake** — otherwise `NavigationAgent3D` keeps a stale map +## and click-to-move can stop working. +func _unhandled_key_input(event: InputEvent) -> void: + if not event is InputEventKey: + return + var k := event as InputEventKey + if k.pressed and not k.echo and k.keycode == KEY_F9: + var obstacle := get_node_or_null("World/NavigationRegion3D/Obstacle") + if obstacle: + obstacle.queue_free() + call_deferred("_rebake_nav_mesh_after_obstacle_removed") + + +func _rebake_nav_mesh_after_obstacle_removed() -> void: + _nav_region.bake_navigation_mesh(false) + await get_tree().physics_frame + await get_tree().physics_frame + if not is_instance_valid(_player): + return + var na := _player.get_node_or_null("NavigationAgent3D") as NavigationAgent3D + if na != null: + na.set_target_position(_player.global_position) diff --git a/docs/plans/NEON-28-implementation-plan.md b/docs/plans/NEON-28-implementation-plan.md index 51e9ea6..7f34acf 100644 --- a/docs/plans/NEON-28-implementation-plan.md +++ b/docs/plans/NEON-28-implementation-plan.md @@ -106,7 +106,7 @@ Jira acceptance criteria (verbatim intent): **Manual verification:** Main scene — zoom bands, occlusion fade, fixed yaw UX; spot-check Slice 2 behaviors (readable motion, occlusion active). -**Freed occluder (end-to-end, editor):** Position player so `Obstacle` is between camera and player (fade active), then `queue_free` the occluder (remote inspector or one-shot script). Expect **no** recurring script errors and **no** stuck transparent materials on other meshes. **Smoke-tested on the story branch in-editor (2026-04-10)** before merge handoff — complements static `occluder_override_key_is_valid` tests, which do not execute the full purge path in CI. +**Freed occluder (end-to-end, editor):** Position player so `Obstacle` is between camera and player (fade active), then `queue_free` the occluder. Expect **no** recurring script errors and **no** stuck transparent materials on other meshes. **`Obstacle` lives under `NavigationRegion3D`** — after removing it, **rebake** the nav mesh (see **`main.gd` F9** dev path: `bake_navigation_mesh(false)` + refresh `NavigationAgent3D` target) or click-to-move can stop until the next full scene reload. Complements static `occluder_override_key_is_valid` tests, which do not execute the full purge path in CI. ## Open questions / risks