T1(D1): ui_click_probe 完整局适配——分派链序修正+锁期/重放三态断言(三种子绿+冒烟718/0+run_all15+t17_defer绿)

①分派链序修正(主循环):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)。
This commit is contained in:
DKChan committed 2026-10-04 06:44:43 +08:00
1 parent 8344b89463
commit cd7d3ea401
1 file changed
+103 -10
+103 -10
View File
@@ -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":