From bf03867f0bec3d6dcac96a75ed8040b922cd4929 Mon Sep 17 00:00:00 2001 From: positnuec <93694981+positnuec@users.noreply.github.com> Date: Mon, 30 Mar 2026 21:38:28 +0800 Subject: [PATCH] Feat: Restart emulator on its network disconnection --- alas.py | 22 ++++++++++++++++------ module/device/method/adb.py | 17 +++++++++++++++++ module/exception.py | 4 ++++ module/handler/login.py | 15 ++++++++++++++- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/alas.py b/alas.py index b71fa27ee..06b635c53 100644 --- a/alas.py +++ b/alas.py @@ -87,6 +87,20 @@ class AzurLaneAutoScript: self.config.task_call('Restart') self.device.sleep(10) return False + except EmulatorNetworkError as e: + logger.error(e) + self.save_error_log() + if self.device.is_emulator: + logger.info('Game update stuck 3 times. Checking network status on both ends.') + self.checker.check_now() + if self.checker.is_available() and not self.device.is_network_available(): + logger.critical('Emulator network is disconnected despite host being online.') + logger.warning('Restarting emulator to fix internal network.') + self.device.emulator_start() + deep_set(self.failure_record, keys='Restart', value=1) + self.config.task_call('Restart') + self.device.sleep(10) + return False except GameBugError as e: logger.warning(e) self.save_error_log() @@ -560,12 +574,8 @@ class AzurLaneAutoScript: _ = self.device self.device.config = self.config # Skip first restart - if task == 'Restart': - if self.is_first_task: - logger.info('Skip task `Restart` at scheduler start') - else: - from module.handler.login import LoginHandler - LoginHandler(self.config, self.device).app_restart() + if task == 'Restart' and self.is_first_task: + logger.info('Skip task `Restart` at scheduler start') self.config.task_delay(server_update=True) del_cached_property(self, 'config') continue diff --git a/module/device/method/adb.py b/module/device/method/adb.py index ff14afcb0..8ee6c92c0 100644 --- a/module/device/method/adb.py +++ b/module/device/method/adb.py @@ -433,3 +433,20 @@ class Adb(Connection): # Parse with lxml hierarchy = etree.fromstring(content) return hierarchy + + @retry + def is_network_available(self) -> bool: + """ + Check if emulator internet connection is available by pinging public DNS. + + Returns: + bool: True if network is available + """ + options = ['-c', '4'] + if self.is_mumu12_family: + options.extend(['-i', '0.2']) + for ip in ['223.5.5.5', '8.8.8.8']: + result = self.adb_shell(['ping', *options, ip]).lower() + if 'ttl=' in result: + return True + return False diff --git a/module/exception.py b/module/exception.py index e0d3ecf39..5d7654fd9 100644 --- a/module/exception.py +++ b/module/exception.py @@ -53,6 +53,10 @@ class GameNotRunningError(Exception): pass +class EmulatorNetworkError(Exception): + pass + + class GamePageUnknownError(Exception): pass diff --git a/module/handler/login.py b/module/handler/login.py index 3fca7a642..d37ff8437 100644 --- a/module/handler/login.py +++ b/module/handler/login.py @@ -8,7 +8,8 @@ from uiautomator2.xpath import XPath, XPathSelector import module.config.server as server from module.base.timer import Timer -from module.base.utils import color_similarity_2d, crop, random_rectangle_point +from module.base.utils import color_similarity_2d, crop, random_rectangle_point, rgb2luma +from module.exception import GameNotRunningError, GameTooManyClickError, EmulatorNetworkError from module.handler.assets import * from module.logger import logger from module.map.assets import * @@ -18,6 +19,8 @@ from module.ui.ui import UI class LoginHandler(UI): + _login_update_error_count = 0 + def _handle_app_login(self): """ Pages: @@ -138,11 +141,20 @@ class LoginHandler(UI): GameStuckError: GameTooManyClickError: GameNotRunningError: + EmulatorNetworkError: """ logger.info('handle_app_login') self.device.screenshot_interval_set(1.0) try: self._handle_app_login() + except GameTooManyClickError as e: + if 'LOGIN_GAME_UPDATE' in str(e): + self.__class__._login_update_error_count += 1 + logger.warning(f'Error on LOGIN_GAME_UPDATE: {self.__class__._login_update_error_count} times') + if self.__class__._login_update_error_count >= 3: + self.__class__._login_update_error_count = 0 + raise EmulatorNetworkError('Emulator network is offline assumed') + raise finally: self.device.screenshot_interval_set() @@ -163,6 +175,7 @@ class LoginHandler(UI): self.device.app_start() self.handle_app_login() # self.ensure_no_unfinished_campaign() + self.config.task_delay(server_update=True) def ensure_no_unfinished_campaign(self, confirm_wait=3): """