Skip to content

Bug: Auto-join game loops clicking the OK button after a match ends and wrongly clicks into the Shop / 自动续战在结算后无法识别主界面,重复点击确认按钮并误触商店 #102

Description

@halfmadnya

环境 Environment

  • Version: 0.6.0
  • Python 3.11 / Windows, Playwright 1.42.0, 1280x720 viewport

问题描述 Description

开启自动加入游戏(auto_join_game)后,一局游戏结束,脚本无法识别游戏已退回主界面,会反复点击结算界面的 OK 按钮(Positions.GAMEOVER[0],坐标为 14.35, 8.12),最终误触主界面右下角的商店入口,进入商店页面后 comp_temp 永远匹配不到主菜单模板,陷入无限点击循环。

补充现象:若在主界面手动开启自动加入,识别正常、能顺利加入下一局——说明主菜单模板比对本身是可靠的,问题集中在结束流程的时序上。

根因分析 Root Cause

_end_game_iter()game/automation.py)的循环时序存在滞后窗口:

# 修改前
while True:
    res, diff = self.g_v.comp_temp(ImgTemp.MAIN_MENU)   # 1. 截图比对
    if res: break
    yield ActionStepDelay(random.uniform(2,3))          # 2. 点击前等待 2~3s
    for step in self.steps_randomized_move_click(x,y):  # 3. 点击 OK(含 0.5~1s 移动+停顿)
        yield step
    # 4. 点击后立即回到 1,再次截图比对(无过渡等待)

问题链条:

  1. 点击 OK 后立即截图比对,此时游戏正处于"结算界面 → 主界面"的过渡/加载帧,必然比对失败;
  2. 从截图完成到鼠标实际按下之间隔了 2.5~4s(23s 等待 + 0.51s 点击序列),而游戏退回主界面通常只需 1~2s;
  3. 于是出现"截图时游戏还在加载、点击时游戏已回到主界面"的错位:点击落在了主界面右下角 (14.35, 8.12 → 1280×720 下的 1148, 650) 的商店按钮上;
  4. 进入商店后 comp_temp 永远无法匹配主菜单 → 无限循环。

由于每次循环的等待时长相对固定,鼠标每次都落在相同的滞后点上,因此表现为"固定"误触商店按钮。

整改方案 Fix

将等待移到点击之后,保证每次截图比对和点击都发生在界面稳定状态下,消除滞后窗口;同时增加点击次数上限作为兜底,并输出 diff 日志便于诊断。

# 修改后
def _end_game_iter(self) -> Iterator[ActionStep]:
    max_clicks = 10
    clicks = 0
    while True:
        res, diff = self.g_v.comp_temp(ImgTemp.MAIN_MENU)
        LOGGER.debug("End-game check: main menu match=%s diff=%.1f", res, diff)
        if res:     # stop on main menu
            LOGGER.debug("Visual sees main menu with diff %.1f", diff)
            self.ui_state = UiState.MAIN_MENU
            break
        if clicks >= max_clicks:    # safety cap to avoid endless clicking
            LOGGER.warning("End-game: reached max clicks (%d), giving up", max_clicks)
            break
        clicks += 1

        x,y = Positions.GAMEOVER[0]
        for step in self.steps_randomized_move_click(x,y):
            yield step

        yield ActionStepDelay(random.uniform(8,10))  # wait after click so both check and click see a settled UI

修改要点

项目 修改前 修改后
等待位置 点击前等 2~3s 点击后等 8~10s
截图时机 点击后立即截图(可能截到过渡帧) 点击后等待过渡完成再截图
兜底 无(可能无限循环) 最多点击 10 次后放弃
诊断 仅匹配成功时输出 diff 每次比对都输出 match/diff

验证效果

  • 一局结束后可正确识别主界面并进入自动续战流程,不再误触商店按钮。

Description

With "auto join game" enabled, after a match ends the script fails to recognize that the game has returned to the main menu. It keeps clicking the OK button (Positions.GAMEOVER[0], 14.35, 8.12) on the result screen and eventually mis-clicks the Shop button at the bottom-right of the main menu. Once inside the Shop page, comp_temp can never match the main-menu template and the loop clicks forever.

Note: enabling auto-join from the main menu works correctly, so the template matching itself is reliable — the problem is in the end-game loop timing.

Root cause

In _end_game_iter() (game/automation.py) the loop had a lag window:

# before
while True:
    res, diff = self.g_v.comp_temp(ImgTemp.MAIN_MENU)   # 1. screenshot + compare
    if res: break
    yield ActionStepDelay(random.uniform(2,3))          # 2. wait 2~3s BEFORE click
    for step in self.steps_randomized_move_click(x,y):  # 3. click OK (~0.5~1s sequence)
        yield step
    # 4. screenshot again immediately after click (no transition wait)
  1. After clicking OK, the screenshot was taken immediately — capturing the transition frame between result screen and main menu, so the comparison always failed;
  2. From screenshot to actual mouse-down there was a 2.5~4s lag (23s wait + 0.51s click sequence), while returning to the main menu takes only 12s;
  3. So the screenshot saw the game still loading, but by the time the click landed the main menu was already up — clicking the Shop button at (1148, 650) in a 1280×720 viewport;
  4. Inside the Shop, comp_temp never matches the main menu → endless loop.

Because the wait is fairly constant each iteration, the click always lands at the same lag offset, hence the consistent mis-click into the Shop.

Fix

Move the wait to after the click so both the comparison and the click always see a settled UI; add a click-count cap as a safety net; log the diff on every check.

# after
def _end_game_iter(self) -> Iterator[ActionStep]:
    max_clicks = 10
    clicks = 0
    while True:
        res, diff = self.g_v.comp_temp(ImgTemp.MAIN_MENU)
        LOGGER.debug("End-game check: main menu match=%s diff=%.1f", res, diff)
        if res:     # stop on main menu
            LOGGER.debug("Visual sees main menu with diff %.1f", diff)
            self.ui_state = UiState.MAIN_MENU
            break
        if clicks >= max_clicks:    # safety cap to avoid endless clicking
            LOGGER.warning("End-game: reached max clicks (%d), giving up", max_clicks)
            break
        clicks += 1

        x,y = Positions.GAMEOVER[0]
        for step in self.steps_randomized_move_click(x,y):
            yield step

        yield ActionStepDelay(random.uniform(8,10))  # wait after click so both check and click see a settled UI

Changes

Item Before After
Wait position 2~3s before click 8~10s after click
Screenshot timing immediately after click (may capture transition frame) after the transition settles
Safety cap none (can loop forever) give up after 10 clicks
Diagnostics diff logged only on match log match/diff on every check

Verification

After the fix, the end-game flow correctly recognizes the main menu and proceeds to auto-join the next game; no more mis-clicks into the Shop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions