Files
gplan-2/game/smoke/ui_layout_probe.gd
T
DKChan 7a0d57ddb0 feat(迭代27 T1): 波一 场景拆分+局生命周期物化——逐位一致对拍全同
P0-1 三屏场景化(契约2 只拆不重写):
- menu_screen/camp_screen/adventure_screen 三 .tscn 屏壳+壳脚本(视图代码原样构建,
  40+ views 零 .tscn 化);adventure 屏壳内含 level_map/battle 两容器
- main.gd _build_ui 解体=三屏实例化+模态装配+接线;组合根句柄全部保留(探针挂载
  假设 main.X 一级路径零迁移);树序=屏壳在前全模态之下(视觉共存对逐对验算)
- 屏壳根 mouse_filter=IGNORE(ui_input 实证:全屏 STOP 壳吃下层模态鼠标输入)

P0-2 会话物化(裁点①甲 autoload+手工清单消亡):
- run_scope.gd 节点持全部局态(adventure/runner/settlement/7+ 局态旗/账本);
  _begin_session 建会话、终局整节点 queue_free()——_reset_run_scope 三项+
  _on_battle_end_continue 置空四件手工清单删除
- SaveManager/MetaProgression 升格 autoload 3/4 号位(类名加 Core 后缀沿 RngService
  先例;--script 模式编译器不解析裸 autoload 标识符——组合根留读视图属性 get_node 形态)
- 探针隔离改 attach_path 原地重置(set_master_seed 先例);10 探针+pacing 测试迁移

验收(V1 核心=逐位一致对拍):
- parity_anchor 三变体 base/attune/shop×40 局 RUNSUM+JSONL 双面逐位全同(零行为漂移)
- 冒烟 1055→1077/0(+V2 屏壳独立实例化 11 断言+V3 两连局复位 11 断言)
- run_all 25 套+probe click 全绿+render_gate golden 0.00%×3
2026-10-14 20:28:53 +08:00

114 lines
5.7 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-09-13(四区布局诊断探针——"内容未满幅/棋盘底裁切"回归定位:打印窗口/视口/四区实际矩形
# 与最小尺寸、展开旗标,对照 battle.md §Layout 1280×800 基座规格)
# 迭代 19 卡① T5(2026-10-08):零断言诊断件补最小布局断言转断言件——1280/1920 两档:
# ①基座 1280×800(battle.md §Layout)②顶层三区(B=stage/C=info_panel/D=board_zone)互不重叠不越视口
# ③board_view(=board_zone 子节点别名)不越视口且含于 D 区 ④1920 档钉分辨率案甲契约(迭代 9 案甲——
# stretch=canvas_items/aspect=keep 下逻辑视口与四区矩形恒定=构图与基准档一致);退出码/PASS-FAIL 语义
# 具备闸可接形态(闸归属归卡③裁点②候裁,本批不入闸)。原诊断打印面全保留。
# 运行:Godot_console.exe --headless --path . res://smoke/ui_layout_probe.tscn
extends Node
const ProbeUiUtil := preload("res://smoke/probe_ui_util.gd") # T6 收口:隔离样板单点
func _ready() -> void:
await get_tree().process_frame # autoload 就绪
var main: Node = load("res://presentation/main.tscn").instantiate()
add_child(main)
await get_tree().process_frame
# 存档隔离(迭代 8 卡①②——停点断点写盘随 main.save_manager;探针禁碰真实档,同族探针隔离纪律;
# isolate_save 先删后建——上次运行的残留断点会触发互斥确认早退)
ProbeUiUtil.isolate_save(main, "smoke_layout_probe_save", true, false, true)
main.debug_overlay.seed_edit.text = "42" # 种子钉死(迭代 18 卡⑦审计🔴——种子框默认改空后空框=非首局随机,探针确定性禁依赖默认分支)
main._start_adventure_from_menu()
for i in range(3):
await get_tree().process_frame
var win := get_window()
print("window.size=%s pos=%s mode=%s" % [win.size, win.position, win.mode])
print("viewport.visible_rect=%s" % get_viewport().get_visible_rect())
print("main.size=%s" % main.size)
for c in main.get_children():
if c is Control:
_dump_ctrl(c, 0)
var zones := {
"board_zone": main.board_zone, "board_view": main.board_view,
"info_panel": main.info_panel,
"stage": main.stage,
}
for k in zones:
var ctl: Control = zones[k]
if ctl == null:
print("%s = null" % k)
continue
print("%-16s pos=%s size=%s min=%s hflag=%d vflag=%d" % [k, ctl.position, ctl.size,
ctl.custom_minimum_size, ctl.size_flags_horizontal, ctl.size_flags_vertical])
var root_box: Control = main._adventure_screen.battle_root # 迭代 27 T1——屏壳化后战斗四区根迁冒险屏壳(序数寻址漂移改名寻址)
print("four-zone root: anchors=(%s,%s)-(%s,%s) offsets=(%s,%s,%s,%s) size=%s" % [
root_box.anchor_left, root_box.anchor_top, root_box.anchor_right, root_box.anchor_bottom,
root_box.offset_left, root_box.offset_top, root_box.offset_right, root_box.offset_bottom, root_box.size])
print("board_view cell_size=%s board=%s" % [main.board_view.get("cell_size"), main.board_view.board()])
# ── 最小布局断言(迭代 19 卡① T5——1280/1920 两档;语义见头注) ──
var problems: PackedStringArray = []
var vr: Rect2 = get_viewport().get_visible_rect()
if vr.size != Vector2(1280, 800):
problems.append("基座视口 %s ≠ 1280x800(battle.md §Layout)" % vr.size)
var azones := {"stage": main.stage, "info_panel": main.info_panel, "board_zone": main.board_zone}
var arects := {}
for k in azones:
var actl: Control = azones[k]
if actl == null:
problems.append("%s=null" % k)
continue
var ar := Rect2(actl.global_position, actl.size)
arects[k] = ar
if ar.size.x <= 0.0 or ar.size.y <= 0.0:
problems.append("%s 零尺寸 %s" % [k, ar.size])
elif not vr.encloses(ar):
problems.append("%s 越视口 %s ⊄ %s" % [k, ar, vr])
var bvc: Control = main.board_view
if bvc == null:
problems.append("board_view=null")
else:
var br := Rect2(bvc.global_position, bvc.size)
if not vr.encloses(br):
problems.append("board_view 越视口 %s ⊄ %s" % [br, vr])
if arects.has("board_zone") and not arects["board_zone"].encloses(br):
problems.append("board_view 越出 board_zone(%s ⊄ %s)" % [br, arects["board_zone"]])
var akeys := arects.keys()
for i in range(akeys.size()):
for j in range(i + 1, akeys.size()):
if arects[akeys[i]].intersects(arects[akeys[j]]):
problems.append("顶层区重叠 %s×%s(%s ∩ %s)" % [akeys[i], akeys[j], arects[akeys[i]], arects[akeys[j]]])
# 1920 档(Q4 注记对应面:单档 1280 闸+本两档断言钉 1920 构图恒等——分辨率维度不重复建闸)
get_window().size = Vector2i(1920, 1080)
for i in range(4):
await get_tree().process_frame
var vr2: Rect2 = get_viewport().get_visible_rect()
if vr2 != vr:
problems.append("1920 档逻辑视口漂移 %s ≠ %s(案甲:stretch 基座恒定)" % [vr2, vr])
for k in azones:
var actl2: Control = azones[k]
if actl2 == null:
continue
var ar2 := Rect2(actl2.global_position, actl2.size)
if arects.has(k) and ar2 != arects[k]:
problems.append("1920 档 %s 矩形漂移 %s ≠ %s(案甲:构图与基准档一致)" % [k, ar2, arects[k]])
if problems.is_empty():
print("[layout_probe] PASS — 1280/1920 两档全过(基座1280x800/顶层三区互斥不越界/board_view含于D区/案甲构图恒定)")
get_tree().quit(0)
else:
for p in problems:
print("[layout_probe] FAIL — " + p)
print("[layout_probe] FAIL — %d 项断言未过" % problems.size())
get_tree().quit(1)
func _dump_ctrl(c: Control, depth: int) -> void:
var ind := " ".repeat(depth)
print("%s%s pos=%s size=%s min=%s" % [ind, c.name, c.position, c.size, c.custom_minimum_size])
for ch in c.get_children():
if ch is Control:
_dump_ctrl(ch, depth + 1)