From 407029dffa0d7aa6ba76f3002a685b1320214800 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:20:31 +0800 Subject: [PATCH 1/7] Fix: [ALAS] BlueStacks_nxt emulator auto-run --- module/device/platform/platform_windows.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/device/platform/platform_windows.py b/module/device/platform/platform_windows.py index de00efeca..ce5c2d177 100644 --- a/module/device/platform/platform_windows.py +++ b/module/device/platform/platform_windows.py @@ -98,8 +98,8 @@ class PlatformWindows(PlatformBase, EmulatorManager): # Nox.exe -clone:Nox_1 self.execute(f'"{exe}" -clone:{instance.name}') elif instance == Emulator.BlueStacks5: - # HD-Player.exe -instance Pie64 - self.execute(f'"{exe}" -instance {instance.name}') + # HD-Player.exe --instance Pie64 + self.execute(f'"{exe}" --instance {instance.name}') elif instance == Emulator.BlueStacks4: # BlueStacks\Client\Bluestacks.exe -vmname Android_1 self.execute(f'"{exe}" -vmname {instance.name}') From 2621cb5d53461f2572302b0d119520b8f04a0ebd Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:50:05 +0800 Subject: [PATCH 2/7] Fix: Weekly farming was skipped if immersifiers are preserved for ornament --- tasks/rogue/entry/entry.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tasks/rogue/entry/entry.py b/tasks/rogue/entry/entry.py index 2f89e6b64..9286f45e0 100644 --- a/tasks/rogue/entry/entry.py +++ b/tasks/rogue/entry/entry.py @@ -375,13 +375,7 @@ class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonRogueUI # Expired, do rogue pass elif self.config.stored.SimulatedUniverse.is_full(): - if self.config.RogueWorld_UseImmersifier and self.config.stored.Immersifier.value > 0: - logger.info( - 'Reached weekly point limit but still have immersifiers left, continue to use them') - if ornament: - logger.info('Ornament enabled, skip farming rogue') - raise RogueReachedWeeklyPointLimit - elif self.config.RogueWorld_WeeklyFarming and not self.config.stored.SimulatedUniverseFarm.is_full(): + if self.config.RogueWorld_WeeklyFarming and not self.config.stored.SimulatedUniverseFarm.is_full(): logger.info( 'Reached weekly point limit but still continue to farm materials') logger.attr( @@ -389,6 +383,12 @@ class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonRogueUI if self.config.is_cloud_game and not self.config.stored.CloudRemainSeasonPass.value: logger.warning('Running WeeklyFarming on cloud game without season pass may cause fee, skip') raise RogueReachedWeeklyPointLimit + elif self.config.RogueWorld_UseImmersifier and self.config.stored.Immersifier.value > 0: + logger.info( + 'Reached weekly point limit but still have immersifiers left, continue to use them') + if ornament: + logger.info('Ornament enabled, skip farming rogue') + raise RogueReachedWeeklyPointLimit else: raise RogueReachedWeeklyPointLimit else: From 83c9fb9b061d307bf5d806dc524ecac0673ad2b4 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:47:59 +0800 Subject: [PATCH 3/7] Fix: Running free weekly for planner --- tasks/combat/combat.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/combat/combat.py b/tasks/combat/combat.py index fd58c9d1b..c5a1bb1e2 100644 --- a/tasks/combat/combat.py +++ b/tasks/combat/combat.py @@ -133,6 +133,9 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo return False if not self.handle_combat_prepare(): return False + if self.is_doing_planner and self.combat_wave_cost == 0: + logger.info('Free combat gets nothing cannot meet planner needs') + return False self.device.click(COMBAT_PREPARE) self.interval_reset(COMBAT_PREPARE) trial += 1 From 00f3bf749542c6db1aee77d2cc08081e1c3f5189 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 15 Jul 2024 22:09:21 +0800 Subject: [PATCH 4/7] Add: [ALAS] Add interval on dump_hierarchy() --- module/device/app_control.py | 20 ++++++++++++++++++++ module/device/device.py | 6 ++++++ 2 files changed, 26 insertions(+) diff --git a/module/device/app_control.py b/module/device/app_control.py index cf6c3a529..3d3791b22 100644 --- a/module/device/app_control.py +++ b/module/device/app_control.py @@ -1,9 +1,11 @@ from lxml import etree +from module.base.timer import Timer from module.device.method.adb import Adb from module.device.method.uiautomator_2 import Uiautomator2 from module.device.method.utils import HierarchyButton from module.device.method.wsa import WSA +from module.exception import ScriptError from module.logger import logger @@ -12,6 +14,7 @@ class AppControl(Adb, WSA, Uiautomator2): # Use ADB for all # See https://github.com/openatx/uiautomator2/issues/565 _app_u2_family = [] + _hierarchy_interval = Timer(0.1) def app_is_running(self) -> bool: method = self.config.Emulator_ControlMethod @@ -44,11 +47,28 @@ class AppControl(Adb, WSA, Uiautomator2): else: self.app_stop_adb() + def hierarchy_timer_set(self, interval=None): + if interval is None: + interval = 0.1 + elif isinstance(interval, (int, float)): + # No limitation for manual set in code + pass + else: + logger.warning(f'Unknown hierarchy interval: {interval}') + raise ScriptError(f'Unknown hierarchy interval: {interval}') + + if interval != self._hierarchy_interval.limit: + logger.info(f'Hierarchy interval set to {interval}s') + self._hierarchy_interval.limit = interval + def dump_hierarchy(self) -> etree._Element: """ Returns: etree._Element: Select elements with `self.hierarchy.xpath('//*[@text="Hermit"]')` for example. """ + self._hierarchy_interval.wait() + self._hierarchy_interval.reset() + # method = self.config.Emulator_ControlMethod # if method in AppControl._app_u2_family: # self.hierarchy = self.dump_hierarchy_uiautomator2() diff --git a/module/device/device.py b/module/device/device.py index 494914176..9847232f7 100644 --- a/module/device/device.py +++ b/module/device/device.py @@ -1,6 +1,8 @@ import collections import itertools +from lxml import etree + # Patch pkg_resources before importing adbutils and uiautomator2 from module.device.pkg_resources import get_distribution @@ -157,6 +159,10 @@ class Device(Screenshot, Control, AppControl): return self.image + def dump_hierarchy(self) -> etree._Element: + self.stuck_record_check() + return super().dump_hierarchy() + def release_during_wait(self): # Scrcpy server is still sending video stream, # stop it during wait From 00f1d04694c5161587b42a30271ebcf1be5fc316 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:39:46 +0800 Subject: [PATCH 5/7] Fix: Set game client if package name is set so setting Emulator_GameClient can be fool-proof --- module/device/connection.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/module/device/connection.py b/module/device/connection.py index fdc03a994..366423afc 100644 --- a/module/device/connection.py +++ b/module/device/connection.py @@ -1023,7 +1023,14 @@ class Connection(ConnectionAttr): self.package = packages[0] # Set config if set_config: - self.config.Emulator_PackageName = server_.to_server(self.package) + with self.config.multi_set(): + self.config.Emulator_PackageName = server_.to_server(self.package) + if self.package in server_.VALID_CLOUD_PACKAGE: + if self.config.Emulator_GameClient != 'cloud_android': + self.config.Emulator_GameClient = 'cloud_android' + else: + if self.config.Emulator_GameClient != 'android': + self.config.Emulator_GameClient = 'android' # Set server # logger.info('Server changed, release resources') # set_server(self.package) From f93445b70cc442f7a8250f67ac3576feb5599942 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:41:37 +0800 Subject: [PATCH 6/7] Fix: Simplify cloud login calls, remove nested retries --- tasks/base/ui.py | 4 ++- tasks/login/cloud.py | 85 ++++++++++++++++++-------------------------- tasks/login/login.py | 13 ++++--- 3 files changed, 47 insertions(+), 55 deletions(-) diff --git a/tasks/base/ui.py b/tasks/base/ui.py index 88e62b249..c0614c0d5 100644 --- a/tasks/base/ui.py +++ b/tasks/base/ui.py @@ -61,7 +61,9 @@ class UI(MainPage): def cloud_login(): if self.config.is_cloud_game: from tasks.login.login import Login - Login(config=self.config, device=self.device).cloud_login() + login = Login(config=self.config, device=self.device) + self.device.dump_hierarchy() + login.cloud_try_enter_game() timeout = Timer(10, count=20).start() while 1: diff --git a/tasks/login/cloud.py b/tasks/login/cloud.py index 11702a6d4..5e47ebe19 100644 --- a/tasks/login/cloud.py +++ b/tasks/login/cloud.py @@ -72,7 +72,7 @@ class XPath: 悬浮窗及侧边栏元素 """ # 悬浮窗 - FLOAT_WINDOW = '//*[@class="android.widget.ImageView"]' + FLOAT_WINDOW = '//*[@package="com.miHoYo.cloudgames.hkrpg" and @class="android.widget.ImageView"]' # 退出按钮,返回登录页面 FLOAT_EXIT = '//*[@resource-id="com.miHoYo.cloudgames.hkrpg:id/iv_exit"]' # 弹出侧边栏的 节点信息 @@ -342,13 +342,16 @@ class LoginAndroidCloud(ModuleBase): logger.attr('Net state', None) return False - def cloud_ensure_ingame(self): + def cloud_enter_game(self): """ + Note that cloud game needs to be started before calling, + hierarchy needs to be updated before calling + Pages: - in: Any + in: Any page in cloud game out: page_main """ - logger.hr('Cloud ensure ingame', level=1) + logger.hr('Cloud enter game', level=1) with self.config.multi_set(): if self.config.Emulator_GameClient != 'cloud_android': @@ -358,48 +361,27 @@ class LoginAndroidCloud(ModuleBase): if self.config.Optimization_WhenTaskQueueEmpty != 'close_game': self.config.Optimization_WhenTaskQueueEmpty = 'close_game' - for _ in range(3): - if self.device.app_is_running(): - logger.info('Cloud game is already running') - self.device.dump_hierarchy() - - if self.appear(XPath.START_GAME): - logger.info('Cloud game is in main page') - self._cloud_get_remain() - self._cloud_enter() - return True - elif self.appear(XPath.FLOAT_WINDOW): - logger.info('Cloud game is in game') - return True - elif self.appear(XPath.FLOAT_DELAY): - logger.info('Cloud game is in game with float window expanded') - self._cloud_setting_exit() - return True - elif self.appear(XPath.POPUP_CONFIRM): - logger.info('Cloud game have a popup') - self._cloud_enter() - return True - else: - try: - self._cloud_start() - except GameNotRunningError: - continue - self._cloud_get_remain() - self._cloud_enter() - return True - else: - logger.info('Cloud game is not running') - self.device.app_start() - try: - self._cloud_start() - except GameNotRunningError: - continue - self._cloud_get_remain() - self._cloud_enter() - return True - - logger.error('Failed to enter cloud game after 3 trials') - return False + if self.appear(XPath.START_GAME): + logger.info('Cloud game is in main page') + self._cloud_get_remain() + self._cloud_enter() + return True + elif self.appear(XPath.FLOAT_WINDOW): + logger.info('Cloud game is in game') + return True + elif self.appear(XPath.FLOAT_DELAY): + logger.info('Cloud game is in game with float window expanded') + self._cloud_setting_exit() + return True + elif self.appear(XPath.POPUP_CONFIRM): + logger.info('Cloud game have a popup') + self._cloud_enter() + return True + else: + self._cloud_start() + self._cloud_get_remain() + self._cloud_enter() + return True def is_in_cloud_page(self): if self.appear(XPath.START_GAME): @@ -418,15 +400,16 @@ class LoginAndroidCloud(ModuleBase): logger.info('Not in cloud page') return False - def cloud_login(self): + def cloud_try_enter_game(self): """ + Note that hierarchy needs to be updated before calling + Pages: in: Any page in cloud game out: page_main """ - self.device.dump_hierarchy() if self.is_in_cloud_page(): - self.cloud_ensure_ingame() + self.cloud_enter_game() return True return False @@ -522,5 +505,7 @@ class LoginAndroidCloud(ModuleBase): if __name__ == '__main__': self = LoginAndroidCloud('src') - self.cloud_login() + self.device.app_start() + self.device.dump_hierarchy() + self.cloud_enter_game() self.cloud_keep_alive() diff --git a/tasks/login/login.py b/tasks/login/login.py index 88d5ca733..412220ac0 100644 --- a/tasks/login/login.py +++ b/tasks/login/login.py @@ -90,18 +90,23 @@ class Login(UI, LoginAndroidCloud): def app_start(self): logger.hr('App start') + self.device.app_start() + if self.config.is_cloud_game: - self.cloud_ensure_ingame() + self.device.dump_hierarchy() + self.cloud_enter_game() else: - self.device.app_start() self.handle_app_login() def app_restart(self): logger.hr('App restart') self.device.app_stop() + self.device.app_start() + if self.config.is_cloud_game: - self.cloud_ensure_ingame() + self.device.dump_hierarchy() + self.cloud_enter_game() else: - self.device.app_start() self.handle_app_login() + self.config.task_delay(server_update=True) From 420a6f1e6dfe2d30cc57b3dc5dcd260dd5bf23a5 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:45:02 +0800 Subject: [PATCH 7/7] Fix: [ALAS] Device.config was never updated during scheduler run --- module/alas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/module/alas.py b/module/alas.py index f03f0a18b..9fe6ea460 100644 --- a/module/alas.py +++ b/module/alas.py @@ -258,6 +258,7 @@ class AzurLaneAutoScript: task = self.get_next_task() # Init device and change server _ = self.device + self.device.config = self.config # Skip first restart if self.is_first_task and task == 'Restart': logger.info('Skip task `Restart` at scheduler start')