feat(exit_game): implement exit game functionality with confirmation dialog

This commit is contained in:
Nik Afiq 2026-07-18 20:32:14 +09:00
parent 0a6af51340
commit 976f0f7241
5 changed files with 41 additions and 8 deletions

File diff suppressed because one or more lines are too long

View File

@ -21,8 +21,10 @@ 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.
Confirmed live (2026-07-18) via a standalone `exit_game` run: the
is_modal_open dim-probe correctly detected the exit-confirmation dialog
after Escape, and the game closed cleanly after Enter. Not yet exercised
as the tail end of a full daily/q4h preset run specifically.
"""
from ba_auto import navigation

View File

@ -56,9 +56,9 @@ DEFAULT_ORDER = ["login", "mailbox", "cafe", "stamina", "gem_shop", "circle"]
# ends the session (Escape then Enter on the confirmed true home screen
# raises and confirms Blue Archive's own "exit the game?" dialog), so like
# every other resource-spending/session-affecting task it's opt-in only, not
# in DEFAULT_ORDER. Not yet live-tested -- see
# ba_auto/reference_notes/mapping.md's "Exit game" row before trusting it
# unattended.
# in DEFAULT_ORDER. Confirmed live standalone (2026-07-18); not yet
# exercised specifically as the tail end of a full daily/q4h preset run --
# see ba_auto/reference_notes/mapping.md's "Exit game" row.
PRESETS = {
"daily": [
"login", "event_sweep", "cafe", "event_sweep", "circle", "lesson",

View File

@ -914,7 +914,7 @@ Wired in as opt-in only (added `exit_game` to `TASKS` in `ba_daily.py`), appende
One real bug found and fixed before any live test, while reasoning through what happens next: `ba_daily.py`'s centralized `_run_task` always calls `navigation.return_to_home` in its post-task `finally` block and prints a warning if it returns False. `return_to_home` already bails out gracefully (returns False, doesn't crash) when the window doesn't exist, added for login.py's cold-start case -- but that means after `exit_game` succeeds, this same finally-block would print a misleading "could not confirm return to home screen after task finished" warning on every single `daily`/`q4h` run that reaches it, even though nothing is wrong. Fixed by skipping the post-task check entirely when `driver.window_exists()` is already False.
**Not yet live-tested.** `navigation.is_modal_open`'s generic dim-probe has not been specifically confirmed against this dialog's own visual layout -- needs a real run to confirm the Escape press actually raises it and that the dim-probe correctly reads it as open, before trusting this unattended in cron. Get explicit go-ahead before the first live test, since it deliberately ends a real game session.
**Confirmed live**: a standalone `./ba_dailies.sh exit_game` run, user-reported "works well" -- `navigation.is_modal_open`'s generic dim-probe correctly detected the exit-confirmation dialog after Escape, and Enter closed the game cleanly (`driver.window_exists()` verified false). Not yet exercised as the tail end of a full `daily`/`q4h` preset run specifically (only standalone so far).
## Prerequisites

View File

@ -6,7 +6,20 @@ set -euo pipefail
# nik-gpu into this repo's scratchpad/ba_logs/ for local reading (e.g. in
# VS Code). Local dev tooling only, not part of the ba_dailies.sh
# game-automation launcher -- same category as setup.sh/clean_scratchpad.sh.
# Read-only on the remote side: never writes back to nik-gpu.
#
# After a successful pull, also deletes the just-synced *.log files on the
# remote side (per explicit user request), so ~/ba_logs/ doesn't grow
# forever. This makes the remote side no longer read-only, unlike before --
# gated behind ba_cron_run.sh's own shared flock (~/ba_logs/ba_dailies.lock)
# to stay safe: that script holds this exact lock for its ENTIRE run,
# wrapping the whole `>> "$LOG_FILE"` append span, which can last many
# minutes (e.g. the "daily" preset's arena fights/event sweeps). If this
# script's own non-blocking flock attempt on the same lock file fails, a
# cron run is currently in progress -- deletion is skipped for this
# invocation (the local copy already pulled above is kept regardless)
# rather than risking `rm` unlinking a log file out from under an open
# write fd, which would silently lose that run's remaining log output to
# an unlinked inode with no error and no way to recover it.
#
# Usage:
# ./pull_logs.sh [host]
@ -21,3 +34,21 @@ mkdir -p "$DEST"
rsync -av "$HOST:ba_logs/" "$DEST/"
echo "Synced $HOST:~/ba_logs/ -> $DEST"
DELETE_RESULT="$(ssh "$HOST" bash -s <<'REMOTE'
LOCK_FILE="$HOME/ba_logs/ba_dailies.lock"
exec 9>"$LOCK_FILE"
if flock -n 9; then
rm -f "$HOME"/ba_logs/*.log
echo "DELETED"
else
echo "SKIPPED"
fi
REMOTE
)"
if [ "$DELETE_RESULT" = "DELETED" ]; then
echo "Deleted *.log on $HOST:~/ba_logs/ (already synced above)"
else
echo "Skipped remote log deletion -- a cron run is currently in progress on $HOST (local copy above is still up to date; rerun later to clear the remote logs)"
fi