示例#1
0
    def get_next(self):
        """
        Returns:
            Function: Command to run
        """
        self.get_next_task()

        if self.pending_task:
            AzurLaneConfig.is_hoarding_task = False
            logger.info(
                f'Pending tasks: {[f.command for f in self.pending_task]}')
            task = self.pending_task[0]
            logger.attr('Task', task)
            return task
        else:
            AzurLaneConfig.is_hoarding_task = True

        if self.waiting_task:
            logger.info('No task pending')
            task = copy.deepcopy(self.waiting_task[0])
            task.next_run = (task.next_run +
                             self.hoarding).replace(microsecond=0)
            logger.attr('Task', task)
            return task
        else:
            logger.critical('No task waiting or pending')
            logger.critical('Please enable at least one task')
            raise RequestHumanTakeover
示例#2
0
    def check_screen(self):
        """
        Screen size must be 1280x720.
        Take a screenshot before call.
        """
        # Check screen size
        width, height = self.image.size
        logger.attr('Screen_size', f'{width}x{height}')
        if not (width == 1280 and height == 720):
            logger.critical(f'Resolution not supported: {width}x{height}')
            logger.critical('Please set emulator resolution to 1280x720')
            raise RequestHumanTakeover

        # Check screen color
        # May get a pure black screenshot on some emulators.
        color = get_color(self.image, area=(0, 0, 1280, 720))
        if sum(color) < 1:
            logger.critical(
                f'Received pure black screenshots from emulator, color: {color}'
            )
            logger.critical(
                f'Screenshot method `{self.config.Emulator_ScreenshotMethod}` '
                f'may not work on emulator `{self.serial}`')
            logger.critical('Please use other screenshot methods')
            raise RequestHumanTakeover
示例#3
0
    def retry_wrapper(self, *args, **kwargs):
        """
        Args:
            self (Hermit):
        """
        init = None
        for _ in range(RETRY_TRIES):
            try:
                if callable(init):
                    self.sleep(RETRY_DELAY)
                    init()
                return func(self, *args, **kwargs)
            # Can't handle
            except RequestHumanTakeover:
                break
            # When adb server was killed
            except ConnectionResetError as e:
                logger.error(e)

                def init():
                    self.adb_reconnect()
            # When unable to send requests
            except requests.exceptions.ConnectionError as e:
                logger.error(e)
                text = str(e)
                if 'Connection aborted' in text:
                    # Hermit not installed or not running
                    # ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
                    def init():
                        self.adb_reconnect()
                        self.hermit_init()
                else:
                    # Lost connection, adb server was killed
                    # HTTPConnectionPool(host='127.0.0.1', port=20269):
                    # Max retries exceeded with url: /click?x=500&y=500
                    def init():
                        self.adb_reconnect()
            # AdbError
            except AdbError as e:
                if handle_adb_error(e):
                    def init():
                        self.adb_reconnect()
                else:
                    break
            # HermitError: {"code":-1,"msg":"error"}
            except HermitError as e:
                logger.error(e)

                def init():
                    self.adb_reconnect()
                    self.hermit_init()
            # Unknown, probably a trucked image
            except Exception as e:
                logger.exception(e)

                def init():
                    pass

        logger.critical(f'Retry {func.__name__}() failed')
        raise RequestHumanTakeover
示例#4
0
    def ascreencap_init(self):
        logger.hr('aScreenCap init')
        self.__bytepointer = 0

        arc = self.adb_shell(['getprop', 'ro.product.cpu.abi'])
        sdk = self.adb_shell(['getprop', 'ro.build.version.sdk'])
        logger.info(f'cpu_arc: {arc}, sdk_ver: {sdk}')

        if int(sdk) in range(21, 26):
            ver = "Android_5.x-7.x"
        elif int(sdk) in range(26, 28):
            ver = "Android_8.x"
        elif int(sdk) == 28:
            ver = "Android_9.x"
        else:
            ver = "0"
        filepath = os.path.join(self.config.ASCREENCAP_FILEPATH_LOCAL, ver, arc, 'ascreencap')
        if not os.path.exists(filepath):
            logger.critical('No suitable version of aScreenCap lib available for this device')
            logger.critical('Please use ADB or uiautomator2 for screenshots instead')
            raise RequestHumanTakeover

        logger.info(f'pushing {filepath}')
        self.adb_push(filepath, self.config.ASCREENCAP_FILEPATH_REMOTE)

        logger.info(f'chmod 0777 {self.config.ASCREENCAP_FILEPATH_REMOTE}')
        self.adb_shell(['chmod', '0777', self.config.ASCREENCAP_FILEPATH_REMOTE])
    def ui_goto_archives_campaign(self, mode='ex'):
        """
        Performs the operations needed to transition
        to target archive's campaign stage map
        """
        # On first run regardless of current location
        # even in target stage map, start from page_archives
        # For subsequent runs when neither reward or
        # stop_triggers occur, no need perform operations
        result = True
        if self.first_run or not self.appear(WAR_ARCHIVES_CAMPAIGN_CHECK,
                                             offset=(20, 20)):
            result = self.ui_ensure(destination=page_archives)

            WAR_ARCHIVES_SWITCH.set(mode, main=self)

            entrance = self._search_archives_entrance(
                self.config.Campaign_Event)
            if entrance is not None:
                self.ui_click(entrance,
                              appear_button=WAR_ARCHIVES_CHECK,
                              check_button=WAR_ARCHIVES_CAMPAIGN_CHECK,
                              skip_first_screenshot=True)
            else:
                logger.critical(
                    'Respective server may not yet support the chosen War Archives campaign, '
                    'check back in the next app update')
                raise RequestHumanTakeover

        # Subsequent runs all set False
        if self.first_run:
            self.first_run = False

        return result
    def check_screen_size(self):
        """
        Screen size must be 1280x720.
        Take a screenshot before call.
        """
        if self._screen_size_checked:
            return True

        orientated = False
        for _ in range(2):
            # Check screen size
            width, height = image_size(self.image)
            logger.attr('Screen_size', f'{width}x{height}')
            if width == 1280 and height == 720:
                self._screen_size_checked = True
                return True
            elif not orientated and (width == 720 and height == 1280):
                logger.info('Received orientated screenshot, handling')
                self.get_orientation()
                self.image = self._handle_orientated_image(self.image)
                orientated = True
                continue
            elif self.config.Emulator_Serial == 'wsa-0':
                self.display_resize_wsa(0)
                return False
            elif hasattr(self, 'app_is_running') and not self.app_is_running():
                logger.warning(
                    'Received orientated screenshot, game not running')
                return True
            else:
                logger.critical(f'Resolution not supported: {width}x{height}')
                logger.critical('Please set emulator resolution to 1280x720')
                raise RequestHumanTakeover
示例#7
0
    def handle_app_login(self):
        """
        Returns:
            bool: If login success

        Raises:
            RequestHumanTakeover: If login failed more than 3
        """
        for _ in range(3):
            self.device.stuck_record_clear()
            self.device.click_record_clear()
            try:
                self._handle_app_login()
                return True
            except (GameTooManyClickError, GameStuckError) as e:
                logger.warning(e)
                self.device.app_stop()
                self.device.app_start()
                continue

        logger.critical('Login failed more than 3')
        logger.critical(
            'Azur Lane server may be under maintenance, or you may lost network connection'
        )
        raise RequestHumanTakeover
示例#8
0
    def _assert_and_prepare_model_files(self):
        model_dir = self._model_dir
        model_files = [
            'label_cn.txt',
            '%s-%04d.params' % (self._model_file_prefix, self._model_epoch),
            '%s-symbol.json' % self._model_file_prefix,
        ]
        file_prepared = True
        for f in model_files:
            f = os.path.join(model_dir, f)
            if not os.path.exists(f):
                file_prepared = False
                logger.warning('can not find file %s', f)
                break

        if file_prepared:
            return

        # Disable auto downloading cnocr models when model not found.
        # get_model_file(model_dir)
        logger.warning(f'Ocr model not prepared: {model_dir}')
        logger.warning(f'Required files: {model_files}')
        logger.critical(
            'Please check if required files of pre-trained OCR model exist')
        raise RequestHumanTakeover
示例#9
0
    def run_stronghold(self):
        """
        All fleets take turns in attacking siren stronghold.

        Returns:
            bool: If success to clear.

        Pages:
            in: Siren logger (abyssal), boss appeared.
            out: If success, dangerous or safe zone.
                If failed, still in abyssal.
        """
        logger.hr(f'Stronghold clear', level=1)
        fleets = self.parse_fleet_filter()
        for fleet in fleets:
            logger.hr(f'Turn: {fleet}', level=2)
            if not isinstance(fleet, BossFleet):
                self.os_order_execute(recon_scan=False, submarine_call=True)
                continue

            result = self.run_stronghold_one_fleet(fleet)
            if result:
                return True
            else:
                continue

        logger.critical('Unable to clear boss, fleets exhausted')
        return False
示例#10
0
    def hermit_send(self, url, **kwargs):
        """
        Args:
            url (str):
            **kwargs:

        Returns:
            dict: Usually to be {"code":0,"msg":"ok"}
        """
        result = self.hermit_session.get(f'{self._hermit_url}{url}', params=kwargs, timeout=3).text
        try:
            result = json.loads(result, encoding='utf-8')
            if result['code'] != 0:
                # {"code":-1,"msg":"error"}
                raise HermitError(result)
        except (json.decoder.JSONDecodeError, KeyError):
            e = HermitError(result)
            if 'GestureDescription$Builder' in result:
                logger.error(e)
                logger.critical('Hermit cannot run on current device, hermit requires Android>=7.0')
                raise RequestHumanTakeover
            if 'accessibilityservice' in result:
                # Attempt to invoke virtual method
                # 'boolean android.accessibilityservice.AccessibilityService.dispatchGesture(
                #     android.accessibilityservice.GestureDescription,
                #     android.accessibilityservice.AccessibilityService$GestureResultCallback,
                #     android.os.Handler
                # )' on a null object reference
                logger.error('Unable to access accessibility service')
            raise e

        # Hermit only takes 2-4ms
        # Add a 50ms delay because game can't response quickly.
        self.sleep(0.05)
        return result
示例#11
0
 def app_start(self):
     logger.info(f'App start: {self.config.Emulator_PackageName}')
     try:
         self.device.app_start(self.config.Emulator_PackageName)
     except BaseError as e:
         logger.critical(e)
         raise RequestHumanTakeover
    def _ascreencap_init(self):
        logger.hr('aScreenCap init')

        arc = self.adb_exec_out(['getprop', 'ro.product.cpu.abi'
                                 ]).decode('utf-8').strip()
        sdk = self.adb_exec_out(['getprop', 'ro.build.version.sdk'
                                 ]).decode('utf-8').strip()
        logger.info(f'cpu_arc: {arc}, sdk_ver: {sdk}')

        filepath = os.path.join(self.config.ASCREENCAP_FILEPATH_LOCAL, arc,
                                'ascreencap')
        if int(sdk) not in range(21, 26) or not os.path.exists(filepath):
            logger.critical(
                'No suitable version of aScreenCap lib available for this device'
            )
            logger.critical(
                'Please use ADB or uiautomator2 for screenshots instead')
            raise RequestHumanTakeover

        logger.info(f'pushing {filepath}')
        self.adb_push([filepath, self.config.ASCREENCAP_FILEPATH_REMOTE])

        logger.info(f'chmod 0777 {self.config.ASCREENCAP_FILEPATH_REMOTE}')
        self.adb_shell(
            ['chmod', '0777', self.config.ASCREENCAP_FILEPATH_REMOTE])
示例#13
0
    def shop_buy_select_execute(self, item):
        """
        Args:
            item (Item):

        Returns:
            bool:
        """
        # Search for appropriate select grid button for item
        select = self.shop_get_select(item)

        # Get displayed stock limit; varies between shops
        # If read 0, then warn and exit as cannot safely buy
        _, _, limit = OCR_SHOP_SELECT_STOCK.ocr(self.device.image)
        if not limit:
            logger.critical(f'{item.name}\'s stock count cannot be '
                            'extracted. Advised to re-cut the asset '
                            'OCR_SHOP_SELECT_STOCK')
            raise ScriptError

        # Click in intervals until plus/minus are onscreen
        click_timer = Timer(3, count=6)
        select_offset = (500, 400)
        while 1:
            if click_timer.reached():
                self.device.click(select)
                click_timer.reset()

            # Scan for plus/minus locations; searching within
            # offset will update the click position automatically
            self.device.screenshot()
            if self.appear(SELECT_MINUS, offset=select_offset) and self.appear(SELECT_PLUS, offset=select_offset):
                break
            else:
                continue

        # Total number to purchase altogether
        total = int(self._currency // item.price)
        diff = limit - total
        if diff > 0:
            limit = total

        # Alias OCR_SHOP_SELECT_STOCK to adapt with
        # ui_ensure_index; prevent overbuying when
        # out of stock; item.price may still evaluate
        # incorrectly
        def shop_buy_select_ensure_index(image):
            current, remain, _ = OCR_SHOP_SELECT_STOCK.ocr(image)
            if not current:
                group_case = item.group.title() if len(item.group) > 2 else item.group.upper()
                logger.info(f'{group_case}(s) out of stock; exit to prevent overbuying')
                return limit
            return remain

        self.ui_ensure_index(limit, letter=shop_buy_select_ensure_index, prev_button=SELECT_MINUS,
                             next_button=SELECT_PLUS,
                             skip_first_screenshot=True)
        self.device.click(SHOP_BUY_CONFIRM_SELECT)
        return True
示例#14
0
    def os_auto_search_daemon(self, drop=None, skip_first_screenshot=True):
        """
        Raises:
            CampaignEnd: If auto search ended
            RequestHumanTakeover: If there's no auto search option.

        Pages:
            in: AUTO_SEARCH_OS_MAP_OPTION_OFF
            out: AUTO_SEARCH_OS_MAP_OPTION_OFF and info_bar_count() >= 2, if no more objects to clear on this map.
                 AUTO_SEARCH_REWARD if get auto search reward.
        """
        logger.hr('OS auto search', level=2)
        self._auto_search_battle_count = 0
        unlock_checked = True
        unlock_check_timer = Timer(5, count=10).start()
        self.ash_popup_canceled = False

        success = True
        died_timer = Timer(1.5, count=3)
        while 1:
            if skip_first_screenshot:
                skip_first_screenshot = False
            else:
                self.device.screenshot()

            if not unlock_checked and unlock_check_timer.reached():
                logger.critical('Unable to use auto search in current zone')
                logger.critical('Please finish the story mode of OpSi to unlock auto search '
                                'before using any OpSi functions')
                raise RequestHumanTakeover
            if self.is_in_map():
                self.device.stuck_record_clear()
                if not success:
                    if died_timer.reached():
                        logger.warning('Fleet died confirm')
                        break
                else:
                    died_timer.reset()
            else:
                died_timer.reset()
            if self.handle_os_auto_search_map_option(drop=drop, enable=success):
                unlock_checked = True
                continue
            if self.handle_retirement():
                # Retire will interrupt auto search, need a retry
                self.ash_popup_canceled = True
                continue
            if self.combat_appear():
                self._auto_search_battle_count += 1
                logger.attr('battle_count', self._auto_search_battle_count)
                result = self.auto_search_combat(drop=drop)
                if not result:
                    success = False
                    logger.warning('Fleet died, stop auto search')
                    continue
            if self.handle_map_event():
                # Auto search can not handle siren searching device.
                continue
示例#15
0
    def boss_clear(self, has_fleet_step=True):
        """
        All fleets take turns in attacking the boss.

        Args:
            has_fleet_step (bool):

        Returns:
            bool: If success to clear.

        Pages:
            in: Siren logger (abyssal), boss appeared.
            out: If success, dangerous or safe zone.
                If failed, still in abyssal.
        """
        logger.hr(f'BOSS clear', level=1)
        fleets = self.parse_fleet_filter()
        with self.stat.new(genre=inflection.underscore(
                self.config.task.command),
                           save=self.config.DropRecord_SaveOpsi,
                           upload=self.config.DropRecord_UploadOpsi) as drop:
            for fleet in fleets:
                logger.hr(f'Turn: {fleet}', level=2)
                if not isinstance(fleet, BossFleet):
                    self.os_order_execute(recon_scan=False,
                                          submarine_call=True)
                    continue

                # Attack
                self.fleet_set(fleet.fleet_index)
                self.handle_os_map_fleet_lock(enable=False)
                self.boss_goto(location=(0, 0),
                               has_fleet_step=has_fleet_step,
                               drop=drop)

                # End
                self.predict_radar()
                if self.radar.select(is_question=True):
                    logger.info('BOSS clear')
                    if drop.count:
                        drop.add(self.device.image)
                    self.map_exit()
                    return True

                # Standby
                self.boss_leave()
                if fleet.standby_loca != (0, 0):
                    self.boss_goto(location=fleet.standby_loca,
                                   has_fleet_step=has_fleet_step,
                                   drop=drop)
                else:
                    if drop.count:
                        drop.add(self.device.image)
                    break

        logger.critical('Unable to clear boss, fleets exhausted')
        return False
示例#16
0
 def app_stop(self):
     logger.info(f'App stop: {self.config.Emulator_PackageName}')
     try:
         self.device.app_stop(self.config.Emulator_PackageName)
         if self.config.Emulator_ControlMethod == "WSA":
             del self.device.__dict__['get_game_windows_id']
     except BaseError as e:
         logger.critical(e)
         raise RequestHumanTakeover
示例#17
0
    def hermit_enable_accessibility(self):
        """
        Turn on accessibility service for Hermit.

        Raises:
            RequestHumanTakeover: If failed and user should do it manually.
        """
        logger.hr('Enable accessibility service')
        interval = Timer(0.3)
        timeout = Timer(10, count=10).start()
        while 1:
            h = self.dump_hierarchy_adb()
            interval.wait()
            interval.reset()

            def appear(xpath):
                return bool(HierarchyButton(h, xpath))

            def appear_then_click(xpath):
                b = HierarchyButton(h, xpath)
                if b:
                    point = random_rectangle_point(b.button)
                    logger.info(f'Click {point2str(*point)} @ {b}')
                    self.click_adb(*point)
                    return True
                else:
                    return False

            if appear_then_click(
                    '//*[@text="Hermit" and @resource-id="android:id/title"]'):
                continue
            if appear_then_click(
                    '//*[@class="android.widget.Switch" and @checked="false"]'
            ):
                continue
            if appear_then_click('//*[@resource-id="android:id/button1"]'):
                # Just plain click here
                # Can't use uiautomator once hermit has access to accessibility service,
                # or uiautomator will get the access.
                break
            if appear(
                    '//*[@class="android.widget.Switch" and @checked="true"]'):
                raise HermitError(
                    'Accessibility service already enable but get error')

            # End
            if timeout.reached():
                logger.critical(
                    'Unable to turn on accessibility service for Hermit')
                logger.critical(
                    '\n\n'
                    'Please do this manually:\n'
                    '1. Find "Hermit" in accessibility setting and click it\n'
                    '2. Turn it ON and click OK\n'
                    '3. Switch back to AzurLane\n')
                raise RequestHumanTakeover
示例#18
0
def possible_reasons(*args):
    """
    Show possible reasons

        Possible reason #1: <reason_1>
        Possible reason #2: <reason_2>
    """
    for index, reason in enumerate(args):
        index += 1
        logger.critical(f'Possible reason #{index}: {reason}')
示例#19
0
 def app_stop(self):
     if not self.config.Error_HandleError:
         logger.critical('No app stop/start, because HandleError disabled')
         logger.critical(
             'Please enable Alas.Error.HandleError or manually login to AzurLane'
         )
         raise RequestHumanTakeover
     super().app_stop()
     self.stuck_record_clear()
     self.click_record_clear()
示例#20
0
 def config(self):
     try:
         config = AzurLaneConfig(config_name=self.config_name)
         return config
     except RequestHumanTakeover:
         logger.critical('Request human takeover')
         exit(1)
     except Exception as e:
         logger.exception(e)
         exit(1)
示例#21
0
 def device(self):
     try:
         from module.device.device import Device
         device = Device(config=self.config)
         return device
     except RequestHumanTakeover:
         logger.critical('Request human takeover')
         exit(1)
     except Exception as e:
         logger.exception(e)
         exit(1)
示例#22
0
    def os_explore(self):
        for _ in range(2):
            try:
                self._os_explore()
            except OSExploreError:
                logger.info('Go back to NY, explore again')
                self.config.OpsiExplore_LastZone = 0
                self.globe_goto(0)

        logger.critical('Failed to solve the locked zone')
        raise RequestHumanTakeover
示例#23
0
 def _api(self):
     method = self.config.DropRecord_API
     if method == 'default':
         return 'https://azurstats.lyoko.io/api/upload/'
     elif method == 'cn_gz_reverse_proxy':
         return 'https://service-rjfzwz8i-1301182309.gz.apigw.tencentcs.com/api/upload'
     elif method == 'cn_sh_reverse_proxy':
         return 'https://service-nlvjetab-1301182309.sh.apigw.tencentcs.com/api/upload'
     else:
         logger.critical('Invalid upload API, please check your settings')
         raise ScriptError('Invalid upload API')
示例#24
0
 def config(self):
     try:
         config = AzurLaneConfig(config_name=self.config_name)
         # Set server before loading any buttons.
         server.server = deep_get(config.data, keys='Alas.Emulator.Server', default='cn')
         return config
     except RequestHumanTakeover:
         logger.critical('Request human takeover')
         exit(1)
     except Exception as e:
         logger.exception(e)
         exit(1)
示例#25
0
    def ui_get_current_page(self, skip_first_screenshot=True):
        """
        Args:
            skip_first_screenshot:

        Returns:
            Page:
        """
        if not skip_first_screenshot or not hasattr(
                self.device, 'image') or self.device.image is None:
            self.device.screenshot()

        # Known pages
        for page in self.ui_pages:
            if page.check_button is None:
                continue
            if self.ui_page_appear(page=page):
                logger.attr('UI', page.name)
                self.ui_current = page
                return page

        # Unknown page but able to handle
        logger.info('Unknown ui page')
        if self.appear_then_click(GOTO_MAIN,
                                  offset=(20, 20)) or self.ui_additional():
            logger.info('Goto page_main')
            self.ui_current = page_unknown
            self.ui_goto(page_main, skip_first_screenshot=True)

        # Unknown page, need manual switching
        if hasattr(self, 'ui_current'):
            logger.warning(
                f'Unrecognized ui_current, using previous: {self.ui_current}')
        else:
            logger.info('Unable to goto page_main')
            logger.attr('EMULATOR__SCREENSHOT_METHOD',
                        self.config.Emulator_ScreenshotMethod)
            logger.attr('EMULATOR__CONTROL_METHOD',
                        self.config.Emulator_ControlMethod)
            logger.attr('SERVER', self.config.SERVER)
            logger.warning('Starting from current page is not supported')
            logger.warning(
                f'Supported page: {[str(page) for page in self.ui_pages]}')
            logger.warning(
                f'Supported page: Any page with a "HOME" button on the upper-right'
            )
            if not self.device.app_is_running():
                raise GameNotRunningError('Game not running')
            else:
                logger.critical(
                    'Please switch to a supported page before starting Alas')
                raise RequestHumanTakeover
示例#26
0
    def run_process(config_name,
                    func: str,
                    q: queue.Queue,
                    e: threading.Event = None) -> None:
        # Setup logger
        set_file_logger(name=config_name)
        set_func_logger(func=q.put)

        # Set server before loading any buttons.
        import module.config.server as server
        from module.config.config import AzurLaneConfig

        AzurLaneConfig.stop_event = e
        config = AzurLaneConfig(config_name=config_name)
        server.server = deep_get(config.data,
                                 keys="Alas.Emulator.Server",
                                 default="cn")
        try:
            # Run alas
            if func == "Alas":
                from alas import AzurLaneAutoScript

                if e is not None:
                    AzurLaneAutoScript.stop_event = e
                AzurLaneAutoScript(config_name=config_name).loop()
            elif func == "Daemon":
                from module.daemon.daemon import AzurLaneDaemon

                AzurLaneDaemon(config=config_name, task="Daemon").run()
            elif func == "OpsiDaemon":
                from module.daemon.os_daemon import AzurLaneDaemon

                AzurLaneDaemon(config=config_name, task="OpsiDaemon").run()
            elif func == "AzurLaneUncensored":
                from module.daemon.uncensored import AzurLaneUncensored

                AzurLaneUncensored(config=config_name,
                                   task="AzurLaneUncensored").run()
            elif func == "Benchmark":
                from module.daemon.benchmark import Benchmark

                Benchmark(config=config_name, task="Benchmark").run()
            elif func == "GameManager":
                from module.daemon.game_manager import GameManager

                GameManager(config=config_name, task="GameManager").run()
            else:
                logger.critical("No function matched")
            logger.info(f"[{config_name}] exited. Reason: Finish\n")
        except Exception as e:
            logger.exception(e)
示例#27
0
    def run_process(config_name,
                    func: str,
                    q: queue.Queue,
                    e: threading.Event = None) -> None:
        # Setup logger
        qh = QueueHandler(q)
        formatter = logging.Formatter(
            fmt='%(asctime)s.%(msecs)03d | %(levelname)s | %(message)s',
            datefmt='%H:%M:%S')
        webconsole = logging.StreamHandler(stream=qh)
        webconsole.setFormatter(formatter)
        logger.addHandler(webconsole)

        # Set server before loading any buttons.
        import module.config.server as server
        from module.config.config import AzurLaneConfig
        AzurLaneConfig.stop_event = e
        config = AzurLaneConfig(config_name=config_name)
        server.server = deep_get(config.data,
                                 keys='Alas.Emulator.Server',
                                 default='cn')
        try:
            # Run alas
            if func == 'Alas':
                from alas import AzurLaneAutoScript
                if e is not None:
                    AzurLaneAutoScript.stop_event = e
                AzurLaneAutoScript(config_name=config_name).loop()
            elif func == 'Daemon':
                from module.daemon.daemon import AzurLaneDaemon
                AzurLaneDaemon(config=config_name, task='Daemon').run()
            elif func == 'OpsiDaemon':
                from module.daemon.os_daemon import AzurLaneDaemon
                AzurLaneDaemon(config=config_name, task='OpsiDaemon').run()
            elif func == 'AzurLaneUncensored':
                from module.daemon.uncensored import AzurLaneUncensored
                AzurLaneUncensored(config=config_name,
                                   task='AzurLaneUncensored').run()
            elif func == 'Benchmark':
                from module.daemon.benchmark import Benchmark
                Benchmark(config=config_name, task='Benchmark').run()
            elif func == 'GameManager':
                from module.daemon.game_manager import GameManager
                GameManager(config=config_name, task='GameManager').run()
            else:
                logger.critical("No function matched")
            logger.info(f"[{config_name}] exited. Reason: Finish")
        except Exception as e:
            logger.exception(e)
示例#28
0
 def app_start(self):
     logger.info(f'App start: {self.config.Emulator_PackageName}')
     try:
         if self.config.Emulator_WSA:
             self.adb_shell(['wm', 'size', '1280x720', '-d', '0'])
             self.adb_shell([
                 'am', 'start', '--display', '0',
                 self.config.Emulator_PackageName +
                 '/com.manjuu.azurlane.MainActivity'
             ])
         else:
             self.device.app_start(self.config.Emulator_PackageName)
     except BaseError as e:
         logger.critical(e)
         raise RequestHumanTakeover
示例#29
0
    def retry_wrapper(self, *args, **kwargs):
        """
        Args:
            self (AScreenCap):
        """
        init = None
        for _ in range(RETRY_TRIES):
            try:
                if callable(init):
                    self.sleep(RETRY_DELAY)
                    init()
                return func(self, *args, **kwargs)
            # Can't handle
            except RequestHumanTakeover:
                break
            # When adb server was killed
            except ConnectionResetError as e:
                logger.error(e)

                def init():
                    self.adb_disconnect(self.serial)
                    self.adb_connect(self.serial)
            # When ascreencap is not installed
            except AscreencapError as e:
                logger.error(e)

                def init():
                    self.ascreencap_init()
            # AdbError
            except AdbError as e:
                if handle_adb_error(e):

                    def init():
                        self.adb_disconnect(self.serial)
                        self.adb_connect(self.serial)
                else:
                    break

            # Unknown, probably a trucked image
            except Exception as e:
                logger.exception(e)

                def init():
                    pass

        logger.critical(f'Retry {func.__name__}() failed')
        raise RequestHumanTakeover
示例#30
0
    def load_campaign(self, name, folder='campaign_main'):
        """
        Args:
            name (str): Name of .py file under module.campaign.
            folder (str): Name of the file folder under campaign.

        Returns:
            bool: If load.
        """
        if hasattr(self, 'name') and name == self.name:
            return False

        self.name = name
        self.folder = folder

        if folder.startswith('campaign_'):
            self.stage = '-'.join(name.split('_')[1:3])
        if folder.startswith('event') or folder.startswith('war_archives'):
            self.stage = name

        try:
            self.module = importlib.import_module('.' + name,
                                                  f'campaign.{folder}')
        except ModuleNotFoundError:
            logger.warning(f'Map file not found: campaign.{folder}.{name}')
            folder = f'./campaign/{folder}'
            if not os.path.exists(folder):
                logger.warning(f'Folder not exists: {folder}')
            else:
                files = [f[:-3] for f in os.listdir(folder) if f[-3:] == '.py']
                logger.warning(f'Existing files: {files}')

            logger.critical(
                f'Possible reason #1: This event ({folder}) does not have {name}'
            )
            logger.critical(
                f'Possible reason #2: You are using an old Alas, '
                'please check for update, or make map files yourself using dev_tools/map_extractor.py'
            )
            raise RequestHumanTakeover

        config = copy.deepcopy(self.config).merge(self.module.Config())
        device = self.device
        self.campaign = self.module.Campaign(config=config, device=device)

        return True