From cd7d3ea40126dc4a3d66f3dc81decae0c1de89bf Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sun, 4 Oct 2026 06:44:43 +0800 Subject: [PATCH] =?UTF-8?q?T1(D1):=20ui=5Fclick=5Fprobe=20=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E5=B1=80=E9=80=82=E9=85=8D=E2=80=94=E2=80=94=E5=88=86?= =?UTF-8?q?=E6=B4=BE=E9=93=BE=E5=BA=8F=E4=BF=AE=E6=AD=A3+=E9=94=81?= =?UTF-8?q?=E6=9C=9F/=E9=87=8D=E6=94=BE=E4=B8=89=E6=80=81=E6=96=AD?= =?UTF-8?q?=E8=A8=80=EF=BC=88=E4=B8=89=E7=A7=8D=E5=AD=90=E7=BB=BF+?= =?UTF-8?q?=E5=86=92=E7=83=9F718/0+run=5Fall15+t17=5Fdefer=E7=BB=BF?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ①分派链序修正(主循环):shop_overlay 停点提前到 level_screen 之前——迭代11商店房重构后 停点呈现为选路页+商店层双 visible,旧序下层候选点击空转烧尽预算(实证 lv2 商店停点双 visible 循环 12000 帧 done=false budget=0 问题=0;收口驱动循环序本就正确,仅主循环错序)。 ②停点态断言:三选一停点输入锁定断言(BonusPickOverlay 分派链顶)。 ③锁期断言(每run一次脚本化 _locktest_tick):演播期注入旗击→直落被冻结(旗未置)+ _locked_click 缓存命中(最后一次语义)。 ④重放断言:演播完边沿 pump_ended→_replay_locked_click 重入唯一动作通道受理恰一次 (旗布尔=单次送达探测器:双发翻转回false/零发false均暴露)。 ⑤演播期豁免保留+注记(冻结/缓存/重放语义由 _locktest_tick 正面承载);_play_one_action 增演播期不出手守卫(逐帧连点只会被「最后一次」覆盖且毁锁测注入独占前提);锁测在飞期 (state1)冻结探针动作面——排空帧免费 move 抢在帧末 deferred 重放前改英雄位致 flag 拒收 not_adjacent 实证,「注入→重放」窗口局面零变化=v3.1 被测语义本体。 基线:ui_click_probe 开工日红(budget 耗尽 done=false)→ 三种子绿(budget 9-10k/20000)。 --- game/smoke/ui_click_probe.gd | 113 +++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 10 deletions(-) diff --git a/game/smoke/ui_click_probe.gd b/game/smoke/ui_click_probe.gd index 22ddf15f..8949011b 100644 --- a/game/smoke/ui_click_probe.gd +++ b/game/smoke/ui_click_probe.gd @@ -30,6 +30,9 @@ var _tested_tooltip := false var _inter_confirms := 0 # 大奖励屏确认计数(冒险推进停点——首见确认推进 L2,再见 = L2 通关收口) var _settlement_confirms := 0 # 卡⑥ 胜利结算框确认计数(观测面——每场普通战斗胜利恰一) var _route_clicks := 0 # 选路覆盖层点击计数(岔路使用率观测面) +var _locktest_state := 0 # T1 D1 锁期/重放断言状态机(0=待注入 1=等重放 2=完结)——每 run 一次 +var _locktest_cell := Vector2i(-9, -9) +var _locktest_frames := 0 func _ready() -> void: @@ -190,9 +193,12 @@ func _ready() -> void: _flags_placed.clear() continue if main.bonus_overlay.visible: - # 迭代 10 三选一停点(BonusPickOverlay——奖励节点/通关兑付共用面;T17 硬锁批适配—— - # 本探针此前未适配该层,走到即卡死)。三态分派:替换子态(满位——放弃新件)/ - # result 态(兑付反馈——点继续推进)/ 待选态(点首件+确认)。真实信号路径全线。 + # 迭代 10 三选一停点(BonusPickOverlay——奖励节点/通关兑付共用面;T17 硬锁批适配—— + # 本探针此前未适配该层,走到即卡死)。三态分派:替换子态(满位——放弃新件)/ + # result 态(兑付反馈——点继续推进)/ 待选态(点首件+确认)。真实信号路径全线。 + # T1 D1——三选一停点输入锁定断言(停点态断言面:替换子/待选/兑付三态共用此层)。 + if not main._input_locked(): + _problems.append("三选一停点打开时输入未锁定") if main.bonus_overlay._replace_box.visible: main.bonus_overlay.replace_chosen.emit(-1) elif main.bonus_overlay._continue_btn.visible: @@ -204,17 +210,20 @@ func _ready() -> void: main.bonus_overlay.press_continue() # 停点已消费的残面——继续关屏 _flags_placed.clear() continue + if main.shop_overlay.visible: + # 商店房覆盖层(GP+商店房批——L2 商店为 Boss 前必经位):零购离开(真实 leave 信号路径)放行选路。 + # T1 D1 分派链序修正:商店层=选路页上的模态覆盖(迭代 11 商店房重构后停点呈现为 + # level_screen+shop 双 visible)——必须先于 level_screen 分派,否则下层候选点击 + # 空转烧尽预算(实证:lv2 商店停点双 visible 循环 12000 帧 done=false)。 + main.shop_overlay.leave_pressed.emit() + _flags_placed.clear() + continue if main.level_screen.visible: # 节点图选路口(零自动推进停点)——图上命中路径交替选候选(岔路使用行为;布局决策 2 改造) main.level_screen.press_candidate(_route_clicks % 2) _route_clicks += 1 _flags_placed.clear() continue - if main.shop_overlay.visible: - # 商店房覆盖层(GP+商店房批——L2 商店为 Boss 前必经位):零购离开(真实 leave 信号路径)放行选路 - main.shop_overlay.leave_pressed.emit() - _flags_placed.clear() - continue if main._inter_overlay.visible: # 大奖励屏(冒险级停点——非末关通关恰一次):首见确认推进 L2(真实按钮信号路径);再见 = L2 已通关,收口 if not main._input_locked(): @@ -281,6 +290,8 @@ func _ready() -> void: # 排播演播期豁免(T17 硬锁 v3 随批——合法停顿态):演播期棋盘锁生效、probe 点击被吞、 # 逻辑态恒定属预期。判据=纯队列(与 main 锁同源)。Waiting 收尾等待期**不豁免**—— # 锁若把收尾链卡死,此处 stall 照报(探测面)。 + # T1 D1 处置=保留豁免+注记:冻结/缓存/重放语义不再靠豁免绕行,由 _locktest_tick + # 脚本化断言正面承载(每 run 一次;逻辑态恒定本豁免继续作 stall 判据)。 if main._row_queue.is_empty(): _stall_frames += 1 if _stall_frames == 30: @@ -290,9 +301,14 @@ func _ready() -> void: _stall_frames = 0 _ap_spent_this_round = 0 _last_state = st + _locktest_tick() if main.settlement.battle_result == "" and main.settlement.action_economy.phase == "Active": - _run_modal_probes_once() - _play_one_action() + # T1 D1——锁测在飞期(state 1)冻结探针动作面:排空帧 autoplay 的免费 move 会抢在 + # 帧末 deferred 重放之前改变英雄位(flag 拒收 not_adjacent 实证)——「注入→重放」 + # 窗口内局面零变化正是 v3.1 被测语义(演播期冻结),动作面恢复待断言收口。 + if _locktest_state != 1: + _run_modal_probes_once() + _play_one_action() # ---- 预算耗尽收口(T17 硬锁批适配):选件变强后 probe 可能活过预算不再战败——断点段前提 # (冒险终局面在案)须主动满足。收口驱动:任何停点层逐个推进(复用主循环分支语义)至 # level_screen 选路停点→真实放弃二击→终局面。战斗中则继续 autoplay 打完。 @@ -527,6 +543,8 @@ func _play_one_action() -> void: var settlement = main.settlement if settlement == null: return # 结算竞态防抖:battle_finished 与本轮动作调度同帧到达时 settlement 可能已被置空(基线既有噪声——加固) + if not main._row_queue.is_empty(): + return # T1 D1——演播期不出手:此时点击只会进锁期缓存被「最后一次」覆盖(原逐帧连点语义无行为覆盖价值,且毁锁期断言注入的独占前提) var minesweeper = settlement.minesweeper # 行为①:随机插旗(右键——未开相邻格),约 20% 轮次 if _ap_spent_this_round == 0 and _rand.randf() < 0.2: @@ -581,6 +599,81 @@ func _click_stop() -> void: main.ap_bar._btn_stop.pressed.emit() +# ---- T1 D1:锁期/重放断言(每 run 一次,脚本化场景——演播期豁免的断言化承载) ---- +# 锁期断言(排播队列活跃=锁面):注入旗击 → 直落被冻结不受理(旗未置)+ `_locked_click` +# 缓存命中且为本注入(「最后一次」语义——注入帧内无并发点击)。 +# 重放断言(演播完边沿 pump_ended→_replay_locked_click 重入唯一动作通道):缓存清空 + +# 受理恰一次——旗布尔=单次送达探测器(双发=两次翻转回 false、零发=false,均暴露)。 +# 前提消失守卫:等重放期间出现停点层/战斗收场(注入时点恰逢终结演播)→ 静默弃测不计 +# problem(旗动作不杀伤,正常局不触发;断言实现形态取舍在代拍白名单内)。 +func _locktest_tick() -> void: + if _locktest_state == 2: + return + var settlement = main.settlement + if settlement == null or settlement.minesweeper.current_board() == null: + return + if _locktest_state == 0: + if main._row_queue.is_empty() or main._input_locked(): + return + if String(settlement.battle_result) != "" or String(settlement.action_economy.phase) != "Active": + return + if int(settlement.action_economy.ap) < 1: + return + var target := _locktest_pick_cell(settlement.minesweeper) + if target.x < 0 or settlement.minesweeper.has_flag(target): + return # 无合法邻格/目标被并发旗行为占位——下帧重挑 + _locktest_cell = target + _locktest_frames = 0 + main.board_view.click_cell(target, MOUSE_BUTTON_RIGHT) + if settlement.minesweeper.has_flag(target): + _problems.append("锁期断言:演播期点击未被冻结(旗即时受理——v3 冻结失守)") + _locktest_state = 2 + return + if main._locked_click.is_empty() or main._locked_click.get("cell") != target: + _problems.append("锁期断言:演播期点击未入缓存(v3.1 缓存失守)") + _locktest_state = 2 + return + _locktest_state = 1 + elif _locktest_state == 1: + if main.bonus_overlay.visible or main._inter_overlay.visible or main._end_overlay.is_open() \ + or String(settlement.battle_result) != "": + _locktest_state = 2 # 前提消失守卫:终结演播竞态——静默弃测 + return + if not main._row_queue.is_empty(): + _locktest_frames = 0 # 演播未完——重放耐心只在排空后起算(链式大演播数百帧不占预算) + return + _locktest_frames += 1 + if _locktest_frames < 3: + return # 排空边沿的 deferred 重放(pump_ended 帧末执行)在途宽限 + if _locktest_frames > 90: + _problems.append("重放断言:演播完边沿后缓存未清(%s)" % str(main._locked_click)) + _locktest_state = 2 + return + if main._locked_click.is_empty(): + if not settlement.minesweeper.has_flag(_locktest_cell): + var b = settlement.minesweeper.current_board() + print("[lockdiag] 重放后旗未置:br='%s' phase=%s ap=%d cell=%s revealed=%s board=%dx%d hero=%s" % [ + str(settlement.battle_result), str(settlement.action_economy.phase), + int(settlement.action_economy.ap), str(_locktest_cell), + str(settlement.minesweeper.is_revealed(_locktest_cell)), + b.width, b.height, str(settlement.minesweeper.hero_pos())]) + _problems.append("重放断言:锁期缓存点击未受理恰一次(旗未置位——零发或双发)") + _locktest_state = 2 + main.board_view.click_cell(_locktest_cell, MOUSE_BUTTON_RIGHT) # 拔旗恢复现场(尽力而为不判定) + + +func _locktest_pick_cell(minesweeper) -> Vector2i: + var hero: Vector2i = minesweeper.hero_pos() + for dy in range(-1, 2): + for dx in range(-1, 2): + if dx == 0 and dy == 0: + continue + var c: Vector2i = hero + Vector2i(dx, dy) + if minesweeper.current_board().in_bounds(c) and not minesweeper.is_revealed(c) and not minesweeper.has_flag(c): + return c + return Vector2i(-1, -1) + + func _report_stall(st: Dictionary) -> void: var why := "" if st.phase == "Waiting":