fix(baal_xp): restore the 09-08 join hardening lost in the 09-09 branch switch
The stash taken before switching to main (stash@{1}) carried a re-verified
_try_join - row click retried up to 3x with a re-OCR of the row when the list
scrolled, JOIN GAME press retried up to 3x when the lobby swallowed it, and a
join_game() default of 900s - but the switch was stashed, never re-applied, and
the branch tip kept the single-click version from 09-02. A single missed click
(or a list that scrolled between scan and click) then failed the whole join,
which is exactly the 'no matching game found' the cycle kept hitting.
Also add the finally: start_detecting_window() the 09-08 version had dropped:
join_game() stops the window-detection thread at the top, and every return
path (success, failure, exception) has to re-arm it or screen tracking stays
dead for the rest of the cycle.
This commit is contained in:
+51
-16
@@ -408,35 +408,67 @@ def _try_join(cand: dict) -> bool | None:
|
|||||||
True = joined
|
True = joined
|
||||||
False = that game was full or gone, try the next candidate
|
False = that game was full or gone, try the next candidate
|
||||||
None = we are no longer in a lobby state where retrying makes sense
|
None = we are no longer in a lobby state where retrying makes sense
|
||||||
"""
|
|
||||||
|
Every click is re-verified against the screen: a single click missed by a
|
||||||
|
frame (window focus, a covered button, a list that scrolled) used to end
|
||||||
|
the whole join attempt, and the caller then reported "no matching game"
|
||||||
|
after a few seconds of a perfectly good lobby. Re-click the row when the
|
||||||
|
JOIN GAME button does not appear, re-OCR the row when the name no longer
|
||||||
|
matches (the list scrolled), and retry the JOIN press when the first one
|
||||||
|
is swallowed. Only give up on a candidate after the retries are spent."""
|
||||||
Logger.info(f"game_browser: joining '{cand['name']}' "
|
Logger.info(f"game_browser: joining '{cand['name']}' "
|
||||||
f"({cand['players'] if cand['players'] is not None else '?'} players, row {cand['row']})")
|
f"({cand['players'] if cand['players'] is not None else '?'} players, row {cand['row']})")
|
||||||
_click((LIST_X + LIST_W // 2, cand["y_center"]), "game row")
|
for click_attempt in range(3):
|
||||||
wait(0.3, 0.5)
|
_click((LIST_X + LIST_W // 2, cand["y_center"]), "game row")
|
||||||
if not is_visible(ScreenObjects.LobbyJoinBtn):
|
wait(0.3, 0.5)
|
||||||
# Usually a leftover error dialog sitting on top of the lobby. Clear it
|
if is_visible(ScreenObjects.LobbyJoinBtn):
|
||||||
# and let the caller try the next candidate rather than aborting.
|
break
|
||||||
if is_visible(ScreenObjects.ServerError):
|
if is_visible(ScreenObjects.ServerError):
|
||||||
|
# Usually a leftover error dialog sitting on top of the lobby. Clear
|
||||||
|
# it and let the caller try the next candidate rather than aborting.
|
||||||
Logger.warning("game_browser: error dialog over the lobby - dismissing")
|
Logger.warning("game_browser: error dialog over the lobby - dismissing")
|
||||||
error_screens.handle_error()
|
error_screens.handle_error()
|
||||||
return False
|
return False
|
||||||
|
if not _in_lobby():
|
||||||
|
Logger.error("game_browser: left the lobby while selecting a row")
|
||||||
|
return None
|
||||||
|
# The list may have scrolled between the scan and now: re-read the row
|
||||||
|
# we are actually pointing at before burning another click on it.
|
||||||
|
img = grab()
|
||||||
|
actual = _ocr_roi(img, [LIST_X, cand["y_center"] - 9, LIST_W, ROW_H])
|
||||||
|
if actual and actual != cand["name"]:
|
||||||
|
Logger.debug(f"game_browser: row now reads '{actual}' (was '{cand['name']}') - list moved, re-scanning")
|
||||||
|
return False
|
||||||
|
Logger.debug(f"game_browser: JOIN GAME button not up after row click {click_attempt + 1}/3 - re-clicking")
|
||||||
|
wait(0.5, 0.8)
|
||||||
|
|
||||||
|
if not is_visible(ScreenObjects.LobbyJoinBtn):
|
||||||
if _in_lobby():
|
if _in_lobby():
|
||||||
Logger.warning("game_browser: JOIN GAME button not visible but still in the lobby - trying the next")
|
Logger.warning("game_browser: JOIN GAME button not visible but still in the lobby - trying the next")
|
||||||
return False
|
return False
|
||||||
Logger.error("game_browser: JOIN GAME button not visible after selecting a row")
|
Logger.error("game_browser: JOIN GAME button not visible after selecting a row")
|
||||||
return None
|
return None
|
||||||
_click(JOIN_BTN, "JOIN GAME")
|
|
||||||
if _wait_for_join():
|
# The first JOIN press is the one that gets swallowed (lobby input lag right
|
||||||
return True
|
# after a row click). Retry it before calling the candidate a failure.
|
||||||
if is_visible(ScreenObjects.LobbyJoinBtn):
|
for press in range(3):
|
||||||
Logger.info(f"game_browser: '{cand['name']}' was full or gone - trying the next candidate")
|
_click(JOIN_BTN, "JOIN GAME")
|
||||||
# The lobby swallows input for a moment after a bounced join.
|
if _wait_for_join():
|
||||||
wait(1.0, 1.5)
|
return True
|
||||||
return False
|
if is_visible(ScreenObjects.LobbyJoinBtn):
|
||||||
return None
|
Logger.info(f"game_browser: '{cand['name']}' was full or gone - trying the next candidate")
|
||||||
|
# The lobby swallows input for a moment after a bounced join.
|
||||||
|
wait(1.0, 1.5)
|
||||||
|
return False
|
||||||
|
if not _in_lobby():
|
||||||
|
Logger.error("game_browser: no longer in the lobby after a JOIN GAME press")
|
||||||
|
return None
|
||||||
|
Logger.debug("game_browser: JOIN GAME press produced no state change - retrying")
|
||||||
|
wait(0.5, 0.8)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def join_game(name_filter: str = "", max_wait_s: float = 60.0,
|
def join_game(name_filter: str = "", max_wait_s: float = 900.0,
|
||||||
difficulty: str = "normal", min_players: int = 3,
|
difficulty: str = "normal", min_players: int = 3,
|
||||||
max_players: int = 7) -> bool:
|
max_players: int = 7) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -524,6 +556,9 @@ def join_game(name_filter: str = "", max_wait_s: float = 60.0,
|
|||||||
Logger.error(f"game_browser: no matching game found within {max_wait_s}s")
|
Logger.error(f"game_browser: no matching game found within {max_wait_s}s")
|
||||||
return False
|
return False
|
||||||
finally:
|
finally:
|
||||||
|
# Re-arm the window-detection thread on every exit path (success,
|
||||||
|
# failure, or an exception mid-join) - leaving it stopped strands the
|
||||||
|
# bot's screen tracking for the rest of the cycle.
|
||||||
start_detecting_window()
|
start_detecting_window()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user