ba-auto-daily/ba_auto/tasks/exit_game.py

74 lines
3.0 KiB
Python

"""Exit the Blue Archive client. No baas-reference counterpart -- see
ba_auto/reference_notes/mapping.md's "Exit game" row for the full search:
the reference project runs as a persistent background scheduler and never
deliberately exits the app between task cycles. This is new, desktop-specific
convenience logic for this project's different (cron, one-shot-per-preset)
architecture, meant to run as the last task in a preset.
navigation.return_to_home's own docstring already documents the mechanism
this relies on: an Escape press on the confirmed true home screen (nowhere
else) raises Blue Archive's own "exit the game?" confirmation dialog. Every
other task treats that as a hazard to avoid triggering by accident; this is
the one task that wants it, so it only fires Escape after verifying true
home first, never blindly.
Enter is this project's established confirm/OK key (circle.py/gem_shop.py's
own reward dismissal). Success is verified against driver.window_exists()
actually going False, not just against the keypress having been sent,
matching every other verified-keypress helper in this project.
No force-kill fallback if the graceful path doesn't verify -- matches this
project's "abort cleanly on unknown state rather than guess" convention
(gem_shop/bounty) rather than reaching for driver.kill_game().
Not yet live-tested: navigation.is_modal_open's generic dim-probe hasn't
been confirmed specifically against this dialog's own visual layout.
"""
from ba_auto import navigation
CONFIRM_RETRIES = 3
CLOSE_WAIT_ITERATIONS = 15
CLOSE_WAIT_INTERVAL = 1
def _raise_exit_dialog(driver, config):
for attempt in range(1, CONFIRM_RETRIES + 1):
if attempt == CONFIRM_RETRIES and driver.window_exists():
driver.focus_game()
driver.keypress("Escape")
driver.wait(1)
if navigation.is_modal_open(driver):
return True
print(f"[exit_game] exit-confirmation dialog not detected after Escape (attempt {attempt}/{CONFIRM_RETRIES})")
return False
def _confirm_exit(driver, config):
for attempt in range(1, CONFIRM_RETRIES + 1):
driver.keypress("Return")
driver.wait(1)
for _ in range(CLOSE_WAIT_ITERATIONS):
if not driver.window_exists():
return True
driver.wait(CLOSE_WAIT_INTERVAL)
print(f"[exit_game] game window still present after Enter (attempt {attempt}/{CONFIRM_RETRIES})")
return not driver.window_exists()
def run(driver, config):
driver.focus_game()
if not navigation.return_to_home(driver):
print("[exit_game] could not confirm the true home screen -- aborting without pressing Escape")
return
if not _raise_exit_dialog(driver, config):
print("[exit_game] could not confirm the exit-confirmation dialog opened -- aborting without pressing Enter")
return
if not _confirm_exit(driver, config):
print("[exit_game] warning: could not confirm the game actually closed")
return
print("[exit_game] game closed.")