From 4e4433a41973440d2f2c3d3f2bb62cb825d42895 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 14 May 2026 21:37:32 -0700 Subject: [PATCH] =?UTF-8?q?feat(api-gdext):=20=E2=9C=A8=20expose=20upgrade?= =?UTF-8?q?=20target=20bridge=20to=20Godot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../objectives/p1-43c-gdext-upgrade-target.md | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/.project/objectives/p1-43c-gdext-upgrade-target.md b/.project/objectives/p1-43c-gdext-upgrade-target.md index 1de3b6f9..af776e4f 100644 --- a/.project/objectives/p1-43c-gdext-upgrade-target.md +++ b/.project/objectives/p1-43c-gdext-upgrade-target.md @@ -25,19 +25,30 @@ academy). The inverse index lives naturally next to `BuildingRegistry` in - ✓ `crates/mc-city/src/building.rs` — `BuildingRegistry` builds an `upgrade_target: HashMap` inverse index over `requires_existing` - at construction time (one pass, deterministic). + at construction time (one pass, deterministic). Evidence: + `src/simulator/crates/mc-city/src/building.rs:425` references the bridge. - ✓ `crates/mc-city/src/building.rs` — `BuildingRegistry::get_upgrade_target(&self, building_id: &str) -> Option<&str>` - returns the successor's `id`, or `None` when no successor exists. -- ✓ `src/simulator/api-gdext/src/` — new `building_registry.rs` (or fold into - `building_action.rs`) exposes `GdBuildingRegistry` as a GodotClass with + returns the successor's `id`, or `None` when no successor exists. Evidence: + Rust unit test `registry_get_upgrade_target_returns_successor_id` in + `src/simulator/api-gdext/src/building_registry.rs:106` exercises both arms. +- ✓ `src/simulator/api-gdext/src/building_registry.rs` exposes + `GdBuildingRegistry` as a `GodotClass` with `#[func] fn get_upgrade_target(building_id: GString) -> GString` returning - `""` for no-successor. Registered in `lib.rs`. -- ✓ `src/game/engine/ui/city/city_detail_formatter.gd` (and - `src/game/engine/ui/encyclopedia/encyclopedia_panel.gd`) call the bridge and - render "Can be upgraded to: " when the bridge returns a non-empty id. -- ✓ GUT test `src/game/engine/tests/test_building_upgrade_target_bridge.gd` - verifies bridge returns `"infantry"` for `barracks` and `""` for terminal - buildings. + `""` for no-successor (lines 86–92). +- ✓ `src/game/engine/scenes/city/city_detail_formatter.gd::_upgrade_target_line` + and `src/game/engine/scenes/encyclopedia/encyclopedia_panel.gd::_building_upgrade_target_line` + call the bridge via `ClassDB.instantiate("GdBuildingRegistry")` + `insert_json` + + `get_upgrade_target` and render "Can be upgraded to: " when the + bridge returns a non-empty id. Both early-return `""` if the GDExtension is + not loaded so headless GUT runs stay green. (Path note: objective text said + `engine/ui/...`; canonical scene path is `engine/scenes/...` per + `gdscript-conventions.md`.) +- ✓ GUT test `src/game/engine/tests/unit/test_building_upgrade_target_bridge.gd` + asserts `get_upgrade_target("barracks") == "infantry"`, + `get_upgrade_target("infantry") == ""`, and unknown-id → `""`. Headless + run on apricot (worktree `~/.cache/mc-src-20260514_181147`): + `flatpak run … gut_cmdln.gd -gtest=res://engine/tests/unit/test_building_upgrade_target_bridge.gd -gexit` + → **4/4 passed**. ## Out of scope