def _sos_is_appear_at_chapter(self, chapter): """ Args: chapter (int): 3 to 10. Returns: bool: Pages: in: page_campaign out: page_campaign, may in different chapter. """ self.ensure_campaign_ui(name=f'{chapter}-4', mode='normal') confirm_timer = Timer(1.5, count=3).start() while 1: self.device.screenshot() try: self.campaign_get_entrance('X-5') logger.info(f'Found SOS stage in chapter {chapter}') return True except CampaignNameError: if confirm_timer.reached(): logger.info(f'No SOS stage in chapter {chapter}') return False else: continue
def _guild_operations_ensure(self, skip_first_screenshot=True): """ Ensure guild operation is loaded After entering guild operation, background loaded first, then dispatch/boss """ confirm_timer = Timer(1.5, count=3).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear(GUILD_OPERATIONS_JOIN, interval=3): confirm_timer.reset() if self.image_color_count(GUILD_OPERATIONS_MONTHLY_COUNT, color=(255, 93, 90), threshold=221, count=20): self.device.click(GUILD_OPERATIONS_CLICK_SAFE_AREA) else: self.device.click(GUILD_OPERATIONS_JOIN) continue # End if self.appear(GUILD_BOSS_ENTER) or self.appear( GUILD_OPERATIONS_ACTIVE_CHECK, offset=(20, 20)): if not self.info_bar_count() and confirm_timer.reached(): break
def wait_until_camera_stable(self, skip_first_screenshot=True): """ Wait until homo_loca stabled. DETECTION_BACKEND must be 'homography'. """ logger.hr('Wait until camera stable') record = None confirm_timer = Timer(0.6, count=2).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() self.update_os() current = self.view.backend.homo_loca logger.attr('homo_loca', current) if record is None or (current is not None and np.linalg.norm( np.subtract(current, record)) < 3): if confirm_timer.reached(): break else: confirm_timer.reset() record = current logger.info('Camera stabled')
def set(self, status, main, skip_first_screenshot=True): """ Args: status (str): main (ModuleBase): skip_first_screenshot (bool): Returns: bool: """ changed = False warning_show_timer = Timer(5, count=10).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: main.device.screenshot() current = self.get(main=main) logger.attr(self.name, current) if current == status: return changed if current == 'unknown': if warning_show_timer.reached(): logger.warning(f'Unknown {self.name} switch') warning_show_timer.reset() continue for data in self.status_list: if data['status'] == current: main.device.click(data['click_button']) main.device.sleep(data['sleep']) changed = True
def story_skip(self): if self.story_popup_timout.started() and not self.story_popup_timout.reached(): if self.handle_popup_confirm('STORY_SKIP'): self.story_popup_timout = Timer(10) self.interval_reset(STORY_SKIP) self.interval_reset(STORY_LETTERS_ONLY) return True if self.appear(STORY_LETTER_BLACK) and self.appear_then_click(STORY_LETTERS_ONLY, offset=True, interval=2): self.story_popup_timout.reset() return True if self._story_option_timer.reached() and self.appear(STORY_SKIP, offset=True, interval=0): options = self._story_option_buttons() if len(options): self.device.click(options[0]) self._story_option_timer.reset() self.story_popup_timout.reset() self.interval_reset(STORY_SKIP) self.interval_reset(STORY_LETTERS_ONLY) return True if self.appear_then_click(STORY_SKIP, offset=True, interval=2): self.story_popup_timout.reset() return True if self.appear_then_click(GAME_TIPS, offset=(20, 20), interval=2): self.story_popup_timout.reset() return True return False
def handle_in_map_with_enemy_searching(self): if not self.is_in_map(): return False timeout = Timer(self.MAP_ENEMY_SEARCHING_TIMEOUT_SECOND) appeared = False while 1: if self.is_in_map(): timeout.start() else: timeout.reset() if self.handle_in_stage(): return True if self.handle_story_skip(): self.ensure_no_story() timeout.limit = 10 timeout.reset() # End if self.enemy_searching_appear(): appeared = True else: if appeared: self.handle_enemy_flashing() self.device.sleep(0.3) logger.info('Enemy searching appeared.') break self.enemy_searching_color_initial() if timeout.reached(): logger.info('Enemy searching timeout.') break self.device.screenshot() return True
def story_skip(self): if self.story_popup_timout.started( ) and not self.story_popup_timout.reached(): if self.handle_popup_confirm('STORY_SKIP'): self.story_popup_timout = Timer(10) self.interval_reset(STORY_SKIP) self.interval_reset(STORY_LETTERS_ONLY) return True if self.appear_then_click(STORY_SKIP, offset=True, interval=2): self.story_popup_timout.reset() return True if self.appear(STORY_LETTER_BLACK) and self.appear_then_click( STORY_LETTERS_ONLY, offset=True, interval=2): self.story_popup_timout.reset() return True if self.appear_then_click(STORY_CHOOSE, offset=True, interval=2): self.story_popup_timout.reset() return True if self.appear_then_click(STORY_CHOOSE_2, offset=True, interval=2): self.story_popup_timout.reset() return True if self.appear_then_click(GAME_TIPS, offset=(20, 20), interval=2): self.story_popup_timout.reset() return True return False
def _ash_enter_from_map(self, skip_first_screenshot=True): """ Pages: in: is_in_map out: is_in_ash """ in_map_timeout = Timer(2, count=3) while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if in_map_timeout.reached() and self.is_in_map(): self.device.click(ASH_COLLECT_STATUS) in_map_timeout.reset() continue if self.appear_then_click(ASH_ENTER_CONFIRM, offset=(20, 20), interval=2): continue if self.appear_then_click(BEACON_ENTER, offset=(20, 20), interval=2): continue if self._handle_ash_beacon_reward(): continue # End: if self.appear(ASH_START, offset=(30, 30)): break
def globe_focus_to(self, zone): """ Args: zone (str, int, Zone): Name in CN/EN/JP/TW, zone id, or Zone instance. Pages: in: IN_GLOBE out: IN_GLOBE, zone selected, ZONE_ENTRANCE """ zone = self.name_to_zone(zone) logger.info(f'Globe focus_to: {zone.zone_id}') interval = Timer(2, count=2) while 1: if self.handle_zone_pinned(): self.globe_update() continue self.globe_in_sight(zone) if interval.reached_and_reset(): self.device.click(self.zone_to_button(zone)) self.device.sleep(0.3) self.globe_update() if self.is_zone_pinned(): if self.get_globe_pinned_zone() == zone: logger.attr('Globe_pinned', zone) break
def gacha_load_ensure(self, skip_first_screenshot=True): """ Switching between sidebar clicks for some takes a bit of processing before fully loading like guild logistics Args: skip_first_screenshot (bool): Returns: bool: Whether expected assets loaded completely """ ensure_timeout = Timer(3, count=6).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() # End results = [self.appear(button) for button in GACHA_LOAD_ENSURE_BUTTONS] if any(results): return True # Exception if ensure_timeout.reached(): logger.warning('Wait for loaded assets is incomplete, ensure not guaranteed') return False
def _handle_app_login(self): """ Pages: in: Any page out: page_main """ logger.hr('App login') confirm_timer = Timer(1.5, count=4).start() login_success = False while 1: self.device.screenshot() if self.handle_get_items(save_get_items=False): continue if self.handle_get_ship(): continue if self.appear_then_click(LOGIN_ANNOUNCE, offset=(30, 30), interval=5): continue if self.appear(EVENT_LIST_CHECK, offset=(30, 30), interval=5): self.device.click(BACK_ARROW) continue if self.appear_then_click(MAINTENANCE_ANNOUNCE, offset=(30, 30), interval=5): continue if self.appear_then_click(LOGIN_GAME_UPDATE, offset=(30, 30), interval=5): continue if self.appear_then_click(LOGIN_RETURN_SIGN, offset=(30, 30), interval=5): continue if server.server == 'cn': if self.appear_then_click(LOGIN_CONFIRM, interval=5): continue if self.handle_popup_confirm('LOGIN'): continue if self.handle_urgent_commission(save_get_items=False): continue if self.appear_then_click(GOTO_MAIN, offset=(30, 30), interval=5): continue if self.appear_then_click(LOGIN_CHECK, interval=5): if not login_success: logger.info('Login success') login_success = True if self.appear(MAIN_CHECK): if confirm_timer.reached(): logger.info('Login to main confirm') break else: confirm_timer.reset() self.config.start_time = datetime.now() return True
def research_project_start(self, project, skip_first_screenshot=True): """ Args: project (ResearchProject): skip_first_screenshot: Returns: bool: If start success. """ logger.info(f'Research project: {project}') if project in self.projects: index = self.projects.index(project) else: logger.warning( f'The project to start: {project} is not in known projects') return False logger.info(f'Research project: {index}') available = False click_timer = Timer(10) while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() max_rgb = np.max(rgb2gray(self.image_crop(RESEARCH_UNAVAILABLE))) # Don't use interval here, RESEARCH_CHECK already appeared 5 seconds ago if click_timer.reached() and self.appear(RESEARCH_CHECK, offset=(20, 20)): i = (index - self._research_project_offset) % 5 logger.info( f'Project offset: {self._research_project_offset}, project {index} is at {i}' ) self.device.click(RESEARCH_ENTRANCE[i]) self._research_project_offset = (index - 2) % 5 self.ensure_research_stable() click_timer.reset() continue if max_rgb > 235 and self.appear_then_click( RESEARCH_START, offset=(5, 20), interval=10): available = True continue if self.handle_popup_confirm('RESEARCH_START'): continue # End if self.appear(RESEARCH_STOP, offset=(20, 20)): # RESEARCH_STOP is a semi-transparent button, color will vary depending on the background. self.research_detail_quit() # self.ensure_no_info_bar(timeout=3) # Research started self.research_project_started = project return True if not available and max_rgb <= 235 and self.appear( RESEARCH_UNAVAILABLE, offset=(5, 20)): logger.info('Not enough resources to start this project') self.research_detail_quit() self.research_project_started = None return False
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
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
def multi_click(self, button, n, interval=(0.1, 0.2)): click_timer = Timer(0.1) for _ in range(n): remain = ensure_time(interval) - click_timer.current() if remain > 0: self.sleep(remain) click_timer.reset() self.click(button)
def ensure_no_info_bar(self, timeout=0.6): timeout = Timer(timeout) timeout.start() while 1: self.device.screenshot() self.handle_info_bar() if timeout.reached(): break
def appear(self, button, offset=0, interval=0, threshold=None): """ Args: button (Button, Template, HierarchyButton, str): offset (bool, int): interval (int, float): interval between two active events. threshold (int, float): 0 to 1 if use offset, bigger means more similar, 0 to 255 if not use offset, smaller means more similar Returns: bool: Examples: Image detection: ``` self.device.screenshot() self.appear(Button(area=(...), color=(...), button=(...)) self.appear(Template(file='...') ``` Hierarchy detection (detect elements with xpath): ``` self.device.dump_hierarchy() self.appear('//*[@resource-id="..."]') ``` """ button = self.ensure_button(button) self.device.stuck_record_add(button) if interval: if button.name in self.interval_timer: if self.interval_timer[button.name].limit != interval: self.interval_timer[button.name] = Timer(interval) else: self.interval_timer[button.name] = Timer(interval) if not self.interval_timer[button.name].reached(): return False if isinstance(button, HierarchyButton): appear = bool(button) elif offset: if isinstance(offset, bool): offset = self.config.BUTTON_OFFSET appear = button.match(self.device.image, offset=offset, threshold=self.config.BUTTON_MATCH_SIMILARITY if threshold is None else threshold) else: appear = button.appear_on( self.device.image, threshold=self.config.COLOR_SIMILAR_THRESHOLD if threshold is None else threshold) if appear and interval: self.interval_timer[button.name].reset() return appear
def os_mission_overview_accept(self): """ Accept all missions in mission overview. Returns: bool: True if all missions accepted or no mission found. False if unable to accept more missions. Pages: in: is_in_map out: is_in_map """ logger.hr('OS mission overview accept', level=1) # is_in_map self.os_map_goto_globe(unpin=False) # is_in_globe self.ui_click(MISSION_OVERVIEW_ENTER, check_button=MISSION_OVERVIEW_CHECK, offset=(200, 20), retry_wait=3, skip_first_screenshot=True) # MISSION_OVERVIEW_CHECK confirm_timer = Timer(1, count=3).start() skip_first_screenshot = True success = True while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear_then_click(MISSION_OVERVIEW_ACCEPT, offset=(20, 20), interval=0.2): confirm_timer.reset() continue else: # End if confirm_timer.reached(): success = True break if self.info_bar_count(): logger.info( 'Unable to accept missions, because reached the maximum number of missions' ) success = False break # is_in_globe self.ui_back(appear_button=MISSION_OVERVIEW_CHECK, check_button=self.is_in_globe, skip_first_screenshot=True) # is_in_map self.os_globe_goto_map() return success
def _enhance_choose_simple(self, skip_first_screenshot=True): """ Info: Simplified version of the legacy _enhance_choose Performs enhancements solely based on appearance of info bars Pages: in: page_ship_enhance, without info_bar out: EQUIP_CONFIRM """ end_activate_timer = Timer(2, count=2) attempt_count = 0 next_count = 0 while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear(EQUIP_CONFIRM, offset=(30, 30)): return True if not end_activate_timer.reached_and_reset(): continue ensured = self.equip_sidebar_ensure(index=4) if ensured: self.wait_until_appear(ENHANCE_RECOMMEND, offset=(5, 5), skip_first_screenshot=True) else: continue if self.info_bar_count(): if attempt_count >= 1: logger.info('Unable to enhance this ship, swipe to next') swiped = self.equip_view_next( check_button=ENHANCE_RECOMMEND) self.ensure_no_info_bar() if not swiped or next_count >= 3: return False else: attempt_count = 0 logger.info( f'Try next ship: {3 - next_count}/3 remaining until give up' ) next_count += 1 continue attempt_count += 1 if self.appear_then_click(ENHANCE_RECOMMEND, offset=(5, 5), interval=2): self.device.sleep(0.3) self.device.click(ENHANCE_CONFIRM)
def commission_receive(self, skip_first_screenshot=True): """ Args: skip_first_screenshot: Returns: bool: If rewarded. Pages: in: page_reward out: page_commission """ logger.hr('Reward receive') reward = False click_timer = Timer(1) with self.stat.new( 'commission', save=self.config.DropRecord_SaveCommission, upload=self.config.DropRecord_UploadCommission) as drop: while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() for button in [ EXP_INFO_S_REWARD, GET_ITEMS_1, GET_ITEMS_2, GET_ITEMS_3, GET_SHIP ]: if self.appear(button, interval=1): self.ensure_no_info_bar(timeout=1) drop.add(self.device.image) REWARD_SAVE_CLICK.name = button.name self.device.click(REWARD_SAVE_CLICK) click_timer.reset() reward = True continue if click_timer.reached() and self.appear_then_click( REWARD_1, interval=1): click_timer.reset() reward = True continue if click_timer.reached() and self.appear_then_click( REWARD_GOTO_COMMISSION, offset=(20, 20)): click_timer.reset() continue # End if self.appear(COMMISSION_CHECK, offset=(20, 20)): # Leaving at page_commission # Commission rewards may appear too slow, causing stuck in UI switching break return reward
def _data_key_collect_confirm(self, skip_first_screenshot=True): """ Wait for results: get_items or cancel popup. Pages: in: page_archives out: page_archives """ confirm_timer = Timer(1.5, count=3).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear_then_click(GET_ITEMS_1, genre='get_items', offset=5): confirm_timer.reset() continue if self.handle_popup_confirm('DATA_KEY_LIMIT'): # If it's in 29/30 means user is not doing war achieves frequently, # no need to bother losing one key, just make it full filled. confirm_timer.reset() continue # End if self.appear(WAR_ARCHIVES_CHECK, offset=(20, 20)): if confirm_timer.reached(): return True else: confirm_timer.reset()
def _data_key_collect_confirm(self, skip_first_screenshot=True): """ Wait for results: get_items or cancel popup. Pages: in: page_archives out: page_archives """ confirm_timer = Timer(1.5, count=3).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear(GET_ITEMS_1, offset=5, interval=3): # Clicking any blank area in page_archives will exit to page_campaign. # Click WAR_ARCHIVES_EX to avoid this, if double clicking GET_ITEMS. self.device.click(WAR_ARCHIVES_EX_ON) confirm_timer.reset() continue if self.handle_popup_confirm('DATA_KEY_LIMIT'): # If it's in 29/30 means user is not doing war achieves frequently, # no need to bother losing one key, just make it full filled. confirm_timer.reset() continue # End if self.appear(WAR_ARCHIVES_CHECK, offset=(20, 20)): if confirm_timer.reached(): return True else: confirm_timer.reset()
def ui_click( self, click_button, check_button, appear_button=None, additional=None, confirm_wait=1, offset=(30, 30), retry_wait=10, skip_first_screenshot=False, ): """ Args: click_button (Button): check_button (Button, callable): appear_button (Button, callable): additional (callable): confirm_wait (int, float): offset (bool, int, tuple): retry_wait (int, float): skip_first_screenshot (bool): """ logger.hr("UI click") if appear_button is None: appear_button = click_button click_timer = Timer(retry_wait, count=retry_wait // 0.5) confirm_wait = confirm_wait if additional is not None else 0 confirm_timer = Timer(confirm_wait, count=confirm_wait // 0.5).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if (isinstance(check_button, Button) and self.appear( check_button, offset=offset)) or (callable(check_button) and check_button()): if confirm_timer.reached(): break else: confirm_timer.reset() if click_timer.reached(): if (isinstance(appear_button, Button) and self.appear(appear_button, offset=offset)) or ( callable(appear_button) and appear_button()): self.device.click(click_button) click_timer.reset() continue if additional is not None: if additional(): continue
def port_mission_accept(self): """ Accept all missions in port. Deprecated since 2022.01.13, missions are shown only in overview, no longer to be shown at ports. Returns: bool: True if all missions accepted or no mission found. False if unable to accept more missions. Pages: in: PORT_CHECK out: PORT_CHECK """ if not self.appear(PORT_MISSION_RED_DOT): logger.info('No available missions in this port') return True self.ui_click(PORT_GOTO_MISSION, appear_button=PORT_CHECK, check_button=PORT_MISSION_CHECK, skip_first_screenshot=True) confirm_timer = Timer(1.5, count=3).start() skip_first_screenshot = True success = True while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.appear_then_click(PORT_MISSION_ACCEPT, offset=(20, 20), interval=0.2): confirm_timer.reset() continue else: # End if confirm_timer.reached(): success = True break if self.info_bar_count(): logger.info( 'Unable to accept missions, because reached the maximum number of missions' ) success = False break self.ui_back(appear_button=PORT_MISSION_CHECK, check_button=PORT_CHECK, skip_first_screenshot=True) return success
def ui_click(self, click_button, check_button, appear_button=None, additional_button=None, offset=(20, 20), retry_wait=10, additional_button_interval=3, skip_first_screenshot=False): """ Args: click_button (Button): check_button (Button, callable): appear_button (Button): additional_button (Button, list[Button], callable): additional_button_interval (int, float): offset (bool, int, tuple): retry_wait (int, float): skip_first_screenshot (bool): """ logger.hr('UI click') if appear_button is None: appear_button = click_button if not isinstance(additional_button, list): additional_button = [additional_button] click_timer = Timer(retry_wait, count=retry_wait // 0.5) while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if isinstance(check_button, Button) and self.appear(check_button, offset=offset): break if callable(check_button) and check_button(): break for button in additional_button: if button is None: continue if isinstance(button, Button): self.appear_then_click(button, offset=offset, interval=additional_button_interval) continue if callable(button) and button(): continue if click_timer.reached() and self.appear(appear_button, offset=offset): self.device.click(click_button) click_timer.reset() continue
def _active_edit(self): timer = Timer(1) while 1: self.device.screenshot() if timer.reached() and self.appear_then_click(EQUIP_EDIT_INACTIVE): timer.reset() # End if self.appear(EQUIP_EDIT_ACTIVE): self.device.sleep((0.2, 0.3)) break
def _set_2x_book_status(self, status, check_button, box_button, skip_first_screenshot=True): """ Set appropriate 2x book setting with corresponding status and buttons Built with retry mechanism that limits to 3 attempts that span 3 second intervals each Args: status (string): on or off check_button (Button): button to check before attempting to click box_button (Button): button to click and image color count against skip_first_screenshot (bool): namesake Returns: bool: True if detected having set correctly False can occur for 2 reasons either assets insufficient to detect properly or 2x book setting is absent """ confirm_timer = Timer(1).start() clicked_threshold = 0 while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if clicked_threshold > 3: break if self.appear(check_button, offset=self._auto_search_menu_offset, interval=3): box_button.load_offset(check_button) enabled = self.image_color_count(box_button.button, color=(156, 255, 82), threshold=221, count=20) if (status == 'on' and enabled) or (status == 'off' and not enabled): return True if (status == 'on' and not enabled) or (status == 'off' and enabled): self.device.click(box_button) clicked_threshold += 1 if not clicked_threshold and confirm_timer.reached(): logger.info('Map do not have 2x book setting') return False logger.warning(f'Wait time has expired; Cannot set 2x book setting') return False
def ensure_no_zone_pinned(self, skip_first_screenshot=True): confirm_timer = Timer(1, count=2).start() while 1: if skip_first_screenshot: skip_first_screenshot = False else: self.device.screenshot() if self.handle_zone_pinned(): confirm_timer.reset() else: if confirm_timer.reached(): break
def _equip_enter(self, enter): enter_timer = Timer(5) while 1: if enter_timer.reached(): self.device.long_click(enter, duration=(1.5, 1.7)) enter_timer.reset() self.device.screenshot() # End if self.appear(EQUIPMENT_OPEN): break
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