class ArknightsHelper(object): def __init__( self, current_strength=None, # 当前理智 adb_host=None, # 当前绑定到的设备 out_put=True, # 是否有命令行输出 call_by_gui=False): # 是否为从 GUI 程序调用 if adb_host is None: adb_host = config.ADB_HOST try: self.adb = ADBShell(adb_host=adb_host) except ConnectionRefusedError as e: logger.error("错误: {}".format(e)) logger.info("尝试启动本地adb") try: os.system(config.ADB_ROOT + "\\adb kill-server") os.system(config.ADB_ROOT + "\\adb start-server") self.adb = ADBShell(adb_host=adb_host) except Exception as e: logger.error("尝试解决失败,错误: {}".format(e)) logger.info("建议检查adb版本夜神模拟器正确的版本为: 1.0.36") self.__is_game_active = False self.__call_by_gui = call_by_gui self.CURRENT_STRENGTH = 100 self.selector = BattleSelector() self.ocr_active = True self.is_called_by_gui = call_by_gui self.viewport = self.adb.get_screen_shoot().size self.operation_time = [] if DEBUG_LEVEL >= 1: self.__print_info() logger.debug("成功初始化模块") def __print_info(self): logger.info('当前系统信息:') logger.info('ADB 服务器:\t%s:%d', *config.ADB_SERVER) logger.info('分辨率:\t%dx%d', *self.viewport) logger.info('OCR 引擎:\t%s', ocr.engine.info) logger.info('截图路径 (legacy):\t%s', config.SCREEN_SHOOT_SAVE_PATH) logger.info('存储路径 (legacy):\t%s', config.STORAGE_PATH) if config.enable_baidu_api: logger.info( '%s', """百度API配置信息: APP_ID\t{app_id} API_KEY\t{api_key} SECRET_KEY\t{secret_key} """.format(app_id=config.APP_ID, api_key=config.API_KEY, secret_key=config.SECRET_KEY)) def __del(self): self.adb.run_device_cmd("am force-stop {}".format( config.ArkNights_PACKAGE_NAME)) def destroy(self): self.__del() def check_game_active(self): # 启动游戏 需要手动调用 logger.debug("base.check_game_active") current = self.adb.run_device_cmd( 'dumpsys window windows | grep mCurrentFocus').decode( errors='ignore') logger.debug("正在尝试启动游戏") logger.debug(current) if config.ArkNights_PACKAGE_NAME in current: self.__is_game_active = True logger.debug("游戏已启动") else: self.adb.run_device_cmd("am start -n {}/{}".format( config.ArkNights_PACKAGE_NAME, config.ArkNights_ACTIVITY_NAME)) logger.debug("成功启动游戏") self.__is_game_active = True @staticmethod def __wait( n=10, # 等待时间中值 MANLIKE_FLAG=True): # 是否在此基础上设偏移量 if MANLIKE_FLAG: m = uniform(0, 0.3) n = uniform(n - m * 0.5 * n, n + m * n) sleep(n) def mouse_click( self, # 点击一个按钮 XY): # 待点击的按钮的左上和右下坐标 assert (self.viewport == (1280, 720)) logger.debug("base.mouse_click") xx = randint(XY[0][0], XY[1][0]) yy = randint(XY[0][1], XY[1][1]) logger.info("接收到点击坐标并传递xx:{}和yy:{}".format(xx, yy)) self.adb.touch_tap((xx, yy)) self.__wait(TINY_WAIT, MANLIKE_FLAG=True) def tap_rect(self, rc): hwidth = (rc[2] - rc[0]) / 2 hheight = (rc[3] - rc[1]) / 2 midx = rc[0] + hwidth midy = rc[1] + hheight xdiff = max(-1, min(1, gauss(0, 0.2))) ydiff = max(-1, min(1, gauss(0, 0.2))) tapx = int(midx + xdiff * hwidth) tapy = int(midy + ydiff * hheight) self.adb.touch_tap((tapx, tapy)) self.__wait(TINY_WAIT, MANLIKE_FLAG=True) def tap_quadrilateral(self, pts): pts = np.asarray(pts) acdiff = max(0, min(2, gauss(1, 0.2))) bddiff = max(0, min(2, gauss(1, 0.2))) halfac = (pts[2] - pts[0]) / 2 m = pts[0] + halfac * acdiff pt2 = pts[1] if bddiff > 1 else pts[3] halfvec = (pt2 - m) / 2 finalpt = m + halfvec * bddiff self.adb.touch_tap(tuple(int(x) for x in finalpt)) self.__wait(TINY_WAIT, MANLIKE_FLAG=True) def module_login(self): logger.debug("base.module_login") logger.info("发送坐标LOGIN_QUICK_LOGIN: {}".format( CLICK_LOCATION['LOGIN_QUICK_LOGIN'])) self.mouse_click(CLICK_LOCATION['LOGIN_QUICK_LOGIN']) self.__wait(BIG_WAIT) logger.info("发送坐标LOGIN_START_WAKEUP: {}".format( CLICK_LOCATION['LOGIN_START_WAKEUP'])) self.mouse_click(CLICK_LOCATION['LOGIN_START_WAKEUP']) self.__wait(BIG_WAIT) def module_battle_slim( self, c_id=None, # 待战斗的关卡编号 set_count=1000, # 战斗次数 check_ai=True, # 是否检查代理指挥 **kwargs): # 扩展参数: ''' :param sub 是否为子程序 (是否为module_battle所调用) :param auto_close 是否自动关闭, 默认为 false :param self_fix 是否尝试自动修复, 默认为 false :param MAX_TIME 最大检查轮数, 默认在 config 中设置, 每隔一段时间进行一轮检查判断战斗是否结束 建议自定义该数值以便在出现一定失误, 超出最大判断次数后有一定的自我修复能力 :return: True 完成指定次数的战斗 False 理智不足, 退出战斗 ''' logger.debug("base.module_battle_slim") sub = kwargs["sub"] \ if "sub" in kwargs else False auto_close = kwargs["auto_close"] \ if "auto_close" in kwargs else False if not sub: logger.info("战斗-选择{}...启动".format(c_id)) if set_count == 0: return True self.operation_time = [] try: for count in range(set_count): logger.info("开始第 %d 次战斗", count + 1) self.operation_once_statemachine(c_id, ) logger.info("第 %d 次战斗完成", count + 1) if count != set_count - 1: # 2019.10.06 更新逻辑后,提前点击后等待时间包括企鹅物流 if config.reporter: self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) else: self.__wait(BIG_WAIT, MANLIKE_FLAG=True) except StopIteration: logger.error('未能进行第 %d 次战斗', count + 1) remain = set_count - count - 1 if remain > 0: logger.error('已忽略余下的 %d 次战斗', remain) logger.info("等待返回{}关卡界面".format(c_id)) self.__wait(SMALL_WAIT, True) if not sub: if auto_close: logger.info("简略模块{}结束,系统准备退出".format(c_id)) self.__wait(120, False) self.__del() else: logger.info("简略模块{}结束".format(c_id)) return True else: logger.info("当前任务{}结束,准备进行下一项任务".format(c_id)) return True class operation_once_state: def __init__(self): self.state = None self.stop = False self.operation_start = None self.first_wait = True def operation_once_statemachine(self, c_id): smobj = ArknightsHelper.operation_once_state() def on_prepare(smobj): count_times = 0 while True: screenshot = self.adb.get_screen_shoot() recoresult = imgreco.before_operation.recognize(screenshot) not_in_scene = False if not recoresult['AP']: # ASSUMPTION: 只有在战斗前界面才能识别到右上角体力 not_in_scene = True if recoresult['consume'] is None: # ASSUMPTION: 所有关卡都显示并能识别体力消耗 not_in_scene = True logger.info('当前画面关卡:%s', recoresult['operation']) if (not not_in_scene) and c_id is not None: # 如果传入了关卡 ID,检查识别结果 if recoresult['operation'] != c_id: not_in_scene = True if not_in_scene: count_times += 1 if count_times <= 7: logger.warning('不在关卡界面,继续等待……') self.__wait(TINY_WAIT, False) continue else: logger.error('{}次检测后都不再关卡界面,退出进程'.format(count_times)) raise StopIteration() else: break self.CURRENT_STRENGTH = int(recoresult['AP'].split('/')[0]) logger.info('当前理智 %d, 关卡消耗 %d', self.CURRENT_STRENGTH, recoresult['consume']) if self.CURRENT_STRENGTH < int(recoresult['consume']): logger.error('理智不足') raise StopIteration() if not recoresult['delegated']: logger.info('设置代理指挥') self.tap_rect( imgreco.before_operation.get_delegate_rect(self.viewport)) logger.info("开始行动") self.tap_rect( imgreco.before_operation.get_start_operation_rect( self.viewport)) smobj.state = on_troop def on_troop(smobj): count_times = 0 while True: self.__wait(TINY_WAIT, False) screenshot = self.adb.get_screen_shoot() recoresult = imgreco.before_operation.check_confirm_troop_rect( screenshot) if recoresult: logger.info('确认编队') break else: count_times += 1 if count_times <= 7: logger.warning('等待确认编队') continue else: logger.error('{}次检测后不再确认编队界面'.format(count_times)) raise StopIteration() self.tap_rect( imgreco.before_operation.get_confirm_troop_rect(self.viewport)) smobj.operation_start = monotonic() smobj.state = on_operation def on_operation(smobj): if smobj.first_wait: if len(self.operation_time) == 0: wait_time = BATTLE_NONE_DETECT_TIME else: wait_time = sum(self.operation_time) / len( self.operation_time) - 7 logger.info('等待 %d s' % wait_time) self.__wait(wait_time, MANLIKE_FLAG=False) smobj.first_wait = False t = monotonic() - smobj.operation_start logger.info('已进行 %.1f s,判断是否结束', t) screenshot = self.adb.get_screen_shoot() if imgreco.end_operation.check_level_up_popup(screenshot): logger.info("检测到升级") self.operation_time.append(t) smobj.state = on_level_up_popup return if imgreco.end_operation.check_end_operation(screenshot): logger.info('战斗结束') self.operation_time.append(t) self.__wait(SMALL_WAIT) smobj.state = on_end_operation return logger.info('战斗未结束') self.__wait(BATTLE_FINISH_DETECT) def on_level_up_popup(smobj): self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) logger.info('关闭升级提示') self.tap_rect( imgreco.end_operation.get_dismiss_level_up_popup_rect( self.viewport)) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) smobj.state = on_end_operation def on_end_operation(smobj): screenshot = self.adb.get_screen_shoot() logger.info('离开结算画面') self.tap_rect( imgreco.end_operation.get_dismiss_end_operation_rect( self.viewport)) try: # 掉落识别 drops = imgreco.end_operation.recognize(screenshot) logger.info('掉落识别结果:%s', repr(drops)) _penguin_report(drops) except Exception as e: logger.error('', exc_info=True) smobj.stop = True smobj.state = on_prepare smobj.stop = False smobj.operation_start = 0 while not smobj.stop: oldstate = smobj.state smobj.state(smobj) if smobj.state != oldstate: logger.debug('state changed to %s', smobj.state.__name__) def back_to_main(self): # 回到主页 logger.debug("base.back_to_main") logger.info("返回主页...") while True: screenshot = self.adb.get_screen_shoot() if imgreco.main.check_main(screenshot): break # 检查是否有返回按钮 if imgreco.common.check_nav_button(screenshot): logger.info('发现返回按钮,点击返回') self.tap_rect( imgreco.common.get_nav_button_back_rect(self.viewport)) # FIXME: 检查基建退出提示 self.__wait(SMALL_WAIT) # 点击返回按钮之后重新检查 continue if imgreco.common.check_get_item_popup(screenshot): logger.info('当前为获得物资画面,关闭') self.tap_rect( imgreco.common.get_reward_popup_dismiss_rect( self.viewport)) self.__wait(SMALL_WAIT) continue # 检查是否在设置画面 if imgreco.common.check_setting_scene(screenshot): logger.info("当前为设置/邮件画面,返回") self.tap_rect( imgreco.common.get_setting_back_rect(self.viewport)) self.__wait(SMALL_WAIT) continue # 检测是否有关闭按钮 rect, confidence = imgreco.common.find_close_button(screenshot) if confidence > 0.9: logger.info("发现关闭按钮") self.tap_rect(rect) self.__wait(SMALL_WAIT) continue raise RuntimeError('未知画面') logger.info("已回到主页") def module_battle( self, # 完整的战斗模块 c_id, # 选择的关卡 set_count=1000): # 作战次数 logger.debug("base.module_battle") assert (self.viewport == (1280, 720)) self.back_to_main() self.__wait(3, MANLIKE_FLAG=False) self.selector.id = c_id logger.info("发送坐标BATTLE_CLICK_IN: {}".format( CLICK_LOCATION['BATTLE_CLICK_IN'])) self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_IN']) self.battle_selector(c_id) # 选关 self.module_battle_slim(c_id, set_count=set_count, check_ai=True, sub=True) return True def main_handler(self, task_list=None, clear_tasks=False, auto_close=True): logger.debug("base.main_handler") if task_list is None: task_list = OrderedDict() logger.info("装载模块...") logger.info("战斗模块...启动") flag = False if task_list.__len__() == 0: logger.fatal("任务清单为空!") for c_id, count in task_list.items(): if c_id not in MAIN_TASK_SUPPORT.keys(): raise IndexError("无此关卡!") logger.info("战斗{} 启动".format(c_id)) self.selector.id = c_id flag = self.module_battle(c_id, count) if flag: if self.__call_by_gui or auto_close is False: logger.info("所有模块执行完毕") else: if clear_tasks: self.clear_daily_task() logger.info("所有模块执行完毕... 60s后退出") self.__wait(60) self.__del() else: if self.__call_by_gui or auto_close is False: logger.error("发生未知错误... 进程已结束") else: logger.error("发生未知错误... 60s后退出") self.__wait(60) self.__del() def battle_selector(self, c_id, first_battle_signal=True): # 选关 logger.debug("base.battle_selector") assert (self.viewport == (1280, 720)) mode = self.selector.id_checker(c_id) # 获取当前关卡所属章节 if mode == 1: if first_battle_signal: logger.info("发送坐标BATTLE_SELECT_MAIN_TASK: {}".format( CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK'])) self.mouse_click(XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK']) logger.info( "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'])) self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) # 拖动到正确的地方 if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys( ) or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys(): if c_id[0].isnumeric(): x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]] else: x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]] logger.info("拖动 {} 次".format(x)) for x in range(0, x): logger.info( "发送滑动坐标BATTLE_TO_MAP_RIGHT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'])) self.adb.touch_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) # 章节选择 if c_id[0].isnumeric(): logger.info("发送坐标BATTLE_SELECT_MAIN_TASK_{}: {}".format( c_id[0], CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format( c_id[0])])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])]) elif c_id[0] == "S": logger.info("发送坐标BATTLE_SELECT_MAIN_TASK_{}: {}".format( c_id[1], CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format( c_id[1])])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])]) else: raise IndexError("C_ID Error") self.__wait(3) # 章节选择结束 # 拖动 logger.info( "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'])) self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.__wait(SMALL_WAIT) logger.info( "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'])) self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.__wait(SMALL_WAIT) logger.info( "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'])) self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) # 拖动到正确的地方 if c_id in MAIN_TASK_BATTLE_SWIPE.keys(): x = MAIN_TASK_BATTLE_SWIPE[c_id] logger.info("拖动 {} 次".format(x)) for x in range(0, x): logger.info( "发送滑动坐标BATTLE_TO_MAP_RIGHT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'])) self.adb.touch_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) logger.info("发送坐标BATTLE_SELECT_MAIN_TASK_{}: {}".format( c_id, CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)]) else: self.__wait(MEDIUM_WAIT) elif mode == 2: try: X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[0:2]] except Exception as e: logger.error('\tclick_location 文件配置错误', exc_info=True) X = None exit(0) if first_battle_signal: logger.info( "发送滑动坐标BATTLE_TO_MAP_LEFT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_LEFT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'])) self.adb.touch_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) logger.info("发送坐标BATTLE_SELECT_MATERIAL_COLLECTION: {}".format( CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION'])) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION']) logger.info( "发送坐标BATTLE_SELECT_MATERIAL_COLLECTION_{}: {}".format( X, CLICK_LOCATION[ 'BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)]) logger.info( "发送坐标BATTLE_SELECT_MATERIAL_COLLECTION_X-{}: {}".format( c_id[-1], CLICK_LOCATION[ 'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format( c_id[-1])])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]) else: logger.info( "发送坐标BATTLE_SELECT_MATERIAL_COLLECTION_X-{}: {}".format( c_id[-1], CLICK_LOCATION[ 'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format( c_id[-1])])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]) elif mode == 3: try: X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[3]] except Exception as e: logger.error('\tclick_location 文件配置错误', exc_info=True) X = None exit(0) if first_battle_signal: logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH: {}".format( CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH'])) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH']) logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH_PR-{}: {}".format( X, CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format( X)])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)]) logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH_PR-X-{}: {}".format( c_id[-1], CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format( c_id[-1])])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]) else: logger.info("发送坐标BATTLE_SELECT_CHIP_SEARCH_PR-X-{}: {}".format( c_id[-1], CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format( c_id[-1])])) self.mouse_click(XY=CLICK_LOCATION[ 'BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]) elif mode == 5: logger.info("发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME: {}".format( CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME"])) self.mouse_click( XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME"]) logger.info("欢迎来到火蓝之心副本\n祝你在黑曜石音乐节上玩的愉快\n目前主舞台只支持OF-7,OF-8") try: if c_id[-2] == "F": logger.info( "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F: {}". format(CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F"])) self.mouse_click(XY=CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F"]) logger.info( "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}: {}". format( c_id, CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}". format(c_id)])) self.mouse_click(XY=CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format( c_id)]) elif c_id[-2] == "-": logger.info( "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-: {}". format(CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-"])) self.mouse_click(XY=CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-"]) for x in range(0, 3): logger.info( "发送滑动坐标BATTLE_TO_MAP_RIGHT: {}; FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT" .format(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'])) self.adb.touch_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) logger.info( "发送坐标BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}: {}". format( c_id, CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}". format(c_id)])) self.mouse_click(XY=CLICK_LOCATION[ "BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format( c_id)]) else: logger.error('click_location 文件配置错误') exit(0) except Exception as e: logger.error('click_location 文件配置错误', exc_info=True) exit(0) def clear_daily_task(self): logger.debug("base.clear_daily_task") logger.info("领取每日任务") self.back_to_main() screenshot = self.adb.get_screen_shoot() logger.info('进入任务界面') self.tap_quadrilateral(imgreco.main.get_task_corners(screenshot)) self.__wait(SMALL_WAIT) screenshot = self.adb.get_screen_shoot() hasbeginner = imgreco.task.check_beginners_task(screenshot) if hasbeginner: logger.info('发现见习任务,切换到每日任务') self.tap_rect( imgreco.task.get_daily_task_rect(screenshot, hasbeginner)) self.__wait(TINY_WAIT) while imgreco.task.check_collectable_reward(screenshot): logger.info('完成任务') self.tap_rect( imgreco.task.get_collect_reward_button_rect(self.viewport)) self.__wait(SMALL_WAIT) while True: screenshot = self.adb.get_screen_shoot() if imgreco.common.check_get_item_popup(screenshot): logger.info('领取奖励') self.tap_rect( imgreco.common.get_reward_popup_dismiss_rect( self.viewport)) self.__wait(SMALL_WAIT) else: break screenshot = self.adb.get_screen_shoot() logger.info("奖励已领取完毕")
class ArknightsHelper(object): def __init__(self, current_strength=None, adb_host=None): if adb_host is None: adb_host = ADB_HOST self.adb = ADBShell(adb_host=adb_host) self.shell_color = ShellColor() self.__is_game_active = False self.__check_game_active() self.CURRENT_STRENGTH = 100 self.selector = BattleSelector() self.ocr_active = False self.__is_ocr_active(current_strength) def __is_ocr_active(self, current_strength): os.popen( "tesseract {} {} --psm 7".format( STORAGE_PATH + "OCR_TEST_1.png", SCREEN_SHOOT_SAVE_PATH + "ocr_test_result" ) ) self.__wait(3) try: with open(SCREEN_SHOOT_SAVE_PATH + "ocr_test_result.txt", 'r', encoding="utf8") as f: tmp = f.read() test_1 = int(tmp.split("/")[0]) if test_1 == 51: self.ocr_active = True else: self.shell_color.failure_text("[!] OCR 模块识别错误...装载初始理智值") if current_strength is not None: self.CURRENT_STRENGTH = current_strength else: self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值") exit(0) except Exception as e: self.shell_color.failure_text("[!] OCR 模块未检测...装载初始理智值") if current_strength is not None: self.CURRENT_STRENGTH = current_strength else: self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值") exit(0) def __del(self): self.adb.ch_tools("shell") self.adb.ch_abd_command("am force-stop {}".format(ArkNights_PACKAGE_NAME)) self.adb.run_cmd() def __check_apk_info_active(self): """ IT IS JUST A HELPER FUNCTION :return: """ self.adb.ch_tools("shell") self.adb.ch_abd_command("dumpsys window windows | findstr \"Current\" > {}" .format(STORAGE_PATH + "package.txt")) self.adb.run_cmd(DEBUG_LEVEL=0) def __check_game_active(self): self.__check_apk_info_active() with open(STORAGE_PATH + "current.txt", 'r', encoding='utf8') as f: if ArkNights_PACKAGE_NAME in f.read(): self.__is_game_active = True else: self.adb.ch_tools("shell") self.adb.ch_abd_command("am start -n {}/{}".format(ArkNights_PACKAGE_NAME, ArkNights_ACTIVITY_NAME)) self.adb.run_cmd() self.__is_game_active = True @staticmethod def __wait(n=10, MANLIKE_FLAG=True): ''' n的+-随机值服从均匀分布 :param n: :param MANLIKE_FLAG: :return: ''' if MANLIKE_FLAG: m = uniform(0, 0.3) n = uniform(n - m * 0.5 * n, n + m * n) sleep(n) else: sleep(n) def __simulate_man(self): ''' 模仿人操作,给检测机制提供一些困扰 :return: ''' action = randint(1, 4) if action == 1: pass elif action == 2: pass elif action == 3: pass elif action == 4: pass def module_login(self): self.__wait(SECURITY_WAIT) self.adb.get_mouse_click( XY=CLICK_LOCATION['LOGIN_QUICK_LOGIN'] ) self.__wait(SECURITY_WAIT) self.adb.get_mouse_click( XY=CLICK_LOCATION['LOGIN_START_WAKEUP'] ) self.__wait(SECURITY_WAIT) # self.adb.get_screen_shoot("login.png") def module_battle_slim(self, c_id, set_count=1000, set_ai=True, sub=False, auto_close=True): ''' 简单的战斗模式,请参考 Arknights README.md 中的使用方法调用 该模块 略去了选关部分,直接开始打 :param c_id: 关卡 ID :param set_count: 设置总次数 :param set_ai: 是否设置代理指挥,默认已经设置 :param sub: 是否是子程序。(是否为module_battle所调用的) :param auto_close: 是否自动关闭,默认为 True :return: True 当且仅当所有战斗计数达到设定值的时候 False 当且仅当理智不足的时候 ''' if not sub: self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id)) if not set_ai: self.set_ai_commander(c_id=c_id, first_battle_signal=False) strength_end_signal = False count = 0 while not strength_end_signal: # 初始化 变量 battle_end_signal = False battle_end_signal_max_execute_time = BATTLE_END_SIGNAL_MAX_EXECUTE_TIME # 初始化 返回主页面 # 查看理智剩余部分 strength_end_signal = not self.check_current_strength(c_id) if strength_end_signal: return True # 查看理智剩余部分结束 self.shell_color.info_text("[+] 开始战斗") self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_START_BATTLE'], FLAG=FLAGS_START_BATTLE_BIAS ) self.__wait(4, False) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_ENSURE_TEAM_INFO'], FLAG=FLAGS_ENSURE_TEAM_INFO_BIAS, ) t = 0 while not battle_end_signal: # 先打个60S,不检测 if t == 0: self.__wait(60) t += 60 else: self.__wait(BATTLE_FINISH_DETECT) t += BATTLE_FINISH_DETECT self.shell_color.helper_text("[*] 战斗进行{}S 判断是否结束".format(t)) # 升级的情况 self.adb.get_screen_shoot( file_name="level_up_real_time.png", screen_range=MAP_LOCATION['BATTLE_INFO_LEVEL_UP'] ) num = self.adb.img_difference(img1=SCREEN_SHOOT_SAVE_PATH + "level_up_real_time.png", img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_LEVEL_UP.png") if num > .7: battle_end_signal = True self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) self.adb.shell_color.helper_text("[*] 检测到升级!") self.adb.get_mouse_click( XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(400, 150) ) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) self.adb.get_mouse_click( XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150) ) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) else: self.adb.get_screen_shoot( file_name="battle_end.png", screen_range=MAP_LOCATION['BATTLE_INFO_BATTLE_END'] ) if self.adb.img_difference( img1=SCREEN_SHOOT_SAVE_PATH + "battle_end.png", img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_TRUE.png" ) >= 0.8: battle_end_signal = True self.adb.get_mouse_click( XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150) # 点到了经验尝试降低从(200, 200)降低(200, 150) ) else: battle_end_signal_max_execute_time -= 1 if battle_end_signal_max_execute_time < 1: self.shell_color.failure_text("[!] 超过最大战斗时常,默认战斗结束") battle_end_signal = True count += 1 self.shell_color.info_text("[*] 当前战斗次数 {}".format(count)) if count >= set_count: strength_end_signal = True self.shell_color.info_text("[-] 战斗结束 重新开始") self.__wait(10, MANLIKE_FLAG=True) if not sub: if auto_close: self.shell_color.helper_text("[+] 简略模块结束,系统准备退出".format(c_id)) self.__wait(120, False) self.__del() else: return False else: return False def module_battle(self, c_id, set_count=1000): ''' 保留 first_battle_signal 尽管这样的代码有些冗余但是可能会在之后用到。 :param c_id: :param set_count: :return: ''' self.__wait(3, MANLIKE_FLAG=False) self.selector.id = c_id strength_end_signal = False first_battle_signal = True while not strength_end_signal: # 初始化 返回主页面 if first_battle_signal: for i in range(4): self.adb.get_mouse_click( XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None ) # 进入战斗选择页面 self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_IN'] ) # 选关部分 self.battle_selector(c_id, first_battle_signal) # 选关结束 strength_end_signal = self.module_battle_slim(c_id, set_count=set_count, set_ai=False, sub=True) first_battle_signal = False return True def main_handler(self, battle_task_list=None): if battle_task_list == None: battle_task_list = OrderedDict() self.shell_color.warning_text("[*] 装在模块....") self.shell_color.warning_text("[+] 战斗模块...启动!") flag = False if battle_task_list.__len__() == 0: self.shell_color.failure_text("[!] ⚠ 任务清单为空") for c_id, count in battle_task_list.items(): if c_id not in LIZHI_CONSUME.keys(): raise IndexError("无此关卡") self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id)) self.selector.id = c_id flag = self.module_battle(c_id, count) # flag = self.module_battle_for_test(c_id, count) if flag: self.shell_color.warning_text("[*] 所有模块执行完毕...无限休眠启动!") self.__wait(1024) self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!") self.__del() else: self.shell_color.failure_text("[*] 未知模块异常...无限休眠启动!") self.__wait(1024) self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!") self.__del() def restart(self): ''' 由于重启的逻辑比较困难,暂时废弃这里的功能 :return: ''' self.shell_color.failure_text("[!] 检测异常发生 重新唤醒所有模块") self.__del() self.__init__() self.shell_color.warning_text("[+] 正在唤醒...明日方舟...") self.module_login() self.main_handler() def __module_battle_for_test(self, c_id, set_count=1000): strength_end_signal = False first_battle_signal = True count = 0 while not strength_end_signal: # 初始化 变量 # 战斗状态存活检测 # 初始化 返回主页面 if first_battle_signal: for i in range(4): self.adb.get_mouse_click( XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None ) # 进入战斗选择页面 self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_IN'] ) # 选关部分 self.battle_selector(c_id, first_battle_signal) # 选关结束 count += 1 self.shell_color.info_text("[*] 当前战斗次数 {}".format(count)) if count >= set_count: strength_end_signal = True first_battle_signal = False self.shell_color.info_text("[-] 战斗结束 重新开始") return True def set_ai_commander(self, c_id, first_battle_signal=False): if first_battle_signal: self.adb.get_screen_shoot('{}.png'.format(c_id), MAP_LOCATION['BATTLE_CLICK_AI_COMMANDER']) if self.adb.img_difference( SCREEN_SHOOT_SAVE_PATH + "{}.png".format(c_id), STORAGE_PATH + "BATTLE_CLICK_AI_COMMANDER_TRUE.png" ) <= 0.8: self.shell_color.helper_text("[-] 代理指挥未设置,设置代理指挥") self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_AI_COMMANDER'] ) else: self.shell_color.helper_text("[+] 代理指挥已设置") def check_current_strength(self, c_id): if self.ocr_active: sleep(4) self.adb.get_screen_shoot( file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"] ) os.popen( "tesseract {} {} --psm 7".format( SCREEN_SHOOT_SAVE_PATH + "strength.png", SCREEN_SHOOT_SAVE_PATH + "1" ) ) self.__wait(3) with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") as f: tmp = f.read() # try: self.CURRENT_STRENGTH = int(tmp.split("/")[0]) self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH)) except Exception as e: self.shell_color.failure_text("[!] {}".format(e)) self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id] else: self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id] self.shell_color.warning_text("[*] OCR 模块为装载,系统将直接计算理智值") self.__wait(TINY_WAIT) self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH)) if self.CURRENT_STRENGTH - LIZHI_CONSUME[c_id] < 0: self.shell_color.failure_text("[!] 理智不足 退出战斗") return False else: return True # 理智不够退出战斗 def battle_selector(self, c_id, first_battle_signal=True): mode = self.selector.id_checker() if mode == 1: if first_battle_signal: self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK'] ) # 拖动到正确的地方 if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys() or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys(): if c_id[0].isnumeric(): x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]] else: x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]] self.shell_color.helper_text("[-] 拖动%{}次".format(x)) for x in range(0, x): self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) # 章节选择 if c_id[0].isnumeric(): self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])] ) elif c_id[0] == "S": self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])] ) else: raise IndexError("C_ID Error") self.__wait(3) # 章节选择结束 # 拖动 self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) sleep(SMALL_WAIT) self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) sleep(SMALL_WAIT) self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) # 拖动到正确的地方 if c_id in MAIN_TASK_BATTLE_SWIPE.keys(): x = MAIN_TASK_BATTLE_SWIPE[c_id] self.shell_color.helper_text("[-] 拖动%{}次".format(x)) for x in range(0, x): self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) # self.__wait(MEDIUM_WAIT) sleep(5) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)] ) else: sleep(5) # 好像打过了就不用再点了,直接PASS就行 # self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) # if c_id in MAIN_TASK_RELOCATE.keys(): # self.adb.get_mouse_click(MAIN_TASK_RELOCATE[c_id]) # else: # self.adb.get_mouse_click( # XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)] # ) elif mode == 2: try: X = DAILY_LIST[mode][self.selector.get_week()][c_id[0:2]] except Exception as e: self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误') X = None exit(0) if first_battle_signal: self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION'] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])] ) else: self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])] ) elif mode == 3: try: X = DAILY_LIST[mode][self.selector.get_week()][c_id[3]] except Exception as e: self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误') X = None exit(0) if first_battle_signal: self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH'] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])] ) else: self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])] )
class ArknightsHelper(object): def __init__(self, current_strength=None, adb_host=None, out_put=0, call_by_gui=False): ''' :param current_strength: :param adb_host: :param out_put: 0 default with console 1 no out put ''' if adb_host is None: adb_host = ADB_HOST self.adb = ADBShell(adb_host=adb_host) self.shell_color = ShellColor() if out_put == 0 else BufferColor() self.__is_game_active = False self.__call_by_gui = call_by_gui self.__rebase_to_null = " 1>nul 2>nul" if "win" in os.sys.platform else " 1>/dev/null 2>/dev/null &" \ if enable_rebase_to_null else "" self.CURRENT_STRENGTH = 100 self.selector = BattleSelector() self.ocr_active = True self.is_call_by_gui = call_by_gui # 为了让 GUI 启动快一些,这里关闭了激活ocr的选项以及确认游戏开启的设置 if not call_by_gui: self.is_ocr_active(current_strength) # self.check_game_active() def __ocr_check(self, file_path, save_path, option=None, change_image=True): """ 选择百度ocr识别,还是tesseract识别;以及图片二值化是否开启, :param file_path: ocr识别图片路径 :param save_path: ocr结果保存路径,建议使用txt跟tesseract同一 :param option: 对tesseract的命令传递 :param change_image:是否进行二值化,默认使用二值化 :return: """ global enable_api if change_image: binarization_image(file_path) if enable_api: try: ocr(file_path, save_path + ".txt") except ConnectionError: self.shell_color.failure_text("[!] 百度API无法连接") enable_api = False self.shell_color.helper_text("继续使用tesseract") if option is not None: option = " " + option os.popen( "tesseract {} {}{}".format(file_path, save_path, option) + self.__rebase_to_null ) self.__wait(3) else: if option is not None: option = " " + option os.popen( "tesseract {} {}{}".format(file_path, save_path, option) + self.__rebase_to_null ) self.__wait(3) def is_ocr_active(self, current_strength): """ 启用ocr判断 :param current_strength: 当前理智 :return: """ global enable_api self.__ocr_check(STORAGE_PATH + "OCR_TEST_1.png", SCREEN_SHOOT_SAVE_PATH + "ocr_test_result", "--psm 7", change_image=False) try: with open(SCREEN_SHOOT_SAVE_PATH + "ocr_test_result.txt", 'r', encoding="utf8") as f: tmp = f.read() test_1 = int(tmp.split("/")[0]) if test_1 == 51: self.ocr_active = True else: # 如果启动了api检测失误的话,关闭api if enable_api: enable_api = False self.shell_color.failure_text("[!] OCR 模块识别错误...装载初始理智值") if current_strength is not None: self.CURRENT_STRENGTH = current_strength else: self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值") if not self.is_call_by_gui: exit(0) else: return False except Exception as e: self.shell_color.failure_text("[!] OCR 模块未检测...装载初始理智值") if current_strength is not None: self.CURRENT_STRENGTH = current_strength else: self.shell_color.failure_text("[!] 未装载初始理智值,请在初始化Ark nights助手时候赋予初值") if not self.is_call_by_gui: exit(0) else: return False def __del(self): self.adb.ch_tools("shell") self.adb.ch_abd_command("am force-stop {}".format(ArkNights_PACKAGE_NAME)) self.adb.run_cmd() def destroy(self): self.__del() def __check_apk_info_active(self): """ IT IS JUST A HELPER FUNCTION :return: """ self.adb.ch_tools("shell") self.adb.ch_abd_command("dumpsys window windows | findstr \"Current\" > {}" .format(STORAGE_PATH + "package.txt")) self.adb.run_cmd(DEBUG_LEVEL=0) def check_game_active(self): ''' 该命令是启动 官服的 明日方舟的函数 在之后的GUI里调用。启动脚本的时候不调用了。默认你已经打开了 :return: ''' # self.__check_apk_info_active() with open(STORAGE_PATH + "current.txt", 'r', encoding='utf8') as f: if ArkNights_PACKAGE_NAME in f.read(): self.__is_game_active = True else: self.adb.ch_tools("shell") self.adb.ch_abd_command("am start -n {}/{}".format(ArkNights_PACKAGE_NAME, ArkNights_ACTIVITY_NAME)) self.adb.run_cmd() self.__is_game_active = True @staticmethod def __wait(n=10, MANLIKE_FLAG=True): """ n的+-随机值服从均匀分布 :param n: :param MANLIKE_FLAG: :return: """ if MANLIKE_FLAG: m = uniform(0, 0.3) n = uniform(n - m * 0.5 * n, n + m * n) sleep(n) else: sleep(n) def __simulate_man(self): """ 模仿人操作,给检测机制提供一些困扰 :return: """ action = randint(1, 4) if action == 1: pass elif action == 2: pass elif action == 3: pass elif action == 4: pass def module_login(self): self.__wait(SECURITY_WAIT) self.adb.get_mouse_click( XY=CLICK_LOCATION['LOGIN_QUICK_LOGIN'] ) self.__wait(SECURITY_WAIT) self.adb.get_mouse_click( XY=CLICK_LOCATION['LOGIN_START_WAKEUP'] ) self.__wait(SECURITY_WAIT) def module_battle_slim(self, c_id, set_count=1000, set_ai=False, **kwargs): """ 简单的战斗模式,请参考 Arknights README.md 中的使用方法调用 该模块 略去了选关部分,直接开始打 :param c_id: 关卡 ID :param set_count: 设置总次数 :param set_ai: 是否设置代理指挥,默认没有设置 True 的时候,系统不会判断 AI 是否设置 False 的时候,系统会判断 AI 是否设置,所以省略不写该参数事一个比较保险的选择 扩展参数 :param sub: 是否是子程序。(是否为module_battle所调用的) :param auto_close: 是否自动关闭,默认为 False :param self_fix: 是否自动修复,默认为 False 该参数如果设置为 True 会在安装OCR模块且获取理智失败的情况下进入DEBUG逻辑 目前只支持不小心点到素材页面导致卡死的状况 :param MAX_TIME: 最大迭代次数,默认为config的设置 该次数 * 14 S + 60 得到每次战斗的最长时间 建议自定义这个数值,如果出现一定失误,超出最大判断次数后有一定的自我修复能力 :return: True 当且仅当所有战斗计数达到设定值的时候 False 当且仅当理智不足的时候 """ if "sub" in kwargs.keys(): sub = kwargs['sub'] else: sub = False if "auto_close" in kwargs.keys(): auto_close = kwargs['auto_close'] else: auto_close = True if "self_fix" in kwargs.keys(): self_fix = kwargs['self_fix'] else: self_fix = False if not sub: self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id)) if not set_ai: self.set_ai_commander() strength_end_signal = False count = 0 while not strength_end_signal: # 初始化 变量 battle_end_signal = False if "MAX_TIME" in kwargs.keys(): battle_end_signal_max_execute_time = kwargs["MAX_TIME"] else: battle_end_signal_max_execute_time = BATTLE_END_SIGNAL_MAX_EXECUTE_TIME # 查看理智剩余部分 strength_end_signal = not self.check_current_strength(c_id, self_fix) if strength_end_signal: return True # 查看理智剩余部分结束 self.shell_color.info_text("[+] 开始战斗") self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_START_BATTLE'], FLAG=FLAGS_START_BATTLE_BIAS ) self.__wait(4, False) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_ENSURE_TEAM_INFO'], FLAG=FLAGS_ENSURE_TEAM_INFO_BIAS, ) t = 0 while not battle_end_signal: # 先打个60S,不检测 if t == 0: self.__wait(60) t += 60 else: self.__wait(BATTLE_FINISH_DETECT) t += BATTLE_FINISH_DETECT self.shell_color.helper_text("[*] 战斗进行{}S 判断是否结束".format(t)) # 升级的情况 self.adb.get_screen_shoot( file_name="level_up_real_time.png", screen_range=MAP_LOCATION['BATTLE_INFO_LEVEL_UP'] ) level_up_signal = False level_up_num = 0 # 检测是否启动ocr检查升级情况 if enable_ocr_check_update: self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "level_up_real_time.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7 -l chi_sim") level_up_text = "等级提升" f = open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") tmp = f.readline() if level_up_text in tmp: level_up_signal = True else: level_up_num = self.adb.img_difference(img1=SCREEN_SHOOT_SAVE_PATH + "level_up_real_time.png", img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_LEVEL_UP.png") if level_up_num > .7 or level_up_signal: battle_end_signal = True self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) self.adb.shell_color.helper_text("[*] 检测到升级!") self.adb.get_mouse_click( XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150) ) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) self.adb.get_mouse_click( XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150) ) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) else: # 检测游戏是否结束 self.adb.get_screen_shoot( file_name="battle_end.png", screen_range=MAP_LOCATION['BATTLE_INFO_BATTLE_END'] ) end_num = 0 end_signal = False if enable_ocr_check_end: self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "battle_end.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7 -l chi_sim") end_text = "行动结束" f = open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") tmp = f.readline() if end_text in tmp: end_signal = True else: end_num = self.adb.img_difference( img1=SCREEN_SHOOT_SAVE_PATH + "battle_end.png", img2=STORAGE_PATH + "BATTLE_INFO_BATTLE_END_TRUE.png") if end_num >= 0.8 or end_signal: battle_end_signal = True self.adb.get_mouse_click( XY=CLICK_LOCATION['CENTER_CLICK'], FLAG=(200, 150) # 点到了经验尝试降低从(200, 200)降低(200, 150) ) else: battle_end_signal_max_execute_time -= 1 if battle_end_signal_max_execute_time < 1: self.shell_color.failure_text("[!] 超过最大战斗时常") # 推测BUG发生,启动自检测模块") battle_end_signal = True count += 1 self.shell_color.info_text("[*] 当前战斗次数 {}".format(count)) if count >= set_count: strength_end_signal = True self.shell_color.info_text("[-] 战斗结束 重新开始") self.__wait(10, MANLIKE_FLAG=True) if not sub: if auto_close: self.shell_color.helper_text("[+] 简略模块结束,系统准备退出".format(c_id)) self.__wait(120, False) self.__del() else: self.shell_color.helper_text("[+] 简略模块结束") return True else: self.shell_color.helper_text("[+] 当前任务清单 {} 结束,准备执行下一任务".format(c_id)) return True def __check_is_on_setting(self): """ 检查是否在设置页面 :return: True 如果在设置页面 """ self.adb.get_screen_shoot( 'is_setting.png', MAP_LOCATION['INDEX_INFO_IS_SETTING'] ) if enable_ocr_debugger: self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "is_setting.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7 -l chi_sim") end_text = "保持" f = open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") tmp = f.readline() if end_text in tmp: return True else: return False else: if self.adb.img_difference( img1=STORAGE_PATH + "INDEX_INFO_IS_SETTING.png", img2=SCREEN_SHOOT_SAVE_PATH + "is_setting.png" ) > .85: return True else: return False def module_battle(self, c_id, set_count=1000): """ 保留 first_battle_signal 尽管这样的代码有些冗余但是可能会在之后用到。 :param c_id: :param set_count: :return: """ self.__wait(3, MANLIKE_FLAG=False) self.selector.id = c_id # 初始化 返回主页面 for i in range(3): self.adb.get_mouse_click( XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None ) if self.__check_is_on_setting(): self.shell_color.helper_text("[=] 不小心点到设置了,点击返回") self.adb.get_mouse_click( XY=CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None ) # 进入战斗选择页面 self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_IN'] ) # 选关部分 self.battle_selector(c_id) # 选关结束 self.module_battle_slim(c_id, set_count=set_count, set_ai=False, sub=True, self_fix=self.ocr_active) return True def main_handler(self, battle_task_list=None): if battle_task_list is None: battle_task_list = OrderedDict() self.shell_color.warning_text("[*] 装在模块....") self.shell_color.warning_text("[+] 战斗模块...启动!") flag = False if battle_task_list.__len__() == 0: self.shell_color.failure_text("[!] ⚠ 任务清单为空") for c_id, count in battle_task_list.items(): if c_id not in LIZHI_CONSUME.keys(): raise IndexError("无此关卡") self.shell_color.helper_text("[+] 战斗-选择{}...启动!".format(c_id)) self.selector.id = c_id flag = self.module_battle(c_id, count) # flag = self.module_battle_for_test(c_id, count) if flag: self.shell_color.warning_text("[*] 所有模块执行完毕...无限休眠启动!") if not self.__call_by_gui: self.__wait(1024) self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!") self.__del() else: self.shell_color.failure_text("[*] 未知模块异常...无限休眠启动!") self.__wait(1024) self.shell_color.failure_text("[*] 休眠过度...启动自毁程序!") self.__del() def restart(self): """ 由于重启的逻辑比较困难,暂时废弃这里的功能 :return: """ self.shell_color.failure_text("[!] 检测异常发生 重新唤醒所有模块") self.__del() self.__init__() self.shell_color.warning_text("[+] 正在唤醒...明日方舟...") self.module_login() self.main_handler() def set_ai_commander(self): self.adb.get_screen_shoot('is_ai.png', MAP_LOCATION['BATTLE_CLICK_AI_COMMANDER']) if self.adb.img_difference( SCREEN_SHOOT_SAVE_PATH + "is_ai.png", STORAGE_PATH + "BATTLE_CLICK_AI_COMMANDER_TRUE.png" ) <= 0.8: self.shell_color.helper_text("[-] 代理指挥未设置,设置代理指挥") self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_CLICK_AI_COMMANDER'] ) else: self.shell_color.helper_text("[+] 代理指挥已设置") def __check_current_strength(self): """ 简易的模式,在debug后重新启动 :return: """ assert self.ocr_active sleep(4) self.adb.get_screen_shoot( file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"] ) self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "strength.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7") with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") as f: tmp = f.read() # try: self.CURRENT_STRENGTH = int(tmp.split("/")[0]) self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH)) return True except Exception as e: self.shell_color.failure_text("[!] {}".format(e)) return False def __check_current_strength_debug(self): # 查看是否在素材页面 self.shell_color.helper_text("[+] 启动自修复模块,检查是否停留在素材页面") self.adb.get_screen_shoot( file_name="debug.png", screen_range=MAP_LOCATION['BATTLE_DEBUG_WHEN_OCR_ERROR'] ) if enable_ocr_debugger: self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "debug.png", SCREEN_SHOOT_SAVE_PATH + "debug", "--psm 7 -l chi_sim") end_text = "首次掉落" f = open(SCREEN_SHOOT_SAVE_PATH + "debug.txt", 'r', encoding="utf8") tmp = f.readline() if end_text in tmp: self.shell_color.helper_text("[$] 检测 BUG 成功,系统停留在素材页面,请求返回...") self.adb.get_mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None) self.__check_current_strength() else: self.shell_color.failure_text("[-] 检测 BUG 失败,系统将继续执行任务") else: if self.adb.img_difference( img1=SCREEN_SHOOT_SAVE_PATH + "debug.png", img2=STORAGE_PATH + "BATTLE_DEBUG_CHECK_LOCATION_IN_SUCAI.png" ) > 0.75: self.shell_color.helper_text("[$] 检测 BUG 成功,系统停留在素材页面,请求返回...") self.adb.get_mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None) self.__check_current_strength() else: self.shell_color.failure_text("[-] 检测 BUG 失败,系统将继续执行任务") def check_current_strength(self, c_id, self_fix=False): if self.ocr_active: sleep(4) self.adb.get_screen_shoot( file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"] ) self.__ocr_check(SCREEN_SHOOT_SAVE_PATH + "strength.png", SCREEN_SHOOT_SAVE_PATH + "1", "--psm 7") with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r', encoding="utf8") as f: tmp = f.read() # try: self.CURRENT_STRENGTH = int(tmp.split("/")[0]) self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH)) except Exception as e: self.shell_color.failure_text("[!] {}".format(e)) if self_fix: self.__check_current_strength_debug() else: self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id] else: self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id] self.shell_color.warning_text("[*] OCR 模块为装载,系统将直接计算理智值") self.__wait(TINY_WAIT) self.shell_color.helper_text("[+] 理智剩余 {}".format(self.CURRENT_STRENGTH)) if self.CURRENT_STRENGTH - LIZHI_CONSUME[c_id] < 0: self.shell_color.failure_text("[!] 理智不足 退出战斗") return False else: return True # 理智不够退出战斗 def battle_selector(self, c_id, first_battle_signal=True): mode = self.selector.id_checker() if mode == 1: if first_battle_signal: self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK'] ) # 拖动到正确的地方 if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys() or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys(): if c_id[0].isnumeric(): x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]] else: x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]] self.shell_color.helper_text("[-] 拖动%{}次".format(x)) for x in range(0, x): self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) # 章节选择 if c_id[0].isnumeric(): self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])] ) elif c_id[0] == "S": self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])] ) else: raise IndexError("C_ID Error") self.__wait(3) # 章节选择结束 # 拖动 self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) sleep(SMALL_WAIT) self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) sleep(SMALL_WAIT) self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) # 拖动到正确的地方 if c_id in MAIN_TASK_BATTLE_SWIPE.keys(): x = MAIN_TASK_BATTLE_SWIPE[c_id] self.shell_color.helper_text("[-] 拖动%{}次".format(x)) for x in range(0, x): self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) # self.__wait(MEDIUM_WAIT) sleep(5) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)] ) else: sleep(5) elif mode == 2: try: X = DAILY_LIST[mode][self.selector.get_week()][c_id[0:2]] except Exception as e: self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误') X = None exit(0) if first_battle_signal: self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION'] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])] ) else: self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])] ) elif mode == 3: try: X = DAILY_LIST[mode][self.selector.get_week()][c_id[3]] except Exception as e: self.shell_color.failure_text(e.__str__() + '\tclick_location 文件配置错误') X = None exit(0) if first_battle_signal: self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH'] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)] ) self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])] ) else: self.adb.get_mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])] )
class ArknightsHelper(object): def __init__(self, current_strength=None, # 当前理智 adb_host=None, # 当前绑定到的设备 out_put=True, # 是否有命令行输出 call_by_gui=False): # 是否为从 GUI 程序调用 if adb_host is None: adb_host = ADB_HOST self.adb = ADBShell(adb_host=adb_host) self.shell_log = ShellColor() if out_put else BufferColor(debug_level=DEBUG_LEVEL) self.__is_game_active = False self.__call_by_gui = call_by_gui self.__rebase_to_null = " 1>nul 2>nul" \ if "win32" in os.sys.platform \ else " 1>/dev/null 2>/dev/null &" \ if enable_rebase_to_null else "" self.CURRENT_STRENGTH = 100 self.selector = BattleSelector() self.ocr_active = True self.is_called_by_gui = call_by_gui if DEBUG_LEVEL >= 1: self.__print_info() if not call_by_gui: self.is_ocr_active(current_strength) self.shell_log.debug_text("成功初始化模块") def __print_info(self): self.shell_log.info_text( """当前系统信息: ADB 路径\t{adb_path} ADB 端口\t{adb_host} 截图路径\t{screen_shoot_path} 存储路径\t{storage_path} """.format( adb_path=ADB_ROOT, adb_host=ADB_HOST, screen_shoot_path=SCREEN_SHOOT_SAVE_PATH, storage_path=STORAGE_PATH ) ) if enable_baidu_api: self.shell_log.info_text( """百度API配置信息: APP_ID\t{app_id} API_KEY\t{api_key} SECRET_KEY\t{secret_key} """.format( app_id=APP_ID, api_key=API_KEY, secret_key=SECRET_KEY ) ) def __ocr_check(self, file_path, # 输入文件路径 save_path, # 输出文件路径 option=None, # 附加选项 change_image=True): # 是否预处理图片 self.shell_log.debug_text("base.__ocr_check") global enable_baidu_api if change_image: if enable_baidu_api: if enable_help_baidu: binarization_image(filepath=file_path, save_backup=True) else: self.shell_log.info_text("不对百度ocr进行图像处理") else: binarization_image(filepath=file_path, save_backup=True) if enable_baidu_api: try: ocr(file_path, save_path + ".txt") except ConnectionError: self.shell_log.failure_text("[!] 百度API无法连接") enable_baidu_api = False self.shell_log.helper_text("继续使用tesseract") if not enable_baidu_api: self.shell_log.debug_text("使用 tesseract OCR") if option is not None: option = " " + option os.popen( 'tesseract "{}" "{}" {}'.format(file_path, save_path, option) + self.__rebase_to_null ) self.__wait(3) else: self.shell_log.debug_text("使用 baidu api") def is_ocr_active(self, # 判断 OCR 是否可用 current_strength=None): # 如果不可用时用于初始化的理智值 self.shell_log.debug_text("base.is_ocr_active") global enable_baidu_api self.__ocr_check(os.path.join(STORAGE_PATH, "OCR_TEST_1.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "ocr_test_result"), "--psm 7", change_image=False) try: with open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "ocr_test_result.txt"), "r") as f: tmp = f.read() test_1 = int(tmp.split("/")[0]) if test_1 == 51: self.ocr_active = True self.shell_log.debug_text("OCR 模块工作正常") return True else: raise Exception except Exception as e: if enable_baidu_api: enable_baidu_api = False return self.is_ocr_active(current_strength) self.shell_log.failure_text("OCR 模块识别错误, 使用初始理智值") if current_strength is not None: self.CURRENT_STRENGTH = current_strength else: self.shell_log.failure_text( "未装载初始理智值, 请在初始化 Arknights 助手时赋予初值") if not self.is_called_by_gui: exit(0) else: return False def __del(self): self.shell_log.debug_text("base.__del") self.adb.ch_tools("shell") self.adb.ch_abd_command( "am force-stop {}".format(ArkNights_PACKAGE_NAME)) self.adb.run_cmd() def destroy(self): self.__del() def __check_apk_info_active(self): self.adb.ch_tools("shell") self.adb.ch_abd_command("dumpsys window windows | findstr \"Current\" > {}".format( os.path.join(STORAGE_PATH, "package.txt"))) self.adb.run_cmd(DEBUG_LEVEL=0) def check_game_active(self): # 启动游戏 需要手动调用 self.shell_log.debug_text("base.check_game_active") self.__check_apk_info_active() self.shell_log.debug_text("正在尝试启动游戏") with open(os.path.join(STORAGE_PATH, "current.txt"), "r") as f: if ArkNights_PACKAGE_NAME in f.read(): self.__is_game_active = True self.shell_log.debug_text("游戏已启动") else: self.adb.ch_tools("shell") self.adb.ch_abd_command( "am start -n {}/{}".format(ArkNights_PACKAGE_NAME, ArkNights_ACTIVITY_NAME)) self.adb.run_cmd() self.shell_log.debug_text("成功启动游戏") self.__is_game_active = True @staticmethod def __wait(n=10, # 等待时间中值 MANLIKE_FLAG=True): # 是否在此基础上设偏移量 if MANLIKE_FLAG: m = uniform(0, 0.3) n = uniform(n - m * 0.5 * n, n + m * n) sleep(n) def mouse_click(self, # 点击一个按钮 XY): # 待点击的按钮的左上和右下坐标 self.shell_log.debug_text("base.mouse_click") xx = randint(XY[0][0], XY[1][0]) yy = randint(XY[0][1], XY[1][1]) self.adb.get_mouse_click((xx, yy)) self.__wait(TINY_WAIT, MANLIKE_FLAG=True) def module_login(self): self.shell_log.debug_text("base.module_login") self.mouse_click(CLICK_LOCATION['LOGIN_QUICK_LOGIN']) self.__wait(BIG_WAIT) self.mouse_click(CLICK_LOCATION['LOGIN_START_WAKEUP']) self.__wait(BIG_WAIT) def module_battle_slim(self, c_id, # 待战斗的关卡编号 set_count=1000, # 战斗次数 check_ai=True, # 是否检查代理指挥 **kwargs): # 扩展参数: ''' :param sub 是否为子程序 (是否为module_battle所调用) :param auto_close 是否自动关闭, 默认为 false :param self_fix 是否尝试自动修复, 默认为 false :param MAX_TIME 最大检查轮数, 默认在 config 中设置, 每隔一段时间进行一轮检查判断战斗是否结束 建议自定义该数值以便在出现一定失误, 超出最大判断次数后有一定的自我修复能力 :return: True 完成指定次数的战斗 False 理智不足, 退出战斗 ''' self.shell_log.debug_text("base.module_battle_slim") sub = kwargs["sub"] \ if "sub" in kwargs.keys() else False auto_close = kwargs["auto_close"] \ if "auto_close" in kwargs.keys() else False self_fix = kwargs["self_fix"] \ if "self_fix" in kwargs.keys() else False if not sub: self.shell_log.helper_text("战斗-选择{}...启动".format(c_id)) if check_ai: self.set_ai_commander() if set_count == 0: return True strength_end_signal = False count = 0 while not strength_end_signal: # 初始化变量 battle_end_signal = False if "MAX_TIME" in kwargs.keys(): battle_end_signal_max_execute_time = kwargs["MAX_TIME"] else: battle_end_signal_max_execute_time = BATTLE_END_SIGNAL_MAX_EXECUTE_TIME # 查看剩余理智 strength_end_signal = not self.check_current_strength( c_id, self_fix) # 需要重新启动 if self.CURRENT_STRENGTH == -1: self.back_to_main() self.__wait(3, MANLIKE_FLAG=False) self.selector.id = c_id self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_IN']) self.battle_selector(c_id) # 选关 return self.module_battle_slim(c_id, set_count - count, check_ai, **kwargs) if strength_end_signal: return True self.shell_log.helper_text("开始战斗") self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_START_BATTLE']) self.__wait(4, False) self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_ENSURE_TEAM_INFO']) t = 0 while not battle_end_signal: # 前 60s 不进行检测 if t == 0: self.__wait(BATTLE_NONE_DETECT_TIME) t += BATTLE_NONE_DETECT_TIME else: self.__wait(BATTLE_FINISH_DETECT) t += BATTLE_FINISH_DETECT self.shell_log.helper_text("战斗进行{}s 判断是否结束".format(t)) # 判断是否升级 self.adb.get_screen_shoot(file_name="battle_status.png") self.adb.get_sub_screen( file_name="battle_status.png", screen_range=MAP_LOCATION['BATTLE_INFO_LEVEL_UP'], save_name="level_up_real_time.png" ) level_up_signal = False # 检查升级情况 if enable_ocr_check_update: self.__ocr_check( os.path.join(SCREEN_SHOOT_SAVE_PATH, "level_up_real_time.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7 -l chi_sim" ) level_up_text = "提升" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r") tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) level_up_signal = level_up_text in tmp else: level_up_signal = self.adb.img_difference( img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "level_up_real_time.png"), img2=os.path.join(STORAGE_PATH, "BATTLE_INFO_BATTLE_END_LEVEL_UP.png") ) > .7 if level_up_signal: battle_end_signal = True self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) self.shell_log.helper_text("检测到升级") self.mouse_click(CLICK_LOCATION['CENTER_CLICK']) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) self.mouse_click(CLICK_LOCATION['CENTER_CLICK']) self.__wait(SMALL_WAIT, MANLIKE_FLAG=True) else: self.adb.get_sub_screen( file_name="battle_status.png", screen_range=MAP_LOCATION['BATTLE_INFO_BATTLE_END'], save_name="battle_end.png" ) end_signal = False if enable_ocr_check_end: self.__ocr_check( os.path.join(SCREEN_SHOOT_SAVE_PATH, "battle_end.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7 -l chi_sim" ) end_text = "结束" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r") tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) end_signal = end_text in tmp else: end_signal = self.adb.img_difference( img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "battle_end.png"), img2=os.path.join(STORAGE_PATH, "BATTLE_INFO_BATTLE_END_TRUE.png") ) > .7 if end_signal: battle_end_signal = True self.mouse_click(CLICK_LOCATION['CENTER_CLICK']) else: battle_end_signal_max_execute_time -= 1 if battle_end_signal_max_execute_time < 1: self.shell_log.failure_text("超过最大战斗时长!") battle_end_signal = True count += 1 self.shell_log.info_text("当前战斗次数 {}".format(count)) if count >= set_count: strength_end_signal = True self.shell_log.info_text("战斗结束") self.__wait(10, MANLIKE_FLAG=True) if not sub: if auto_close: self.shell_log.helper_text("简略模块{}结束,系统准备退出".format(c_id)) self.__wait(120, False) self.__del() else: self.shell_log.helper_text("简略模块{}结束".format(c_id)) return True else: self.shell_log.helper_text("当前任务{}结束,准备进行下一项任务".format(c_id)) return True def __check_is_on_setting(self): # 检查是否在设置页面,True 为是 self.shell_log.debug_text("base.__check_is_on_setting") self.adb.get_screen_shoot( file_name="is_setting.png", screen_range=MAP_LOCATION['INDEX_INFO_IS_SETTING'] ) if enable_ocr_debugger: self.__ocr_check( os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_setting.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7 -l chi_sim", change_image=False ) end_text = "设置" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r") tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) return end_text in tmp else: return self.adb.img_difference( img1=os.path.join(STORAGE_PATH, "INDEX_INFO_IS_SETTING.png"), img2=os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_setting.png") ) > .85 def __check_is_on_notice(self): # 检查是否有公告,True为是 self.shell_log.debug_text("base.__check_is_on_notice") self.adb.get_screen_shoot( file_name="is_notice.png", screen_range=MAP_LOCATION['INDEX_INFO_IS_NOTICE'] ) if enable_ocr_debugger: self.__ocr_check( os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_notice.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7 -l chi_sim", change_image=False ) end_text = "活动公告" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r") tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) return end_text in tmp else: return self.adb.img_difference( img1=os.path.join(STORAGE_PATH, "INDEX_INFO_IS_NOTICE.png"), img2=os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_notice.png") ) > .85 def back_to_main(self): # 回到主页 self.shell_log.debug_text("base.back_to_main") self.shell_log.helper_text("返回主页ing...") # 检测是否有公告,如果有就点掉,点掉公告就是在主页 if self.__check_is_on_notice(): self.shell_log.helper_text("触发公告,点掉公告") self.mouse_click(CLICK_LOCATION['CLOSE_NOTICE']) self.shell_log.helper_text("已回到主页") self.__wait(SMALL_WAIT, True) return # 检测左上角是否有返回标志,有就返回,没有就结束 for i in range(5): self.adb.get_screen_shoot( file_name="is_return.png", screen_range=MAP_LOCATION['INDEX_INFO_IS_RETURN'] ) if self.adb.img_difference( img1=os.path.join(STORAGE_PATH, "INDEX_INFO_IS_RETURN.png"), img2=os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_return.png") ) > .75: self.shell_log.helper_text("未回到主页,点击返回") self.mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX']) self.__wait(TINY_WAIT, True) if self.__check_is_on_notice(): self.shell_log.helper_text("触发公告,点掉公告") self.mouse_click(CLICK_LOCATION['CLOSE_NOTICE']) break else: break if self.__check_is_on_setting(): self.shell_log.helper_text("触发设置,返回") self.mouse_click(CLICK_LOCATION['MAIN_RETURN_INDEX']) self.shell_log.helper_text("已回到主页") self.__wait(SMALL_WAIT, True) def module_battle(self, # 完整的战斗模块 c_id, # 选择的关卡 set_count=1000): # 作战次数 self.shell_log.debug_text("base.module_battle") self.back_to_main() self.__wait(3, MANLIKE_FLAG=False) self.selector.id = c_id self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_IN']) self.battle_selector(c_id) # 选关 self.module_battle_slim(c_id, set_count=set_count, check_ai=True, sub=True, self_fix=self.ocr_active) return True def main_handler(self, battle_task_list=None): self.shell_log.debug_text("base.main_handler") if battle_task_list is None: battle_task_list = OrderedDict() self.shell_log.warning_text("装载模块...") self.shell_log.warning_text("战斗模块...启动") flag = False if battle_task_list.__len__() == 0: self.shell_log.failure_text("任务清单为空!") for c_id, count in battle_task_list.items(): if c_id not in MAIN_TASK_SUPPORT.keys(): raise IndexError("无此关卡!") self.shell_log.helper_text("战斗{} 启动".format(c_id)) self.selector.id = c_id flag = self.module_battle(c_id, count) if flag: if not self.__call_by_gui: self.shell_log.warning_text("所有模块执行完毕... 60s后退出") self.__wait(60) self.__del() else: self.shell_log.warning_text("所有模块执行完毕") else: if not self.__call_by_gui: self.shell_log.warning_text("发生未知错误... 60s后退出") self.__wait(60) self.__del() else: self.shell_log.warning_text("发生未知错误... 进程已结束") def set_ai_commander(self): self.shell_log.debug_text("base.set_ai_commander") self.adb.get_screen_shoot( file_name="is_ai.png", screen_range=MAP_LOCATION['BATTLE_CLICK_AI_COMMANDER'] ) if self.adb.img_difference( os.path.join(SCREEN_SHOOT_SAVE_PATH, "is_ai.png"), os.path.join(STORAGE_PATH, "BATTLE_CLICK_AI_COMMANDER_TRUE.png") ) <= 0.8: self.shell_log.helper_text("代理指挥未设置,设置代理指挥") self.mouse_click(CLICK_LOCATION['BATTLE_CLICK_AI_COMMANDER']) else: self.shell_log.helper_text("代理指挥已设置") def __check_current_strength(self): # 检查当前理智是否足够 self.shell_log.debug_text("base.__check_current_strength") assert self.ocr_active self.__wait(SMALL_WAIT, False) self.adb.get_screen_shoot( file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"] ) self.__ocr_check( os.path.join(SCREEN_SHOOT_SAVE_PATH, "strength.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7") with open(SCREEN_SHOOT_SAVE_PATH + "1.txt", 'r') as f: tmp = f.read() # try: self.CURRENT_STRENGTH = int(tmp.split("/")[0]) self.shell_log.helper_text( "理智剩余 {}".format(self.CURRENT_STRENGTH)) return True except Exception as e: self.shell_log.failure_text("{}".format(e)) return False def __check_current_strength_debug(self, c_id): # 查看是否在素材页面 self.shell_log.debug_text("base.__check_current_strength_debug") self.shell_log.helper_text("启动自修复模块,检查是否停留在素材页面") self.adb.get_screen_shoot( file_name="debug.png", screen_range=MAP_LOCATION['BATTLE_DEBUG_WHEN_OCR_ERROR'] ) if enable_ocr_debugger: self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug"), "--psm 7 -l chi_sim") end_text = "掉落" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug.txt"), 'r') tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) if end_text in tmp: self.shell_log.helper_text("检测 BUG 成功,系统停留在素材页面,请求返回...") self.adb.get_mouse_click( CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None) self.__check_current_strength() else: self.shell_log.failure_text("检测 BUG 失败,系统将返回主页重新开始") self.CURRENT_STRENGTH = -1 # CURRENT_STRENGTH = -1 代表需要需要回到主页重来 else: if self.adb.img_difference( img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "debug.png"), img2=os.path.join(STORAGE_PATH, "BATTLE_DEBUG_CHECK_LOCATION_IN_SUCAI.png") ) > 0.75: self.shell_log.helper_text("检测 BUG 成功,系统停留在素材页面,请求返回...") self.adb.get_mouse_click( CLICK_LOCATION['MAIN_RETURN_INDEX'], FLAG=None) self.__check_current_strength() else: self.shell_log.failure_text("检测 BUG 失败,系统将返回主页重新开始") self.CURRENT_STRENGTH = -1 # CURRENT_STRENGTH = -1 代表需要需要回到主页重来 def check_current_strength(self, c_id, self_fix=False): self.shell_log.debug_text("base.check_current_strength") if self.ocr_active: self.__wait(SMALL_WAIT, False) self.adb.get_screen_shoot( file_name="strength.png", screen_range=MAP_LOCATION["BATTLE_INFO_STRENGTH_REMAIN"] ) self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "strength.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7") with open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), 'r') as f: tmp = f.read() # try: self.CURRENT_STRENGTH = int(tmp.split("/")[0]) self.shell_log.helper_text( "理智剩余 {}".format(self.CURRENT_STRENGTH)) except Exception as e: self.shell_log.failure_text("{}".format(e)) if self_fix: self.__check_current_strength_debug(c_id) if self.CURRENT_STRENGTH == -1: return False else: self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id] else: self.CURRENT_STRENGTH -= LIZHI_CONSUME[c_id] self.shell_log.warning_text("OCR 模块未装载,系统将直接计算理智值") self.__wait(TINY_WAIT) self.shell_log.helper_text( "理智剩余 {}".format(self.CURRENT_STRENGTH)) if self.CURRENT_STRENGTH - LIZHI_CONSUME[c_id] < 0: self.shell_log.failure_text("理智不足 退出战斗") return False else: return True def battle_selector(self, c_id, first_battle_signal=True): # 选关 self.shell_log.debug_text("base.battle_selector") mode = self.selector.id_checker(c_id) # 获取当前关卡所属章节 if mode == 1: if first_battle_signal: self.mouse_click(XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK']) self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT ) # 拖动到正确的地方 if c_id[0] in MAIN_TASK_CHAPTER_SWIPE.keys() or c_id[1] in MAIN_TASK_CHAPTER_SWIPE.keys(): if c_id[0].isnumeric(): x = MAIN_TASK_CHAPTER_SWIPE[c_id[0]] else: x = MAIN_TASK_CHAPTER_SWIPE[c_id[1]] self.shell_log.helper_text("拖动 {} 次".format(x)) for x in range(0, x): self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) # 章节选择 if c_id[0].isnumeric(): self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[0])]) elif c_id[0] == "S": self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id[1])]) else: raise IndexError("C_ID Error") self.__wait(3) # 章节选择结束 # 拖动 self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) sleep(SMALL_WAIT) self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) sleep(SMALL_WAIT) self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) # 拖动到正确的地方 if c_id in MAIN_TASK_BATTLE_SWIPE.keys(): x = MAIN_TASK_BATTLE_SWIPE[c_id] self.shell_log.helper_text("拖动 {} 次".format(x)) for x in range(0, x): self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) sleep(5) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MAIN_TASK_{}'.format(c_id)]) else: sleep(5) elif mode == 2: try: X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[0:2]] except Exception as e: self.shell_log.failure_text( e.__str__() + '\tclick_location 文件配置错误') X = None exit(0) if first_battle_signal: self.adb.get_mouse_swipe( SWIPE_LOCATION['BATTLE_TO_MAP_LEFT'], FLAG=FLAGS_SWIPE_BIAS_TO_LEFT) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION']) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_{}'.format(X)]) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]) else: self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_MATERIAL_COLLECTION_X-{}'.format(c_id[-1])]) elif mode == 3: try: X = DAILY_LIST[str(mode)][self.selector.get_week()][c_id[3]] except Exception as e: self.shell_log.failure_text( e.__str__() + '\tclick_location 文件配置错误') X = None exit(0) if first_battle_signal: self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH']) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-{}'.format(X)]) self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]) else: self.mouse_click( XY=CLICK_LOCATION['BATTLE_SELECT_CHIP_SEARCH_PR-X-{}'.format(c_id[-1])]) elif mode == 5: self.mouse_click( XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME"]) self.shell_log.helper_text( "欢迎来到火蓝之心副本\n祝你在黑曜石音乐节上玩的愉快\n目前主舞台只支持OF-7,OF-8") try: if c_id[-2] == "F": self.mouse_click( XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-F"]) self.mouse_click( XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format(c_id)]) elif c_id[-2] == "-": self.mouse_click( XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_OF-"]) for x in range(0, 3): self.adb.get_mouse_swipe(SWIPE_LOCATION['BATTLE_TO_MAP_RIGHT'], FLAG=FLAGS_SWIPE_BIAS_TO_RIGHT) self.__wait(MEDIUM_WAIT) self.mouse_click( XY=CLICK_LOCATION["BATTLE_SELECT_HEART_OF_SURGING_FLAME_{}".format(c_id)]) else: self.shell_log.failure_text('click_location 文件配置错误') exit(0) except Exception as e: self.shell_log.failure_text( e.__str__() + 'click_location 文件配置错误') exit(0) def clear_daily_task(self): self.shell_log.debug_text("base.clear_daily_task") self.back_to_main() self.mouse_click(CLICK_LOCATION['TASK_CLICK_IN']) self.__wait(TINY_WAIT, True) self.mouse_click(CLICK_LOCATION['TASK_DAILY_TASK']) self.__wait(TINY_WAIT, True) task_ok_signal = True while task_ok_signal: self.adb.get_screen_shoot(file_name="task_status.png") self.shell_log.helper_text("正在检查任务状况") self.adb.get_sub_screen( file_name="task_status.png", screen_range=MAP_LOCATION['TASK_INFO'], save_name="task_status_1.png" ) if enable_ocr_check_task: self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_1.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7 -l chi_sim") task_ok_text = "领取" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r") tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) task_ok_signal = task_ok_text in tmp else: task_ok_signal = self.adb.img_difference( img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_1.png"), img2=os.path.join(STORAGE_PATH, "TASK_COMPLETE.png") ) > .7 if not task_ok_signal: # 检查当前是否在获得物资页面 self.shell_log.debug_text("未检测到可领取奖励,检查是否在获得物资页面") self.adb.get_sub_screen( file_name="task_status.png", screen_range=MAP_LOCATION['REWARD_GET'], save_name="task_status_2.png" ) if enable_ocr_check_task: self.__ocr_check(os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_2.png"), os.path.join(SCREEN_SHOOT_SAVE_PATH, "1"), "--psm 7 -l chi_sim") reward_text = "物资" f = open(os.path.join(SCREEN_SHOOT_SAVE_PATH, "1.txt"), "r") tmp = f.readline() tmp = tmp.replace(' ', '') self.shell_log.debug_text("OCR 识别结果: {}".format(tmp)) task_ok_signal = reward_text in tmp else: task_ok_signal = self.adb.img_difference( img1=os.path.join(SCREEN_SHOOT_SAVE_PATH, "task_status_2.png"), img2=os.path.join(STORAGE_PATH, "REWARD_GET.png") ) > .7 if task_ok_signal: self.shell_log.debug_text("当前有可领取奖励") self.mouse_click(CLICK_LOCATION['TASK_DAILY_TASK_CHECK']) self.__wait(2, False) self.shell_log.helper_text("奖励已领取完毕")