工程(真输入化5/7·screen_flow_probe): 14处emit→13处真输入——篝火/窗壳轮转/V6/V7/V8场景命中区push_click_at,二次确认真点_confirm_btn,选档返回/终局继续/生涯返回/清窗返回钮真点,esc返回主菜单真点_return_btn; V5b一处保留emit并注记(V5b被测面=窗开态遮罩挡场景点选,前提只能信号注入); 判据出处注记13条逐段挂(architecture:168互斥判据×2+test-conventions:49 boot组+camp.md:10/22/45×3+存档序列化:61选档+level-map:11/42+battle.md:57+settlement-summary:12); 本步凭据: screen_flow_probe headless直跑PASS exit=0(六步主流程+回退全绿)

This commit is contained in:
DKChan committed 2026-11-06 05:59:53 +08:00
1 parent e0b22f40fb
commit 4f48c40fd5
1 file changed
+27 -14
+27 -14
View File
@@ -69,12 +69,14 @@ func _seals_text(f: Dictionary) -> String:
# ---- 流程状态位(与可见性是两回事,逐步单独判)----
func _expect_adventure_seal(step: String, expect: bool) -> void:
# oracle: design/engineering/architecture/architecture.md:168 三屏壳与呈现装配——屏级互斥与流程状态位判据宿主面(状态位判据组)
var got: bool = main.run_scope != null and main.run_scope.is_adventure
if got != expect:
_problems.append("%s:流程状态位 is_adventure 应为 %s,实测 %s" % [step, str(expect), str(got)])
func _expect_exclusive(step: String, expect: String) -> void:
# oracle: design/engineering/architecture/architecture.md:168 屏壳切换与呈现装配(屏级互斥组)
var f: Dictionary = _screen_seals()
var pairs := [["菜单", "营地"], ["菜单", "冒险"], ["营地", "冒险"], ["终局", "营地"], ["终局", "菜单"]]
for pair in pairs:
@@ -101,6 +103,7 @@ func _frames(n: int = 2) -> void:
# ---- ① boot:菜单独占 ----
func _step_boot_menu() -> void:
# oracle: design/engineering/test-conventions.md:49 调试面发布态恒隐、无 UI 开启口(boot 组)
_expect_exclusive("①boot", "菜单")
_expect_adventure_seal("①boot", false)
if main.ui.modals.menu.debug_overlay != null and main.ui.modals.menu.debug_overlay.visible:
@@ -109,6 +112,7 @@ func _step_boot_menu() -> void:
# ---- ② 菜单 → 营地(真实按钮信号路径)----
func _step_menu_to_camp() -> void:
# oracle: design/gdd/ux/camp.md:10 营地=存档内局外枢纽,存档语境可达(菜单→营地组)
# 营地经进档开层(卡② mn9 新路径——campbtn 已撤;槽模板注入隔离命名空间)
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_camp"):
_problems.append("②菜单→营地:选档层新档钮缺失(新路径驱动中断)")
@@ -119,14 +123,15 @@ func _step_menu_to_camp() -> void:
# ---- ③ 营地 → 菜单(回退路径:篝火二次确认动线——卡④ 营地唯一回菜单出口;选档层随关层收闭同收)----
func _step_camp_back_to_menu() -> void:
# oracle: design/gdd/ux/camp.md:22 篝火=离开营地回主菜单、必须二次确认(营地→菜单组)
if main.ui.modals.camp.scene == null:
_problems.append("③营地→菜单:营地场景根句柄缺失〔句柄子容器批 V1〕")
return
main.ui.modals.camp.scene.object_pressed.emit(&"campfire")
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"campfire").get_center())
await _frames()
if not main.ui.modals.menu.confirm_dialog.visible:
_problems.append("③篝火:二次确认弹窗未现(camp.md v2.2 必须先确认)〔营地图批 V7〕")
main.ui.modals.menu.confirm_dialog.confirmed.emit() # 二次确认离场(confirmed 先于关层——卡④ T4)
ProbeUiUtil.push_click(main, main.ui.modals.menu.confirm_dialog._confirm_btn) # 二次确认离场(confirmed 先于关层——卡④ T4)
await _frames()
_expect_exclusive("③营地→菜单(回退)", "菜单")
@@ -135,6 +140,7 @@ func _step_camp_back_to_menu() -> void:
# ---- 选档界面开合(卡③ sl10):函数直调开层(「进入存档」钮归卡② mn3)→屏级互斥采样→
# 返回钮真实信号路径关闭→ESC 语境不响应(卡⑤ 契约 2 范围外——零实现即断言)。----
func _step_save_select_open_back() -> void:
# oracle: design/gdd/systems/表现与支撑/存档序列化.md:61 激活态由选档界面的「新档」或「进档」建立(选档开合组)
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_savesel", false, false, true)
main.save_manager.slots.attach_slot_template("user://smoke_screen_flow_savesel_slot_%d.json")
var esb: Button = ProbeUiUtil.find_button(main.ui.screens.start_overlay, "进入存档", "prefix")
@@ -150,7 +156,7 @@ func _step_save_select_open_back() -> void:
if back_btn == null:
_problems.append("[savesel] sl10 返回钮缺失(页壳顶条)")
else:
back_btn.pressed.emit()
ProbeUiUtil.push_click(main, back_btn)
await get_tree().process_frame
if main.ui.modals.menu.save_select_overlay.visible or not main.ui.screens.start_overlay.visible:
_problems.append("[savesel] sl10 返回后选档未隐藏或开始层未恢复(关闭链失守)")
@@ -181,6 +187,7 @@ func seals_check_single(f: Dictionary) -> bool:
func _step_menu_to_adventure() -> void:
# oracle: design/gdd/ux/level-map.md:11 入口停点候选数=入口个数(菜单→冒险组)
# 开始冒险钮已随三入口化撤出——函数直调中间态(卡② mn10;卡④ 大门两分支换代)
main._start_adventure_from_menu()
await _frames(3)
@@ -194,6 +201,7 @@ func _step_menu_to_adventure() -> void:
# ---- ⑤ 冒险内屏切换:关卡地图屏 ⇄ 战斗屏(屏内两态,屏级仍独占)----
func _step_level_to_battle_and_back() -> void:
# oracle: design/gdd/ux/battle.md:57 Entry & Exit Points——进出战斗屏(冒险内切换组)
if not main.ui.modals.run.level_screen.visible:
_problems.append("⑤冒险内切换:前置不在关卡地图屏")
return
@@ -213,6 +221,7 @@ func _step_level_to_battle_and_back() -> void:
# ---- ⑥ 放弃 → 终局(放弃路径=回退路径的非正常出口)----
func _step_abandon_to_end() -> void:
# oracle: design/gdd/ux/level-map.md:42 放弃冒险(任意选路停点)→ 冒险落幕(放弃→终局组)
if main.run_scope == null or main.run_scope.adventure == null:
_problems.append("⑥放弃→终局:前置无冒险实例")
return
@@ -225,10 +234,11 @@ func _step_abandon_to_end() -> void:
# ---- ⑦ 终局 → 菜单(终局出口返回开始界面)----
func _step_end_back_to_menu() -> void:
# oracle: design/gdd/ux/settlement-summary.md:12 冒险总结结算=冒险落幕时终局覆盖层(终局→菜单组)
if main.ui.modals.run.end_overlay == null or not main.ui.modals.run.end_overlay.visible:
_problems.append("⑦终局→菜单:前置不在终局")
return
main.ui.modals.run.end_overlay.continue_pressed.emit()
ProbeUiUtil.push_click(main, main.ui.modals.run.end_overlay._btn) # 真点继续钮(_btn 唯一钮——ui_click_probe:543 同源)
await _frames(3)
_expect_exclusive("⑦终局→菜单", "菜单")
if main.run_scope != null and main.run_scope.is_adventure:
@@ -237,6 +247,7 @@ func _step_end_back_to_menu() -> void:
# ---- ③' 营地 Esc 浮窗+HUD(卡⑤——真实键盘合成路径 push_input;四态路由+三出口+语境分支+余额单口)----
func _step_camp_esc_and_hud() -> void:
# oracle: design/gdd/ux/camp.md:45 ESC 优先序:有功能窗口先关最上层窗,无窗才进 ESC 浮窗(Esc 段组)
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_esc", false, false, true)
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_esc"):
_problems.append("[esc] 营地入口缺失(选档层新档钮驱动中断)〔ESC批 V1〕")
@@ -254,7 +265,7 @@ func _step_camp_esc_and_hud() -> void:
await _frames()
if main.ui.modals.camp.esc_overlay.visible:
_problems.append("[esc] echo 事件唤起浮窗(触发沿 pressed 且非 echo 失守)〔ESC批 V1〕")
main.ui.modals.camp.scene.object_pressed.emit(&"dummy") # 子界面开态
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"dummy").get_center()) # 子界面开态
await _frames()
_push_esc()
await _frames()
@@ -285,7 +296,7 @@ func _step_camp_esc_and_hud() -> void:
if not main.ui.modals.camp.esc_overlay.visible or main.ui.screens.start_overlay.visible:
_problems.append("[esc] 关设置后未回浮窗或回弹主菜单(契约 3 语境分支失守)〔ESC批 V4〕〔ESC批 B3〕")
# 返回主菜单动线(契约 4——浮窗自收+营地隐+选档收+菜单显)
main.ui.modals.camp.esc_overlay.return_requested.emit()
ProbeUiUtil.push_click(main, main.ui.modals.camp.esc_overlay._return_btn) # 真点返回主菜单钮(camp_esc_overlay 底栏钮)
await _frames()
if main.ui.modals.camp.esc_overlay.visible or main.ui.modals.camp.scene.visible or main.ui.modals.menu.save_select_overlay.visible or not main.ui.screens.start_overlay.visible:
_problems.append("[esc] 返回主菜单动线失守(浮窗自收/营地隐/选档收/菜单显)〔ESC批 V3〕〔ESC批 B3〕")
@@ -300,6 +311,7 @@ func _step_camp_esc_and_hud() -> void:
# 判的是呈现形态换壳(近全屏面板→居中定尺寸窗壳 720×640):窗几何/场景根留底/遮罩 0.6/关闭钮/
# 互斥单开/ESC 优先序/窗内滚动/生涯同壳——行为面(开合路由)零改,只钉窗壳可观测提交面。
func _step_camp_window_shell() -> void:
# oracle: design/gdd/ux/camp.md:45 五功能窗统一窗壳、五窗互斥单开、各窗自带关闭钮(窗壳 V1–V8 组)
ProbeUiUtil.isolate_save(main, "smoke_screen_flow_winshell", false, false, true)
if not await ProbeUiUtil.open_camp_via_savesel(main, "smoke_screen_flow_winshell"):
_problems.append("[winshell] 营地入口缺失(选档层新档钮驱动中断)〔窗口化批 V1〕")
@@ -323,11 +335,11 @@ func _step_camp_window_shell() -> void:
if prev_back == null:
_problems.append("[winshell] %s 底栏「返回营地」钮缺失〔窗口化批 V4〕" % String(opened.back()))
else:
prev_back.pressed.emit()
ProbeUiUtil.push_click(main, prev_back)
await _frames()
if prev.visible or not main.ui.modals.camp.scene.visible:
_problems.append("[winshell] %s 关闭钮按下未隐窗或场景根失守〔窗口化批 V4〕" % String(opened.back()))
main.ui.modals.camp.scene.object_pressed.emit(k)
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(k).get_center())
await _frames()
opened.append(k)
var view: Control = views[k]
@@ -362,7 +374,7 @@ func _step_camp_window_shell() -> void:
if vis_n != 1:
_problems.append("[winshell] %s 开态五窗 visible 计数=%d 应=1(互斥单开失守)〔窗口化批 V5〕" % [String(k), vis_n])
# 树窗点选遮挡(V5b——树窗开态向锻炉命中区推真实鼠标点:被遮罩挡=零新窗零响应)
main.ui.modals.camp.scene.object_pressed.emit(&"dummy")
main.ui.modals.camp.scene.object_pressed.emit(&"dummy") # 前提注入(保留 emit):V5b 被测面=窗开态遮罩挡场景点选——真点击会被遮罩吞掉,树窗开态只能信号注入建立
await _frames()
var tree_view: Control = views[&"dummy"]
if not tree_view.visible:
@@ -383,7 +395,7 @@ func _step_camp_window_shell() -> void:
# 随栈 close 恢复语义逐层清账,V6/V8 从干净单窗态起步)
await _close_all_windows(views)
# V6 ESC 先关窗(生涯窗开态 Esc→关生涯窗、浮窗不唤起)
main.ui.modals.camp.scene.object_pressed.emit(&"notebook")
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"notebook").get_center())
await _frames()
if not career.visible:
_problems.append("[winshell] 生涯窗未开(V6 前置中断)〔窗口化批 V6〕")
@@ -395,7 +407,7 @@ func _step_camp_window_shell() -> void:
if main.ui.modals.camp.esc_overlay.visible:
_problems.append("[winshell] 关窗同拍唤起浮窗(应无窗才进浮窗)〔窗口化批 V6〕")
# V7 内容超高窗内滚动(树窗+真实投影喂加长行册)
main.ui.modals.camp.scene.object_pressed.emit(&"dummy")
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"dummy").get_center())
await _frames()
if not tree_view.visible:
_problems.append("[winshell] 树窗未开(V7 前置中断)〔窗口化批 V7〕")
@@ -420,7 +432,7 @@ func _step_camp_window_shell() -> void:
# 清窗经真实钮(同 V6 前置——干净单窗态起步)
await _close_all_windows(views)
# V8 生涯同壳(窗板同几何+返回钮在位+内容列滚动面在)
main.ui.modals.camp.scene.object_pressed.emit(&"notebook")
ProbeUiUtil.push_click_at(main, main.ui.modals.camp.scene.get_hotspot_rect(&"notebook").get_center())
await _frames()
if not career.visible:
_problems.append("[winshell] 生涯窗未开(V8 前置中断)〔窗口化批 V8〕")
@@ -445,7 +457,7 @@ func _step_camp_window_shell() -> void:
# 段尾收闭:生涯窗经真实「返回」钮关闭(on_camp_closed 关闭名单不含生涯窗——防残留泄段)
var career_back: Button = ProbeUiUtil.find_button(career, "返回", "prefix")
if career_back != null:
career_back.pressed.emit()
ProbeUiUtil.push_click(main, career_back)
await _frames()
if career.visible:
_problems.append("[winshell] 生涯「返回」钮未隐窗〔窗口化批 V4〕")
@@ -455,6 +467,7 @@ func _step_camp_window_shell() -> void:
# 清窗经真实钮(逐窗巡检 visible→钮 pressed——栈 close 恢复账随层清空)
func _close_all_windows(views: Dictionary) -> void:
# oracle: design/gdd/ux/camp.md:45 各窗自带关闭钮(清窗组)
for k: StringName in [&"forge", &"chest", &"dummy", &"board"]:
var w: Control = views[k]
if not w.visible:
@@ -463,7 +476,7 @@ func _close_all_windows(views: Dictionary) -> void:
if back == null:
_problems.append("[winshell] %s 底栏「返回营地」钮缺失〔窗口化批 V4〕" % String(k))
continue
back.pressed.emit()
ProbeUiUtil.push_click(main, back)
await _frames()