diff --git a/aas.py b/aas.py index 4a3997c..afe1205 100644 --- a/aas.py +++ b/aas.py @@ -11,6 +11,10 @@ class ArisuAutoSweeper(AzurLaneAutoScript): from tasks.login.login import Login Login(self.config, device=self.device).app_start() + def stop(self): + from tasks.login.login import Login + Login(self.config, device=self.device).app_stop() + def goto_main(self): from tasks.login.login import Login from tasks.base.ui import UI diff --git a/module/alas.py b/module/alas.py index 5abfd0a..34d1d7b 100644 --- a/module/alas.py +++ b/module/alas.py @@ -62,6 +62,18 @@ class AzurLaneAutoScript: logger.exception(e) exit(1) + def restart(self): + raise NotImplemented + + def start(self): + raise NotImplemented + + def stop(self): + raise NotImplemented + + def goto_main(self): + raise NotImplemented + def run(self, command): try: self.device.screenshot() @@ -211,7 +223,7 @@ class AzurLaneAutoScript: method = self.config.Optimization_WhenTaskQueueEmpty if method == 'close_game': logger.info('Close game during wait') - self.device.app_stop() + self.run('stop') release_resources() self.device.release_during_wait() if not self.wait_until(task.next_run): diff --git a/module/base/base.py b/module/base/base.py index d3bd400..06ba45f 100644 --- a/module/base/base.py +++ b/module/base/base.py @@ -6,6 +6,7 @@ from module.base.timer import Timer from module.base.utils import * from module.config.config import AzurLaneConfig from module.device.device import Device +from module.device.method.utils import HierarchyButton from module.logger import logger from module.webui.setting import cached_class_property @@ -132,9 +133,56 @@ class ModuleBase: return appear - appear = match_template + def xpath(self, xpath) -> HierarchyButton: + if isinstance(xpath, str): + return HierarchyButton(self.device.hierarchy, xpath) + else: + return xpath + + def xpath_appear(self, xpath: str, interval=0): + button = self.xpath(xpath) + + self.device.stuck_record_add(button) + + if interval and not self.interval_is_reached(button, interval=interval): + return False + + appear = bool(button) + + if appear and interval: + self.interval_reset(button, interval=interval) + + return appear + + def appear(self, button, interval=0, similarity=0.85): + """ + Args: + button (Button, ButtonWrapper, HierarchyButton, str): + interval (int, float): interval between two active events. + + Returns: + bool: + + Examples: + Template match: + ``` + self.device.screenshot() + self.appear(POPUP_CONFIRM) + ``` + + Hierarchy detection (detect elements with xpath): + ``` + self.device.dump_hierarchy() + self.appear('//*[@resource-id="..."]') + ``` + """ + if isinstance(button, (HierarchyButton, str)): + return self.xpath_appear(button, interval=interval) + else: + return self.match_template(button, interval=interval, similarity=similarity) def appear_then_click(self, button, interval=5, similarity=0.85): + button = self.xpath(button) appear = self.appear(button, interval=interval, similarity=similarity) if appear: self.device.click(button) @@ -309,7 +357,7 @@ class ModuleBase: """ if not self.config.Error_SaveError: return - + logger.info('screenshot_tracking_add') data = self.device.screenshot_deque[-1] image = data['image'] diff --git a/module/device/app_control.py b/module/device/app_control.py index 390c505..cf6c3a5 100644 --- a/module/device/app_control.py +++ b/module/device/app_control.py @@ -49,11 +49,14 @@ class AppControl(Adb, WSA, Uiautomator2): Returns: etree._Element: Select elements with `self.hierarchy.xpath('//*[@text="Hermit"]')` for example. """ - method = self.config.Emulator_ControlMethod - if method in AppControl._app_u2_family: - self.hierarchy = self.dump_hierarchy_uiautomator2() - else: - self.hierarchy = self.dump_hierarchy_adb() + # method = self.config.Emulator_ControlMethod + # if method in AppControl._app_u2_family: + # self.hierarchy = self.dump_hierarchy_uiautomator2() + # else: + # self.hierarchy = self.dump_hierarchy_adb() + + # Using uiautomator2 + self.hierarchy = self.dump_hierarchy_uiautomator2() return self.hierarchy def xpath_to_button(self, xpath: str) -> HierarchyButton: diff --git a/module/device/method/utils.py b/module/device/method/utils.py index 67bd654..9f81352 100644 --- a/module/device/method/utils.py +++ b/module/device/method/utils.py @@ -18,9 +18,11 @@ except ImportError: # We expect `screencap | nc 192.168.0.1 20298` instead of `screencap '|' nc 192.168.80.1 20298` import adbutils import subprocess + adbutils._utils.list2cmdline = subprocess.list2cmdline adbutils._device.list2cmdline = subprocess.list2cmdline + # BaseDevice.shell() is missing a check_okay() call before reading output, # resulting in an `OKAY` prefix in output. def shell(self, @@ -40,6 +42,7 @@ except ImportError: output = c.read_until_close() return output.rstrip() if rstrip else output + adbutils._device.BaseDevice.shell = shell from module.base.decorator import cached_property @@ -323,7 +326,7 @@ class HierarchyButton: if res: return res[0] else: - return 'HierarchyButton' + return self.xpath @cached_property def count(self): @@ -333,10 +336,17 @@ class HierarchyButton: def exist(self): return self.count == 1 + @cached_property + def attrib(self): + if self.exist: + return self.nodes[0].attrib + else: + return {} + @cached_property def area(self): if self.exist: - bounds = self.nodes[0].attrib.get("bounds") + bounds = self.attrib.get("bounds") lx, ly, rx, ry = map(int, re.findall(r"\d+", bounds)) return lx, ly, rx, ry else: @@ -355,6 +365,28 @@ class HierarchyButton: @cached_property def focused(self): if self.exist: - return self.nodes[0].attrib.get("focused").lower() == 'true' + return self.attrib.get("focused").lower() == 'true' else: return False + + @cached_property + def text(self): + if self.exist: + return self.attrib.get("text").strip() + else: + return "" + + +class AreaButton: + def __init__(self, area, name='AREA_BUTTON'): + self.area = area + self.color = () + self.name = name + self.button = area + + def __str__(self): + return self.name + + def __bool__(self): + # Cannot appear + return False