3 KiB
3 KiB
| id | title | priority | status | scope | parent | created_at | updated_at |
|---|---|---|---|---|---|---|---|
| p1-43c-gdext-upgrade-target | api-gdext bridge — GdBuildingRegistry::get_upgrade_target for city UI upgrade surface | p1 | done | game1 | p1-43c | 2026-05-14 | 2026-05-14 |
Summary
Expose a Rust→Godot bridge that lets the city UI / encyclopedia display the
upgrade successor of any building without forcing GDScript to walk an inverse
scan over DataLoader.get_all_buildings() (a Rail-3 violation: GDScript would
be deriving a join that belongs in the simulation layer).
Source field is requires_existing on building JSON (e.g. academy_of_sciences
declares requires_existing: "university" → university's successor is the
academy). The inverse index lives naturally next to BuildingRegistry in
crates/mc-city/src/building.rs.
Acceptance
- ✓
crates/mc-city/src/building.rs—BuildingRegistrybuilds anupgrade_target: HashMap<String, String>inverse index overrequires_existingat construction time (one pass, deterministic). Evidence:src/simulator/crates/mc-city/src/building.rs:425references the bridge. - ✓
crates/mc-city/src/building.rs—BuildingRegistry::get_upgrade_target(&self, building_id: &str) -> Option<&str>returns the successor'sid, orNonewhen no successor exists. Evidence: Rust unit testregistry_get_upgrade_target_returns_successor_idinsrc/simulator/api-gdext/src/building_registry.rs:106exercises both arms. - ✓
src/simulator/api-gdext/src/building_registry.rsexposesGdBuildingRegistryas aGodotClasswith#[func] fn get_upgrade_target(building_id: GString) -> GStringreturning""for no-successor (lines 86–92). - ✓
src/game/engine/scenes/city/city_detail_formatter.gd::_upgrade_target_lineandsrc/game/engine/scenes/encyclopedia/encyclopedia_panel.gd::_building_upgrade_target_linecall the bridge viaClassDB.instantiate("GdBuildingRegistry")+insert_jsonget_upgrade_targetand 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 saidengine/ui/...; canonical scene path isengine/scenes/...pergdscript-conventions.md.)
- ✓ GUT test
src/game/engine/tests/unit/test_building_upgrade_target_bridge.gdassertsget_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
- AI scoring of upgrade chains (lives in mc-ai, tracked by p1-42).
- Multi-step (>2-deep) chain rendering in UI; current ladders are 3-step and one "successor" hop is sufficient per row.
- Hybrid Merged Structures (p1-59).
Blockers
- None known. Inverse index is a pure derivation over existing JSON data.