## VERTICAL SLICE - NOT FOR PRODUCTION ## 组合根调试流程承接件:调试浮窗开合与上下文同步、批量模拟入口、两层调试对局起手、诊断转储。 ## 本件是 main.gd 同名函数的逐字搬运(成员访问改 root 前缀)——main 侧留同名薄委托,探针 main.X 路径零改动。 ## 调试会话状态机归 debug_session.gd;本件只接线与出 UI,零成员态。 extends RefCounted static func _on_diagnose_pressed(root: Variant) -> void: # 本局种子现值走 _current_master_seed 只读单点 var ctx := {"mode": "level" if root.run_scope.level_active else "debug", "seed": root._current_master_seed()} if root.run_scope.level_active and root.run_scope.runner != null: ctx["runner"] = {"node_index": root.run_scope.runner.node_index, "level_result": String(root.run_scope.runner.level_result), "hero_hp": root.run_scope.runner.hero_hp, "settlement_is_null": root.run_scope.runner.current_battle() == null} if root.run_scope.settlement != null: ctx["settlement"] = root.run_scope.settlement.diagnostic_snapshot() # 诊断观测面(私有字段零直读) var path: String = root.logger.dump_diagnosis(ctx) root.board_zone.toast.show_toast("已转储诊断: " + path, "info") static func _show_debug_overlay(root: Variant) -> void: # 门禁:对局中可开;本函数仍是唯一开窗入口,门禁逻辑收函数内: # 棋盘输入锁/状态角标判据排除浮窗, # 遮挡语义=ModalStack 登记制(他模态开时暂隐、关后自动恢复),此处零场景限制 if root.debug_overlay == null: return root._open_modal(root.debug_overlay) _sync_debug_overlay(root) # 调试浮窗角标点击(两屏同款处理器——与状态角标同形制守卫;仍收口 _show_debug_overlay 单口) static func _on_debug_badge_pressed(root: Variant) -> void: var map_on: bool = root.level_screen != null and root.level_screen.visible if (map_on and root._modal_flow.badge_greyed_map()) or (not map_on and root._modal_flow.badge_greyed_battle()): return _show_debug_overlay(root) # 浮窗上下文同步(当局数据刷新+对局中按钮禁用单点):调用面=开窗口与模态开合 # 单口(凡影响开态/对局态的路径必经其一——与 _sync_status_entry 同款纪律) static func _sync_debug_overlay(root: Variant) -> void: if root.debug_overlay == null: return root.debug_overlay.set_context_locked(root.run_scope.settlement != null or root.run_scope.is_adventure) # 对局中批量模拟/两层调试入口禁用(长程异步模拟与活跃结算并存态不开放) root.debug_overlay.update_run_data(_debug_run_data(root)) # 当局数据只读区块喂入(开窗+模态开合信号驱动) # 当局数据六项只读投影(零直读内部状态、零写通路):种子=adventure.master_seed 现值 # (非 _seed_value() 重算);调试两层/非对局无冒险对象=RNG 服务 master_seed 现值(只读出口, # 未播种 -1 显「—」);关卡/节点/HP/GP=runner 成文出口、钥石=adventure 冒险账本(LevelRunner 无此域); # 缺位=「—」占位。零动效(纯标签重查)。 static func _debug_run_data(root: Variant) -> Dictionary: var r = root.run_scope.adventure.runner() if root.run_scope.adventure != null else null var seed_now: int = root._current_master_seed() var seed_txt: String = str(seed_now) if seed_now >= 0 else "—" if r == null: return {"seed": seed_txt, "level": "—", "node": "—", "hp": "—", "gp": "—", "keystone": "—"} return {"seed": seed_txt, "level": int(root.run_scope.adventure.level_index), "node": int(r.node_index), "hp": "%d/%d" % [int(r.hero_hp), int(r.effective_max_hp())], "gp": int(r.gp), "keystone": int(root.run_scope.adventure.keystone)} static func _close_debug_overlay(root: Variant) -> void: root._close_modal(root.debug_overlay) # 模态栈单口——开始层全程未隐藏,无需恢复 static func _on_tune_apply(root: Variant, atk_pct: int, hp_pct: int) -> void: # 加成无持久态可"落"——各战斗开局经 board_resolvers.debug_hero_override/runner 现算生效(应用=关闭浮窗) _close_debug_overlay(root) static func _on_tune_simulate(root: Variant, n: int) -> void: # 批量模拟编排 = 控制器承接(tune_sim_controller.gd);E4 后无表态需复位——模拟走 runner 覆盖参数。 # 对局中禁用兜底(长程异步模拟与活跃冒险/结算并存态不开放;探针 emit 绕过 disabled 时由此守住) if root.run_scope.settlement != null or root.run_scope.is_adventure: return root._tune_sim.run(n) static func _start_debug_levels(root: Variant) -> void: # 守卫:调试对局与活跃冒险/结算/批量模拟并存不开放——并发会清写 # settlement/编排态=状态机破坏;模拟在跑时 reset_sliders 会作废测量读数(d5 置灰之外的信号绕过闸) if root.run_scope.is_adventure or root.run_scope.settlement != null or root._tune_sim.is_running(): return root.debug_overlay.reset_sliders() root._close_modal(root.debug_overlay) # 浮窗内入口发起——随开随收(对局期不可再开:门禁在 _show_debug_overlay) root._start_overlay.visible = false root.log_view.clear() root.log_view.append_bb(root.Narrator.debug_open_line(root._seed_value(), 1, true)) root._begin_session(false) if not root._debug.start_debug_levels(): root._fatal_screen("战斗启动失败——见输出日志") static func _on_debug_battle_created(root: Variant, settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void: # begin_battle 前接手 + 接线(signal.connect 唯一归组合根)。settlement 必须先于 begin_battle # 就位——begin 期间发出的 board_changed 要用新板重建棋盘并触发一次性提示(缺陷①同款时序义务) root.run_scope.settlement = settlement_ref root._wire_battle(settlement_ref) static func _on_debug_battle_ready(root: Variant, settlement_ref: BattleOrchestrator, _level: int, _carry: int) -> void: root.run_scope.settlement = settlement_ref root.board_view.rebuild(root.run_scope.settlement.minesweeper.current_board(), root.run_scope.settlement.minesweeper) root._check_board_hints() root._refresh_presentations()