diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index b7a3b0d6..b39a522f 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -86,6 +86,7 @@ func _split_tail() -> void: _smoke_hygiene_gates() if autoload_ok: await _smoke_scene_split() # 协程函数必须 await(无 await=发射后不管,首个 await 后即被 quit 截断) + await _smoke_boot_chain() await _smoke_run_lifecycle() else: check(false, "V2/V3 前置:autoload 链未就绪(ConfigDB/SaveManager)") @@ -237,6 +238,70 @@ func _topmost_visible_layer(main: Node) -> Node: return best +# ---- boot 链路时序后置条件(迭代 28 T2——装配修复后启动态六断言;只立行为可判断言,不造假时序)---- +func _smoke_boot_chain() -> void: + print("--- 迭代28 T2 boot 链路时序后置条件(V2:六断言)---") + var main: Node = load("res://presentation/main.tscn").instantiate() + root.add_child(main) + await process_frame + await process_frame + # ① ConfigDB 就绪且表已载 + var db = main.get_node("/root/ConfigDB") + check(db.is_ready and db.hero != null, + "V2a ConfigDB 就绪且表已载(is_ready+hero 表在座)〔装配生命批 V2〕") + # ② 设置已应用(引擎态=settings_store 现值——真实设置文件照读,一致性判据与文件内容无关) + var ss = main.settings_store + var master := AudioServer.get_bus_index("Master") + check(AudioServer.is_bus_mute(master) == (ss.volume_linear <= 0.001) + and is_equal_approx(AudioServer.get_bus_volume_db(master), linear_to_db(maxf(ss.volume_linear, 0.001))), + "V2b 设置已应用·音量(Master mute/volume_db=settings_store 现值 linear=%f)〔装配生命批 V2〕" % ss.volume_linear) + var ui_kit = load("res://presentation/views/ui_kit.gd") + check(ui_kit.motion_scale == (0.5 if ss.reduced_motion else 1.0), + "V2b 设置已应用·减动效(UiKit.motion_scale=%s=settings_store.reduced_motion=%s)〔装配生命批 V2〕" % [ + str(ui_kit.motion_scale), str(ss.reduced_motion)]) + # ③ 启动态菜单可见 + check(main._start_overlay.visible, + "V2c 启动态 _start_overlay.visible=true(boot 后玩家见菜单)〔装配生命批 V2〕") + # ④ 续玩钮可见态==SaveManager 断点在档态 + var sm = main.get_node("/root/SaveManager") + # ④-1 boot 路径:boot 时按钮态==真实档断点态(关系判据——与真实档当时内容无关) + var real_bp: bool = sm.has_breakpoint() + check(main._resume_btn.visible == real_bp, + "V2d 续玩钮 boot 态==断点在档态(visible=%s has_breakpoint=%s)〔装配生命批 V2〕" % [ + str(main._resume_btn.visible), str(real_bp)]) + # ④-2 隔离新档双向(attach 原地重置——绝不碰真实档 user://save.json;刷新单口与 boot 路径同源) + for p in ["user://smoke_boot_chain.json", "user://smoke_boot_chain.json.tmp"]: + if FileAccess.file_exists(p): + DirAccess.remove_absolute(p) + sm.attach_path("user://smoke_boot_chain.json") + main._refresh_resume_button() + check(not sm.has_breakpoint() and not main._resume_btn.visible, + "V2d 续玩钮·无断点态隐藏(visible=%s has_breakpoint=%s)〔装配生命批 V2〕" % [ + str(main._resume_btn.visible), str(sm.has_breakpoint())]) + sm.set_breakpoint({"level_index": 2, "master_seed": 42}) + main._refresh_resume_button() + check(sm.has_breakpoint() and main._resume_btn.visible, + "V2d 续玩钮·有断点态可见(visible=%s has_breakpoint=%s)〔装配生命批 V2〕" % [ + str(main._resume_btn.visible), str(sm.has_breakpoint())]) + sm.clear_breakpoint() + main._refresh_resume_button() + check(not main._resume_btn.visible, + "V2d 续玩钮·清断点后回隐藏(visible=%s)〔装配生命批 V2〕" % str(main._resume_btn.visible)) + # ⑤ 闲时会话(_ready 即建、永非 null、在树) + check(main.run_scope != null and not main.run_scope.is_adventure and main.run_scope.is_inside_tree(), + "V2e run_scope 非空且为闲时会话(is_adventure=false+is_inside_tree)〔装配生命批 V2〕") + # ⑥ DS_DEBUG 门控一致性(未设=浮窗隐藏;设了=启动即开——两侧同一判据) + var debug_on: bool = OS.get_environment("DS_DEBUG") == "1" + check(main.debug_overlay.visible == debug_on, + "V2f 调试浮窗态==DS_DEBUG 门控(visible=%s DS_DEBUG=%s)〔装配生命批 V2〕" % [ + str(main.debug_overlay.visible), str(debug_on)]) + main.queue_free() + await process_frame + for p in ["user://smoke_boot_chain.json", "user://smoke_boot_chain.json.tmp"]: + if FileAccess.file_exists(p): + DirAccess.remove_absolute(p) + + # ---- 会话物化断言(迭代 27 T1 V3——两连局复位/无脏状态残留;原手工复位清单消亡的行为级证明)---- func _smoke_run_lifecycle() -> void: print("--- 迭代27 T1 会话物化(V3:两连局复位+脏状态不残留)---")