Files
gplan-2/game/presentation/views/debug_overlay.gd
T
DKChan bf65b49331 fix(调试入口): boot 菜单优先+开始屏右下角调试角标恢复——用户实测否决「启动即开」
用户 F5 实测:浮窗 boot 自动开把开始屏盖成调试面板(640×约700 居中面板盖掉大半个屏),
且菜单层没有任何浮窗入口(iter18 迁宿主两屏的理由=启动即开,已不成立)——关掉浮窗后
菜单上无法再开。用户令查三问(入口在哪/何时触发/触发后效果)后修正:

- main.gd:_ready 删 boot 自动开浮窗(_debug_entry 门控保留);恢复菜单角标接线
  (pressed→_on_debug_badge_pressed);可见性赋值挪到门控落定之后(原在 _build_ui
  读到初始 false——首跑冒烟抓出)
- ui_assembler:恢复右下角「调试」角标(git 历史 40fb4a5c^ 原实现:PRESET_BOTTOM_RIGHT
  16px 角距+FS_HINT+豁免宽度基准)+ 返回键补 dbgbtn(首跑漏了返回键致 menu_screen
  句柄 null、_build_ui 中断、V1c 层序红——冒烟抓出)
- scenes/menu_screen.gd:暴露 dbgbtn 句柄
- debug_overlay.gd:desc 文案改三处入口说明(开始屏右下角/战斗屏 HUD/地图屏角标)
- 探针/断言四处换代:smoke V2f 改「boot 不开浮窗+菜单角标可见」、V1a 收回严格判据;
  click_probe boot 检查反转+角标检查翻转为缺失才红+删浮窗恢复断言;tune_probe ① 改
  角标真实点击开窗路径;shot_probe 删浮窗归一段(已成死代码)
2026-10-16 04:21:49 +08:00

333 lines
13 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VERTICAL SLICE - NOT FOR PRODUCTION
# Date: 2026-10-04(主菜单调试三散件(随机种子/角色数值调整板/两层调试入口)收一张调试浮窗)
# 开发调试浮窗:全局可开(调试会话恒开,启动即开〔组合根 _ready〕+战斗屏 HUD/关卡地图屏
# 两枚角标再开;遮挡语义=ModalStack 登记制:他模态开时暂隐、关后自动恢复)。
# 当局数据只读区块=本局种子唯一查看位(六项)。
# 列表页形态可扩展:后续调试项按区块往下追加,超高滚动。
# 纯视图边界(规范 1.3):数值应用/批量模拟/对局启动全部经信号外发由组合根承接
#(apply_requested / simulate_requested / debug_levels_requested / closed);
# 当局数据经 update_run_data setter 喂入(只读投影零回读);模拟进度与报告经 setter 注入——
# 零核心写、不拼报告文案(装配归 HudPresenter)。零动效(零 tween/AnimationPlayer)。
# 探针接缝(合成输入走真实翻译出口口径):press_apply_for_probe 等三键 = 按钮真实信号路径。
class_name DebugOverlay
extends Control
signal apply_requested(atk_pct: int, hp_pct: int) # 应用并关闭——加成落表归组合根单一应用路径
signal simulate_requested(count: int) # 批量模拟编排归组合根(表基线复位 + 单路径施加)
signal debug_levels_requested # 两层调试对局入口(编排归 debug_session.gd)
signal diagnose_requested # 诊断转储入口(迭代 26 T5b——原主画面角落钮迁入;卡死取证编排归组合根)
signal closed
var seed_edit: LineEdit # 组合根 _seed_value 唯一读取面(原开始覆盖层种子行迁入)
var _db
var _base_atk := 0
var _base_hp := 0
var _atk: HSlider
var _hp: HSlider
var _atk_val: Label
var _hp_val: Label
var _eff: Label
var _sim_count: SpinBox
var _sim_btn: Button
var _dbg_btn: Button # 两层调试入口钮(迭代 18 卡⑦——对局中禁用承载面)
var _sim_out: RichTextLabel
var _sim_running := false # 批量模拟进行中(is_running 判据——与对局中禁用态分离防互扰)
var _ctx_locked := false # 对局中上下文锁定(组合根 _sync_debug_overlay 喂入——批量模拟/两层调试入口禁用)
var _run_labels := {} # 当局数据六项标签(P4 甲——只读投影,组合根 update_run_data 喂入)
var _run_data := {} # 最近一次投喂快照(探针值对面 run_data_probe)
func _init(db_ref, base_atk: int, base_hp: int) -> void:
_db = db_ref
_base_atk = base_atk
_base_hp = base_hp
_build()
_sync_labels()
visible = false # 显式初始化——不靠树序巧合(缺陷⑤家族纪律)
# ---- 对外语义面(组合根/探针)----
func atk_pct() -> int:
return int(_atk.value)
func hp_pct() -> int:
return int(_hp.value)
func set_sliders(atk: int, hp: int) -> void:
_atk.value = atk
_hp.value = hp
func reset_sliders() -> void:
_atk.value = 0
_hp.value = 0
_sync_labels()
func effect_text() -> String:
return _eff.text
func set_sim_count(n: int) -> void:
_sim_count.value = n
func is_running() -> bool:
return _sim_running # 批量模拟进行中(迭代 18 卡⑦——与对局中禁用态分离,置灰 ≠ 在跑)
func set_sim_running(running: bool) -> void:
_sim_running = running
_sync_sim_button()
# 对局中上下文锁定(迭代 18 卡⑦ T2——组合根 _sync_debug_overlay 喂入):批量模拟与两层调试入口
# 在活跃对局并存态不开放(长程异步模拟/并发对局编排与活跃结算并存态破坏状态机)
func set_context_locked(locked: bool) -> void:
_ctx_locked = locked
_dbg_btn.disabled = _ctx_locked
_sync_sim_button()
# 当局数据只读投影喂入(T3 P4 甲六项——组合根 _debug_run_data 构造;纯标签重查零动效)
func update_run_data(data: Dictionary) -> void:
_run_data = data.duplicate()
for key in _run_labels:
(_run_labels[key] as Label).text = str(data.get(key, "—"))
# 当局数据快照读面(探针值对面——ui_tune_probe 断言六项与只读访问器逐项一致)
func run_data_probe() -> Dictionary:
return _run_data.duplicate()
func _sync_sim_button() -> void:
_sim_btn.disabled = _sim_running or _ctx_locked
_sim_btn.text = "模拟中…" if _sim_running else "运行模拟"
func set_sim_progress(text: String) -> void:
_sim_out.text = text
func set_sim_report(text: String) -> void:
_sim_out.text = text
func output_text() -> String:
return _sim_out.get_parsed_text()
# ---- 探针接缝(真实翻译出口——按钮 pressed 信号路径,非直调组合根)----
func press_apply_for_probe() -> void:
_apply_btn_pressed()
func press_reset_for_probe() -> void:
_reset_btn_pressed()
func press_simulate_for_probe() -> void:
_sim_btn.pressed.emit()
# ---- 内部(信号 → 外发)----
func _apply_btn_pressed() -> void:
apply_requested.emit(atk_pct(), hp_pct())
func _reset_btn_pressed() -> void:
reset_sliders()
func effective_atk() -> int:
return UiKit.scaled(_base_atk, atk_pct())
func effective_max_hp() -> int:
return UiKit.scaled(_base_hp, hp_pct())
# ---- 内部构建(标题/关闭固定于浮窗骨架,可扩展列表区居中滚动)----
func _build() -> void:
var shell: Dictionary[Variant, Variant] = UiKit.modal_shell(self, UiKit.BG_OVERLAY, Vector2(640, 0), 8)
var box: VBoxContainer = shell.box
var title := UiKit.label("调试",UiKit.FS_TITLE, true, UiKit.WARM)
box.add_child(title)
var desc := UiKit.label(
"开发调试专用(开始屏右下角/战斗屏 HUD/关卡地图屏「调试」角标均可开)。当局数据=本局只读投影,种子即本局种子唯一查看位。\n百分比叠加基础值:攻击 %d / 生命 %d。影响所有模式(手动与模拟),不落盘。" % [_base_atk, _base_hp],
13, false, UiKit.WARM_SOFT)
box.add_child(desc)
box.add_child(HSeparator.new())
# 可扩展列表页(后续调试项按区块往下追加——超高滚动,滚轮下探)
var scroll := ScrollContainer.new()
scroll.custom_minimum_size = Vector2(0, 430)
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
box.add_child(scroll)
var list := VBoxContainer.new()
list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
list.add_theme_constant_override("separation", 8)
scroll.add_child(list)
# 区块·当局数据(迭代 18 卡⑦ T3 P4 甲——六项只读投影:种子=本局种子唯一查看位〔adventure
# .master_seed 现值,非 _seed_value() 重算〕/关卡/节点/HP/GP/钥石;数据由组合根开窗与模态开合
# 时 update_run_data 喂入;纯标签零信号连接零动效——17卡③只读契约)
var run_head := UiKit.label("当局数据(只读)",UiKit.FS_HINT, true, UiKit.WARM)
list.add_child(run_head)
var run_grid := GridContainer.new()
run_grid.columns = 2
run_grid.add_theme_constant_override("h_separation", 14)
run_grid.add_theme_constant_override("v_separation", 2)
list.add_child(run_grid)
for item in [["seed", "种子"], ["level", "关卡"], ["node", "节点"], ["hp", "HP"], ["gp", "GP"], ["keystone", "钥石"]]:
var cap := UiKit.label(String(item[1]),UiKit.FS_HINT, false, UiKit.WARM_FAINT)
cap.custom_minimum_size = Vector2(52, 0)
run_grid.add_child(cap)
var val := UiKit.label("—",UiKit.FS_HINT, false, UiKit.WARM)
_run_labels[item[0]] = val
run_grid.add_child(val)
list.add_child(HSeparator.new())
# 区块⓪胜利演出风格(P-C5 两套并存——纹章拼合[默认]/尘金粒子;会话级不落盘)
var fx_row := HBoxContainer.new()
fx_row.add_theme_constant_override("separation", 10)
list.add_child(fx_row)
fx_row.add_child(UiKit.label("胜利演出",UiKit.FS_HINT, false, UiKit.WARM))
var fx_btn := UiKit.button("纹章拼合" if UiKit.victory_fx_style == "crest" else "尘金粒子")
fx_btn.tooltip_text = "两套演出并存——点击切换(会话级,不落盘)"
fx_btn.pressed.connect(_on_fx_toggle.bind(fx_btn)) # 迭代 18 卡⑦——lambda 转命名方法(只读巡检白名单方法名精确可判)
fx_row.add_child(fx_btn)
# 区块①随机种子(原开始覆盖层种子行迁入——种子三分判定归组合根 _seed_value 单点):
# 默认空框(迭代 18 卡⑦ C1——空=随全局规则:首局恒 42/非首局随机;显式填入全场景优先)
var seed_row := HBoxContainer.new()
list.add_child(seed_row)
seed_row.add_child(UiKit.label("随机种子",UiKit.FS_BODY, false))
seed_edit = LineEdit.new()
seed_edit.text = ""
seed_edit.placeholder_text = "留空=随机 · 首局恒 42"
seed_edit.custom_minimum_size = Vector2(120, 0)
seed_row.add_child(seed_edit)
list.add_child(HSeparator.new())
# 区块②角色数值调整板(原 TunePanel 内容原样吸收)
var atk_row := _slider_row(list, "攻击加成")
_atk = atk_row.slider
_atk_val = atk_row.value_label
var hp_row := _slider_row(list, "生命加成")
_hp = hp_row.slider
_hp_val = hp_row.value_label
_eff = UiKit.label("",UiKit.FS_HINT, false)
list.add_child(_eff)
var btn_row := HBoxContainer.new()
list.add_child(btn_row)
var apply_btn := UiKit.button("应用并关闭")
apply_btn.pressed.connect(_apply_btn_pressed)
btn_row.add_child(apply_btn)
var reset_btn := UiKit.button("重置为 0")
reset_btn.pressed.connect(_reset_btn_pressed)
btn_row.add_child(reset_btn)
list.add_child(HSeparator.new())
# 区块③批量模拟(与 headless 扫描同口径——编排归 tune_sim_controller)
var sim_row := HBoxContainer.new()
list.add_child(sim_row)
sim_row.add_child(UiKit.label("批量模拟第一关",UiKit.FS_BODY, false))
_sim_count = SpinBox.new()
_sim_count.min_value = 10
_sim_count.max_value = 200
_sim_count.step = 10
_sim_count.value = 30
_sim_count.custom_minimum_size = Vector2(90, 0)
sim_row.add_child(_sim_count)
sim_row.add_child(UiKit.label("次(理性玩家策略,含面板当前加成)",UiKit.FS_HINT, false))
_sim_btn = UiKit.button("运行模拟")
_sim_btn.pressed.connect(_emit_simulate_requested)
sim_row.add_child(_sim_btn)
_sim_out = RichTextLabel.new()
_sim_out.bbcode_enabled = true
_sim_out.custom_minimum_size = Vector2(0, 300)
list.add_child(_sim_out)
list.add_child(HSeparator.new())
# 区块④两层调试对局入口(原开始覆盖层调试按钮迁入——HP 关内延续;迭代 18 卡⑦——对局中禁用)
_dbg_btn = UiKit.button("调试 · 连续关卡两层(HP 关内延续)")
_dbg_btn.pressed.connect(_emit_debug_levels)
list.add_child(_dbg_btn)
# 区块⑤诊断转储(迭代 26 T5b——原主画面左下角「诊断转储」常驻钮退役迁入:grilling Q8 裁甲,
# 承迭代 18 卡⑦「主菜单三散件收一」纪律;dump_diagnosis 卡死取证功能保留〔删除案否〕,
# 门控隐藏案否——本浮窗本就可全局可开,双轨无意义。纯视图边界:转储编排经信号外发归组合根)
var diag_row := HBoxContainer.new()
diag_row.add_theme_constant_override("separation", 10)
list.add_child(diag_row)
diag_row.add_child(UiKit.label("诊断转储",UiKit.FS_BODY, false))
var diag_btn := UiKit.button("转储")
diag_btn.tooltip_text = "卡死取证:全量核心状态+环形缓冲 → user://logs/diag_*.json"
diag_btn.pressed.connect(_emit_diagnose_requested)
diag_row.add_child(diag_btn)
var close_btn := UiKit.button("关闭")
close_btn.pressed.connect(_emit_closed)
box.add_child(close_btn)
func _slider_row(box: VBoxContainer, title: String) -> Dictionary:
var row := HBoxContainer.new()
box.add_child(row)
row.add_child(UiKit.label(title,UiKit.FS_BODY, false))
var s := HSlider.new()
s.min_value = 0
s.max_value = 300
s.step = 5
s.custom_minimum_size = Vector2(320, 24) # 皮肤走全局主题(迭代 25:与设置屏音量滑轨同一构建方式,消双轨)
row.add_child(s)
var v := UiKit.label("+0%",UiKit.FS_BODY, true)
v.custom_minimum_size = Vector2(70, 0)
row.add_child(v)
s.value_changed.connect(_on_slider_value_changed)
return {"slider": s, "value_label": v}
func _sync_labels() -> void:
_atk_val.text = "+%d%%" % atk_pct()
_hp_val.text = "+%d%%" % hp_pct()
_eff.text = "生效值:攻击 %d → %d · 生命 %d → %d" % [
_base_atk, effective_atk(), _base_hp, effective_max_hp()]
func _emit_simulate_requested() -> void:
simulate_requested.emit(int(_sim_count.value))
func _emit_diagnose_requested() -> void:
diagnose_requested.emit()
func _emit_debug_levels() -> void:
debug_levels_requested.emit()
func _emit_closed() -> void:
closed.emit()
func _on_slider_value_changed(_value: float) -> void:
_sync_labels()
# 胜利演出切换(原 _build 内 lambda——迭代 18 卡⑦ 转命名方法,只读巡检白名单承载)
func _on_fx_toggle(btn: Button) -> void:
UiKit.victory_fx_style = "dust" if UiKit.victory_fx_style == "crest" else "crest"
btn.text = "纹章拼合" if UiKit.victory_fx_style == "crest" else "尘金粒子"