Files
gplan-2/game/probe/level_map_shot_probe.gd
T
DKChan 9f21236f80 工程(注释标记词换代·oracle→判据出处): 用户 2026-11-07 令——判据出处注记的标记词改用项目已有中文名,避免 Oracle 被读成数据库。注释格式句、机检正则、标识符、卡片与登记同步换代;零行为改动。
改动面 112 文件 572+/572-:game/tests/** 与 game/probe/** 共 106 件 545 行 `# oracle:`→`# 判据出处:`;tools/capability_audit.py 正则字面量换中文+ORACLE_*→CRITERION_*/check_oracle_markers→check_criterion_markers/oracle_marked(flagged)→criterion_* 共 11 行;test-conventions.md:119 格式句+:155 措辞;待办清单与需求卡片-QA覆盖余量收口批各 1 处字面量;coverage_enum.py:21 与 camp_scene_layout_test.gd:101 旁支措辞;ui_click_probe.gd 对拍局部变量 oracle→expected 7 处;auto_player.gd 三处 safe_set 真值措辞。不动:历史审计报告两份、test-oracle-anchor 分支名、git 史、生成日志;指针格式/扫描面/判红条件/验收义务全不变。

读数(区内实跑):改前 capability_audit --strict「417 注记函数·红项 0」→改后「417 判据出处注记函数·红项 0」exit=0;新标记 545 行/106 文件,现行义务面 oracle 残留 0(在册沿革除外);diff 自检 game/ 非注释新增行仅 6 行且全在 ui_click_probe.gd 的 expected 变量段;112 改动文件 CRLF=0;py_compile tools/capability_audit.py OK;--docs exit=0【验收通过】无新增红;--gates exit=0(静态扫描绿、闸壳 bash -n ×13 失败 0)。
2026-11-07 07:11:15 +08:00

95 lines
4.1 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.
# level_map_shot_probe.gd — 关卡画面视口 golden 采集探针(卷轴视口批 golden 扩项)
# 两 Shot 面(2026-11-05 用户裁:只对拍关卡最开始与关卡 Boss 节点,中间过程不对拍):
# lmap_entry.png = 入口停点(关卡最开始——锚点=入口组包围盒中心夹紧)
# lmap_boss.png = 中段停点锚定末列(Boss 紫赤描边列入屏——viewport_center 夹紧右缘)
# 采集确定性 = 固定种子单关直构(LevelRunner.start_level_external defer_entry / resume_state,
# 零 RNG 消耗路径)+ 探针隔离档(无断点、出厂设置 1280×800);运行=窗口化(--headless 禁——
# 渲染闸机器面吃真实渲染帧)。截图经 user args 目录落盘,基线换代走 golden_baseline_refresh.sh --lmap。
# 运行:Godot_console.exe --path game res://probe/level_map_shot_probe.tscn -- <shots_dir>
extends Node
const SEED_L3 := 910212 # 深图固定种子(与 level_map_viewport_probe 同源——图确定性承载)
func _ready() -> void:
# 判据出处: design/engineering/test-conventions.md:84 (关卡画面截图取证——载入守卫组)
var args := OS.get_cmdline_user_args()
var out_dir := args[0] if args.size() > 0 else "user://"
await get_tree().process_frame
var host := Control.new()
add_child(host)
host.size = get_viewport().get_visible_rect().size
var screen = load("res://presentation/views/level_map_screen.gd").new()
screen.set_anchors_preset(Control.PRESET_FULL_RECT)
host.add_child(screen)
for i in range(6):
await get_tree().process_frame # 布局收敛(视口实况尺寸落定→resize 重锚)
# Shot①:入口停点(关卡最开始)
var runner = _make_runner(true, -1)
screen.open_choices(_cand_nodes(runner), runner)
await _settle()
_shot(out_dir, "lmap_entry.png")
# Shot②:中段停点锚定末列(布局 x 最深的有出边节点——id 不按深度排,锚定后 Boss 列入屏)
var boss_stop := _deepest_with_outs(screen, runner)
runner = _make_runner(false, boss_stop)
screen.open_choices(_cand_nodes(runner), runner)
await _settle()
_shot(out_dir, "lmap_boss.png")
print("[level_map_shot_probe] PASS — 两 Shot 落盘(entry+boss → %s)" % out_dir)
get_tree().quit(0)
func _settle() -> void:
for i in range(8):
await get_tree().process_frame
await get_tree().create_timer(0.5).timeout # 平滑滚动终态余量(reanchor tween 0.3s)
func _make_runner(entry: bool, node_id: int):
# 判据出处: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组)
var rng = load("res://core/rng_service.gd").new()
rng.new_adventure(SEED_L3)
var runner = load("res://core/level_runner.gd").new(get_node("/root/ConfigDB"), rng)
var ok: bool
if entry:
ok = runner.start_level_external(3, Callable(runner, "rest_heal_amount"), true)
else:
ok = runner.start_level_external(3, Callable(runner, "rest_heal_amount"),
false, {"node_id": node_id, "visited_ids": [node_id]})
if not ok:
push_error("[level_map_shot_probe] 状态注入失败(entry=%s node=%d)" % [str(entry), node_id])
get_tree().quit(1)
return runner
func _cand_nodes(runner) -> Array:
var ids: Array = runner.next_candidate_ids()
var out: Array = []
for node in runner.nodes():
if ids.has(runner.node_id_of(node)):
out.append(node)
return out
func _deepest_with_outs(screen, runner) -> int:
var pos: Dictionary = screen.layout_probe(runner.nodes())
var best := -1
var best_x := -INF
for node in runner.nodes():
if runner.node_out_ids(node).is_empty():
continue
var x: float = pos[node].x
if x > best_x:
best_x = x
best = runner.node_id_of(node)
return best
func _shot(out_dir: String, fname: String) -> void:
# 判据出处: design/engineering/test-conventions.md:84 (判定上报通道——验证函数组)
DirAccess.make_dir_recursive_absolute(out_dir) # 落盘目录自建(save_png 对缺目录静默失败——刷新链不预建)
var img := get_viewport().get_texture().get_image()
var err := img.save_png(out_dir.path_join(fname))
if err != OK:
push_error("[level_map_shot_probe] 截图落盘失败 %s(err=%d)" % [fname, err])
get_tree().quit(1)