merge: 演播后排窗+定点探针
This commit is contained in:
commit
bb35fdc169
4 files changed
+157
-10
No files matched your search
@@ -123,6 +123,32 @@ var _locked_click := {} # 锁期点击缓存(T17 v3.1——最后一
|
|||||||
# 锁期点击重放(v3.1):延迟一帧重入唯一动作通道——此刻队列空锁已解,按普通动作受理
|
# 锁期点击重放(v3.1):延迟一帧重入唯一动作通道——此刻队列空锁已解,按普通动作受理
|
||||||
#(局面在演播期无变化:逻辑先行、演播只是回放——点击语义保真;_row_queue=RowPacer 委托面,
|
#(局面在演播期无变化:逻辑先行、演播只是回放——点击语义保真;_row_queue=RowPacer 委托面,
|
||||||
# 排播泵本体已迁 row_pacer.gd——T3 结构段)。
|
# 排播泵本体已迁 row_pacer.gd——T3 结构段)。
|
||||||
|
var _deferred_modal: Control = null # 演播后开窗挂起(T17——胜利/Boss 总结/终局面等排播放完再开)
|
||||||
|
|
||||||
|
|
||||||
|
# 演播后排窗(T17 用户令「伤害过程演完才切结算窗口」):排播队列在播=挂起,演播完边沿
|
||||||
|
# (_on_pump_ended 派发)再开——旧路径 _open_modal 前置 flush 会把击杀轮的伤害/死亡演出
|
||||||
|
# 同帧倒掉(「直接跳战斗胜利」缺陷本体)。队列空=立即开(行为同旧路径)。
|
||||||
|
func _open_modal_after_playback(m: Control) -> void:
|
||||||
|
if _row_pacer.pending_rows().is_empty():
|
||||||
|
_open_modal(m)
|
||||||
|
return
|
||||||
|
_deferred_modal = m
|
||||||
|
m.visible = false # 挂起含视觉(open_* 已置 visible=true——不压掉则窗在排播期照会上屏,延迟形同虚设)
|
||||||
|
|
||||||
|
|
||||||
|
# 演播完边沿派发(row_pacer.pump_ended 注入口——原直连锁期点击重放,现统一派发):
|
||||||
|
# 先开挂起 modal(胜利窗接管呈现),后锁期点击重放——modal 开启后 _input_locked 吞掉
|
||||||
|
# 重放点击(战斗已收场,重放无意义)。
|
||||||
|
func _on_pump_ended() -> void:
|
||||||
|
if _deferred_modal != null:
|
||||||
|
var m: Control = _deferred_modal
|
||||||
|
_deferred_modal = null
|
||||||
|
_open_modal(m)
|
||||||
|
return
|
||||||
|
_replay_locked_click()
|
||||||
|
|
||||||
|
|
||||||
func _replay_locked_click() -> void:
|
func _replay_locked_click() -> void:
|
||||||
if _locked_click.is_empty() or not _row_queue.is_empty():
|
if _locked_click.is_empty() or not _row_queue.is_empty():
|
||||||
return
|
return
|
||||||
@@ -180,7 +206,7 @@ func _build_ui() -> void:
|
|||||||
_row_pacer.settlement_fx = settlement_fx
|
_row_pacer.settlement_fx = settlement_fx
|
||||||
_row_pacer.board_view = board_view
|
_row_pacer.board_view = board_view
|
||||||
_row_pacer.refresh_request = _refresh_presentations
|
_row_pacer.refresh_request = _refresh_presentations
|
||||||
_row_pacer.pump_ended = _replay_locked_click # T17 v3.1——演播完边沿重放锁期点击(合并批接线)
|
_row_pacer.pump_ended = _on_pump_ended # T17 v3.1+演播后排窗——边沿统一派发(挂起 modal 优先,其次锁期点击重放) # T17 v3.1——演播完边沿重放锁期点击(合并批接线)
|
||||||
add_child(_row_pacer)
|
add_child(_row_pacer)
|
||||||
# 魔法道具两步交互(T3 拆件批——迁 aux_interact_controller.gd;settlement/runner 随关卡更替,
|
# 魔法道具两步交互(T3 拆件批——迁 aux_interact_controller.gd;settlement/runner 随关卡更替,
|
||||||
# 经现值回调注入——仿 identity_resolver 只读回调先例)
|
# 经现值回调注入——仿 identity_resolver 只读回调先例)
|
||||||
@@ -298,6 +324,12 @@ func _register_modal(m: Control) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _open_modal(m: Control) -> void:
|
func _open_modal(m: Control) -> void:
|
||||||
|
# 挂起兜底(T17 演播后排窗):其他路径(如回看)在播期排空队列会使演播完边沿不再触发——
|
||||||
|
# 此处先结挂起 modal 防永不兑现(m==挂起对象时跳过=本调用自身)。
|
||||||
|
if _deferred_modal != null and m != _deferred_modal:
|
||||||
|
var dm: Control = _deferred_modal
|
||||||
|
_deferred_modal = null
|
||||||
|
_open_modal(dm)
|
||||||
# 打开时显式隐藏树序在其上方的可见层(遮挡物隐藏),关闭恢复——单一模态栈
|
# 打开时显式隐藏树序在其上方的可见层(遮挡物隐藏),关闭恢复——单一模态栈
|
||||||
_flush_row_queue() # 卡⑦——任何覆盖层开启前排空排播队列(明细带恒完整,回看/停点面不缺行)
|
_flush_row_queue() # 卡⑦——任何覆盖层开启前排空排播队列(明细带恒完整,回看/停点面不缺行)
|
||||||
_modals.open(m)
|
_modals.open(m)
|
||||||
@@ -486,7 +518,7 @@ func _on_bonus_presented(payload: Dictionary) -> void:
|
|||||||
_end_overlay.open_victory(Narrator.battle_end_text("victory", false), "继续",
|
_end_overlay.open_victory(Narrator.battle_end_text("victory", false), "继续",
|
||||||
board_view.get_global_rect(),
|
board_view.get_global_rect(),
|
||||||
"%s\n%s" % [_gp_summary_text({"gp_dropped": _last_gain_amount}), Narrator.bonus_keystone_line(payload)])
|
"%s\n%s" % [_gp_summary_text({"gp_dropped": _last_gain_amount}), Narrator.bonus_keystone_line(payload)])
|
||||||
_open_modal(_end_overlay)
|
_open_modal_after_playback(_end_overlay)
|
||||||
_refresh_presentations()
|
_refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
@@ -615,7 +647,7 @@ func _on_adventure_finished(summary: Dictionary) -> void:
|
|||||||
logger.log_level_end(summary) # 试玩时间线:冒险终局(摘要随载荷)
|
logger.log_level_end(summary) # 试玩时间线:冒险终局(摘要随载荷)
|
||||||
if runner != null:
|
if runner != null:
|
||||||
runner.restore_hero_base()
|
runner.restore_hero_base()
|
||||||
_open_modal(_end_overlay)
|
_open_modal_after_playback(_end_overlay)
|
||||||
_refresh_presentations()
|
_refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
@@ -779,7 +811,7 @@ func _on_battle_finished(payload: Dictionary) -> void:
|
|||||||
else:
|
else:
|
||||||
_end_overlay.open_defeat(Narrator.battle_end_text("defeat", false),
|
_end_overlay.open_defeat(Narrator.battle_end_text("defeat", false),
|
||||||
"返回", board_view.get_global_rect())
|
"返回", board_view.get_global_rect())
|
||||||
_open_modal(_end_overlay)
|
_open_modal_after_playback(_end_overlay)
|
||||||
_refresh_presentations()
|
_refresh_presentations()
|
||||||
|
|
||||||
|
|
||||||
@@ -898,7 +930,7 @@ func _on_choices_presented(candidates: Array) -> void:
|
|||||||
_end_overlay.open_victory(Narrator.battle_end_text("victory", false), "下一节点",
|
_end_overlay.open_victory(Narrator.battle_end_text("victory", false), "下一节点",
|
||||||
board_view.get_global_rect(),
|
board_view.get_global_rect(),
|
||||||
"战利品 GP +%d · 合计 %d" % [_last_gain_amount, int(runner.gp)])
|
"战利品 GP +%d · 合计 %d" % [_last_gain_amount, int(runner.gp)])
|
||||||
_open_modal(_end_overlay)
|
_open_modal_after_playback(_end_overlay)
|
||||||
_refresh_presentations()
|
_refresh_presentations()
|
||||||
return
|
return
|
||||||
_enter_level_screen()
|
_enter_level_screen()
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||||
|
# 演播后排窗定点探针(T17 用户令「伤害过程演完才切战斗胜利结算窗」——对应本改动的唯一关联测试):
|
||||||
|
# 真实信号路径驱动一场战斗到击杀胜利(结算行在排播队列),断言两条:
|
||||||
|
# ①胜利同帧:终局面未开 + 挂起态在案 + 队列非空(旧行为=同帧 flush+开窗,本断言即红——判别性);
|
||||||
|
# ②排播放完:终局面开启(演播完边沿派发——_on_pump_ended)。
|
||||||
|
# 存档/设置/元进度三面隔离(fx_shot_probe 同款),零真实档触碰。headless 可跑(不抓帧)。
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var main
|
||||||
|
var _problems: Array = []
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
await get_tree().process_frame
|
||||||
|
main = load("res://presentation/main.tscn").instantiate()
|
||||||
|
add_child(main)
|
||||||
|
await get_tree().process_frame
|
||||||
|
for p0 in ["user://t17_defer_probe.json", "user://t17_defer_probe_settings.cfg"]:
|
||||||
|
if FileAccess.file_exists(p0):
|
||||||
|
DirAccess.remove_absolute(p0)
|
||||||
|
var iso_c = load("res://core/save_manager.gd").new("user://t17_defer_probe.json")
|
||||||
|
iso_c.load_from_disk()
|
||||||
|
main.save_manager = iso_c
|
||||||
|
main.meta = load("res://core/meta_progression.gd").new(main.db, iso_c)
|
||||||
|
main.settings_store = load("res://presentation/settings_store.gd").new("user://t17_defer_probe_settings.cfg")
|
||||||
|
# 本探针验证完整动画档的演播后排窗——强制 motion_scale=1.0(隔离档替换在 boot 后,
|
||||||
|
# 减动效已随真档 settings.cfg 应用于引擎态;减动效档=consume_now 快路、开窗即时,另属语义)
|
||||||
|
UiKit.motion_scale = 1.0
|
||||||
|
for i in 8:
|
||||||
|
await get_tree().process_frame
|
||||||
|
var lvbtn: Button = _find_button_by_sub(main._start_overlay, "开始冒险")
|
||||||
|
if lvbtn == null:
|
||||||
|
_fail("开始冒险按钮缺失")
|
||||||
|
return
|
||||||
|
lvbtn.pressed.emit()
|
||||||
|
for i in 60:
|
||||||
|
await get_tree().process_frame
|
||||||
|
if main.level_screen != null and main.level_screen.visible:
|
||||||
|
break
|
||||||
|
if main.level_screen == null or not main.level_screen.visible:
|
||||||
|
_fail("关卡画面未出现")
|
||||||
|
return
|
||||||
|
for i in 5:
|
||||||
|
await get_tree().process_frame
|
||||||
|
main.level_screen.press_candidate(0)
|
||||||
|
for i in 20:
|
||||||
|
await get_tree().process_frame
|
||||||
|
if main.settlement == null:
|
||||||
|
_fail("战斗未启动")
|
||||||
|
return
|
||||||
|
# 直挖至击杀胜利(settle_batch 真实管线——step_row 信号→排播队列,与点击路径同链)
|
||||||
|
var ms = main.settlement.minesweeper
|
||||||
|
var guard := 200
|
||||||
|
while guard > 0 and String(main.settlement.battle_result) == "":
|
||||||
|
guard -= 1
|
||||||
|
var plan = load("res://smoke/auto_player.gd").choose_dig(ms)
|
||||||
|
if plan.is_empty():
|
||||||
|
main.settlement.settle_batch([{"action": "stop", "cell": Vector2i(-1, -1)}])
|
||||||
|
await get_tree().process_frame
|
||||||
|
continue
|
||||||
|
if plan.hero_cell != ms.hero_pos():
|
||||||
|
ms.settle_batch([{"action": "move", "cell": plan.hero_cell}])
|
||||||
|
ms.settle_batch([{"action": "dig", "cell": plan.dig_cell}])
|
||||||
|
await get_tree().process_frame
|
||||||
|
if String(main.settlement.battle_result) != "victory":
|
||||||
|
_fail("战斗未胜利(result='%s')" % str(main.settlement.battle_result))
|
||||||
|
return
|
||||||
|
# 断言①胜利同帧:终局面未开 + 挂起在案 + 队列非空(判别性——旧行为同帧开窗即红)
|
||||||
|
if main._end_overlay.is_open():
|
||||||
|
_problems.append("胜利同帧终局面已开(演播后排窗失效——同帧 flush 旧路径回潮)")
|
||||||
|
if main._deferred_modal == null:
|
||||||
|
_problems.append("胜利同帧挂起态缺失(_deferred_modal == null)")
|
||||||
|
if main._row_pacer.pending_rows().is_empty():
|
||||||
|
_problems.append("胜利同帧排播队列已空(结算行未走排播链)")
|
||||||
|
# 断言②排播放完:终局面开启(20s 守卫——0.22s×行数 ×10 余量)
|
||||||
|
var waited := 0.0
|
||||||
|
while not main._end_overlay.is_open() and waited < 20.0:
|
||||||
|
await get_tree().process_frame
|
||||||
|
waited += get_process_delta_time()
|
||||||
|
if not main._end_overlay.is_open():
|
||||||
|
_problems.append("排播放完后终局面未开(%.1fs——演播完边沿派发失守)" % waited)
|
||||||
|
if _problems.is_empty():
|
||||||
|
print("[t17_defer] PASS — 胜利同帧挂起+排播完开窗 两断言全过(waited=%.1fs)" % waited)
|
||||||
|
get_tree().quit(0)
|
||||||
|
else:
|
||||||
|
for p in _problems:
|
||||||
|
print("[t17_defer] FAIL — " + p)
|
||||||
|
get_tree().quit(2)
|
||||||
|
|
||||||
|
|
||||||
|
func _fail(why: String) -> void:
|
||||||
|
print("[t17_defer] FAIL — " + why)
|
||||||
|
get_tree().quit(2)
|
||||||
|
|
||||||
|
|
||||||
|
func _find_button_by_sub(root: Node, sub: String) -> Button:
|
||||||
|
if root is Button and String(root.text).contains(sub):
|
||||||
|
return root
|
||||||
|
for c in root.get_children():
|
||||||
|
var r := _find_button_by_sub(c, sub)
|
||||||
|
if r != null:
|
||||||
|
return r
|
||||||
|
return null
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://smoke/t17_defer_probe.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="T17DeferProbe" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
@@ -256,7 +256,11 @@ func _ready() -> void:
|
|||||||
# 冒险终局(失败/放弃/打穿)——单关直入口退役后无二段入口,见终局即收口(模态断言照旧)
|
# 冒险终局(失败/放弃/打穿)——单关直入口退役后无二段入口,见终局即收口(模态断言照旧)
|
||||||
# T17 适配(迭代 10 三选一链):_adventure_mode 仍真且非选路挂起=中途结算面(Boss 胜利
|
# T17 适配(迭代 10 三选一链):_adventure_mode 仍真且非选路挂起=中途结算面(Boss 胜利
|
||||||
# 总结「继续」后挂三选一→真终局未到)——真实信号路径点继续推进。
|
# 总结「继续」后挂三选一→真终局未到)——真实信号路径点继续推进。
|
||||||
if main._adventure_mode and not main._settlement_stop_pending:
|
# T17 演播后排窗适配:真终局 vs 中途结算面判据=adventure.state(冒险结构三态——
|
||||||
|
# 战斗胜利停点=running / 真终局(失败/放弃/打穿)=settling)。旧判据
|
||||||
|
# (_adventure_mode)在真终局仍 true——会把真终局当中途面点掉返回键(实证)。
|
||||||
|
var _adv_running: bool = main.adventure != null and String(main.adventure.state) == "running"
|
||||||
|
if main._adventure_mode and _adv_running:
|
||||||
main._end_overlay._btn.pressed.emit()
|
main._end_overlay._btn.pressed.emit()
|
||||||
continue
|
continue
|
||||||
if not main._input_locked():
|
if not main._input_locked():
|
||||||
@@ -293,14 +297,14 @@ func _ready() -> void:
|
|||||||
# (冒险终局面在案)须主动满足。收口驱动:任何停点层逐个推进(复用主循环分支语义)至
|
# (冒险终局面在案)须主动满足。收口驱动:任何停点层逐个推进(复用主循环分支语义)至
|
||||||
# level_screen 选路停点→真实放弃二击→终局面。战斗中则继续 autoplay 打完。
|
# level_screen 选路停点→真实放弃二击→终局面。战斗中则继续 autoplay 打完。
|
||||||
if not _done and not main._end_overlay.is_open():
|
if not _done and not main._end_overlay.is_open():
|
||||||
var close_guard := 1200
|
var close_guard := 8000
|
||||||
|
var dbg_frame := 0 # T17 演播后排窗:每场胜利 +~400 帧演播等待(旧同帧 flush 零等待)——守卫按多场战斗放大
|
||||||
while close_guard > 0:
|
while close_guard > 0:
|
||||||
close_guard -= 1
|
close_guard -= 1
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
if main._end_overlay.is_open():
|
if main._end_overlay.is_open():
|
||||||
# 冒险中=中途结算面(战斗总结「继续」/下一节点——L2 通关后还有三选一面续推);
|
# 中途结算面(state=running)=点继续推进;真终局(settling)=断点段前提满足,收口。
|
||||||
# 非冒险=终局面在案——断点段前提满足,收口完成。
|
if main._adventure_mode and main.adventure != null and String(main.adventure.state) == "running":
|
||||||
if main._adventure_mode:
|
|
||||||
main._end_overlay._btn.pressed.emit()
|
main._end_overlay._btn.pressed.emit()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@@ -336,6 +340,8 @@ func _ready() -> void:
|
|||||||
and main.settlement.action_economy.phase == "Active":
|
and main.settlement.action_economy.phase == "Active":
|
||||||
_play_one_action()
|
_play_one_action()
|
||||||
# 排播期/Waiting 等待态=自然流逝(演播秒级、锁随队列空解除)
|
# 排播期/Waiting 等待态=自然流逝(演播秒级、锁随队列空解除)
|
||||||
|
str(main.settlement.battle_result) if main.settlement != null else "-",
|
||||||
|
main._row_queue.size(), str(main._deferred_modal != null)])
|
||||||
# T17 适配:战败或放弃二途皆达终局面(放弃=预算耗尽收口路径——见上),断点段前提不变。
|
# T17 适配:战败或放弃二途皆达终局面(放弃=预算耗尽收口路径——见上),断点段前提不变。
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
var bp_file := "user://smoke_click_probe_reset.json"
|
var bp_file := "user://smoke_click_probe_reset.json"
|
||||||
|
|||||||
Reference in new issue
Block a user