Skip to content

Commit c794ee4

Browse files
committed
fix: 游戏闪退/最小化时截图失败处理
- executor: 新增 _screenshot 统一入口, 异常/None 返回 None - executor: 所有 post_screencap 调用改为 _screenshot + None 检查 - executor: _wait_until_frames 截图失败设 _abort_reason 中止本轮 - avatar: locate_oper 和槽位 OCR 截图加 None 检查 - worker: 连续截图失败退避, 前3次快重试, 之后5s一次
1 parent 57f366e commit c794ee4

3 files changed

Lines changed: 51 additions & 10 deletions

File tree

aao/core/avatar.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ def locate_oper(
120120
3. 无缓存/匹配失败 → 逐个点击槽位 → OCR 干员名 → 截取头像存盘
121121
"""
122122
image = ctrl.post_screencap().wait().get()
123+
if image is None:
124+
logger.error("截图失败, 游戏可能已退出或最小化")
125+
return None
123126
slots = detect_slots(context, image)
124127
if not slots:
125128
logger.error("未检测到干员槽位")
@@ -165,6 +168,9 @@ def locate_oper(
165168

166169
# 截图详情页
167170
detail_img = ctrl.post_screencap().wait().get()
171+
if detail_img is None:
172+
logger.warning("截图失败, 跳过该槽位")
173+
continue
168174

169175
# OCR 干员名
170176
name = _ocr_oper_name(context, detail_img)

aao/measure/worker.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def __init__(
4040
self.interval_s = interval_s
4141
self._running = False
4242
self._reset_requested = False
43+
self._consecutive_errors = 0
4344
self._latest: dict = {}
4445
self._lock = threading.Lock()
4546

@@ -58,9 +59,19 @@ def run(self) -> None:
5859
try:
5960
img = self.controller.post_screencap().wait().get()
6061
self.time_source.update(img)
62+
self._consecutive_errors = 0
6163
except Exception:
62-
logger.exception("采集/更新失败,跳过")
63-
time.sleep(self.interval_s)
64+
self._consecutive_errors += 1
65+
if self._consecutive_errors <= 3:
66+
logger.warning("截图失败 %d 次", self._consecutive_errors)
67+
elif self._consecutive_errors == 4:
68+
logger.error(
69+
"截图连续失败 %d 次, 游戏可能已退出或最小化, 降低重试频率",
70+
self._consecutive_errors,
71+
)
72+
# 退避: 前 3 次快重试, 之后 5s 一次
73+
backoff = self.interval_s if self._consecutive_errors <= 3 else 5.0
74+
time.sleep(backoff)
6475
continue
6576

6677
state = {

custom/action/executor.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,20 @@ def _perform_action(
356356
elif action.action_type == ActionType.RETREAT:
357357
self._retreat(ctrl, action)
358358

359+
def _screenshot(self, ctrl: Controller) -> np.ndarray | None:
360+
"""统一截图入口, 异常或空返回 None。"""
361+
try:
362+
img = ctrl.post_screencap().wait().get()
363+
except Exception:
364+
logger.exception("截图失败, 游戏可能已退出或最小化")
365+
return None
366+
return img
367+
359368
def _read_frames(self, ctrl: Controller, ts: TimeSource) -> int | None:
360-
"""截图 → TimeSource → 累计帧。"""
361-
img = ctrl.post_screencap().wait().get()
369+
"""截图 → TimeSource → 累计帧。截图异常返回 None。"""
370+
img = self._screenshot(ctrl)
371+
if img is None:
372+
return None
362373
lf = ts.update(img)
363374
if lf is None:
364375
return None
@@ -383,7 +394,10 @@ def _wait_until_frames(
383394
while time.time() < deadline:
384395
if context_tasker_stopping():
385396
return
386-
img = ctrl.post_screencap().wait().get()
397+
img = self._screenshot(ctrl)
398+
if img is None:
399+
self._abort_reason = "screenshot failed"
400+
return
387401
now = time.time()
388402
lf = ts.update(img)
389403
if lf is not None:
@@ -435,7 +449,9 @@ def _pause_at_battle_start(
435449
if context_tasker_stopping():
436450
return False
437451
time.sleep(0.2)
438-
img = ctrl.post_screencap().wait().get()
452+
img = self._screenshot(ctrl)
453+
if img is None:
454+
continue
439455
reco = context.run_recognition("Farm@BattleOn", img)
440456
if reco and reco.hit:
441457
logger.debug("开局暂停: 战斗已加载")
@@ -451,7 +467,9 @@ def _pause_at_battle_start(
451467
self._tap_afa(afa_hotkey.VK_F, "F 开局暂停")
452468
self._paused = True
453469
time.sleep(0.03)
454-
img = ctrl.post_screencap().wait().get()
470+
img = self._screenshot(ctrl)
471+
if img is None:
472+
continue
455473
reco = context.run_recognition("BattlePaused", img)
456474
if reco and reco.hit:
457475
logger.debug("开局暂停成功 (Play.png 命中), attempt=%d", i + 1)
@@ -481,7 +499,9 @@ def _pause(
481499
if context_tasker_stopping():
482500
return False
483501
for attempt in range(2):
484-
img = ctrl.post_screencap().wait().get()
502+
img = self._screenshot(ctrl)
503+
if img is None:
504+
return False
485505
reco = context.run_recognition("BattlePaused", img)
486506
if reco and reco.hit:
487507
self._paused = True
@@ -491,7 +511,9 @@ def _pause(
491511
self._paused = True
492512
logger.debug("暂停(F), 等待 %dms, attempt=%d", config.PAUSE_WAIT_MS, attempt + 1)
493513
time.sleep(config.PAUSE_WAIT_MS / 1000)
494-
img = ctrl.post_screencap().wait().get()
514+
img = self._screenshot(ctrl)
515+
if img is None:
516+
return False
495517
reco = context.run_recognition("BattlePaused", img)
496518
if reco and reco.hit:
497519
logger.debug("暂停确认成功(模板命中), attempt=%d", attempt + 1)
@@ -588,7 +610,9 @@ def _step_to_frames(
588610
for _ in range(max_steps):
589611
if context_tasker_stopping():
590612
return
591-
img = ctrl.post_screencap().wait().get()
613+
img = self._screenshot(ctrl)
614+
if img is None:
615+
return
592616
lf = ts.update(img)
593617
if lf is None:
594618
break

0 commit comments

Comments
 (0)