- main.gd 卸载点删除(build_diag_button 挂载+连接);build_diag_button 工厂退役(ui_assembler); 连接随迁=debug_overlay.diagnose_requested→_on_diagnose_pressed(dump_diagnosis 卡死取证保留, 删除案否/门控隐藏案否——浮窗本就可全局可开,双轨无意义) - debug_overlay 新增 diagnose_requested 信号+区块⑤转储钮(_emit_diagnose_requested 外发,纯视图边界) - 探针同批入册:ui_tune_probe 只读巡检白名单+_emit_diagnose_requested、连接数 10→11(七钮), confirm_dialog/main 树序注释订正(诊断钮引用清除) - 冒烟新增 _smoke_diag_button_retired() 7 断言(V6:主区零残留+工厂退役+连接随迁+浮窗可达); 冒烟 1048→1055/0;probe --click/--full 全绿残留 0
334 lines
13 KiB
GDScript
334 lines
13 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# Date: 2026-10-04(迭代 14.5 调试整合批——主菜单三散件(随机种子/角色数值调整板/两层调试入口)收一张调试浮窗,
|
||
# 原 views/tune_panel.gd 整体吸收退役)
|
||
# 开发调试浮窗:全局可开(迭代 18 卡⑦——DS_DEBUG=1 会话启动即开〔组合根 _ready〕+战斗屏 HUD/关卡地图屏
|
||
# 两枚角标再开〔P2 甲,17卡③状态角标同形制〕;遮挡语义=ModalStack 登记制:他模态开时暂隐、关后自动恢复;
|
||
# 旧「仅开始菜单可开」门随入口迁宿主退役)。当局数据只读区块=本局种子唯一查看位(T3,P4 甲六项)。
|
||
# 列表页形态可扩展:后续调试项按区块往下追加,超高滚动。
|
||
# 纯视图边界(规范 1.3):数值应用/批量模拟/对局启动全部经信号外发由组合根承接
|
||
#(apply_requested / simulate_requested / debug_levels_requested / closed);
|
||
# 当局数据经 update_run_data setter 喂入(只读投影零回读);模拟进度与报告经 setter 注入——
|
||
# 零核心写、不拼报告文案(装配归 HudPresenter)。零动效(零 tween/AnimationPlayer——17卡③契约)。
|
||
# 探针接缝(ADR-0004"合成输入走真实翻译出口"口径):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 = 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(
|
||
"开发调试专用(DS_DEBUG=1 会话:启动即开;战斗屏/地图屏「调试」角标可再开)。当局数据=本局只读投影,种子即本局种子唯一查看位。\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 "尘金粒子"
|