def init_fastscreen(self): if fast_screencut and Multithreading({}).program_is_stopped(): from core.get_screen import ReceiveFromMinicap self.receive_minicap = ReceiveFromMinicap(self.address) self.receive_minicap.start() print("Device:", self._d.serial, "快速截图已打开,测试中……") for retry in range(3): try: data = self.receive_minicap.receive_img() if data is None: raise Exception("读取数据超过最大尝试次数") self.fastscreencut_retry = 0 print("Device:", self._d.serial, "快速截图运行正常。") break except Exception as e: self.receive_minicap.stop() time.sleep(1) if retry < 2: print("Device:", self._d.serial, f"尝试重新开启快速截图...{e}") self.receive_minicap = ReceiveFromMinicap(self.address) self.receive_minicap.start() else: self.fastscreencut_retry = 3 if force_fast_screencut: raise FastScreencutException("快速截图打开失败!") else: print("Device:", self._d.serial, f"快速截图打开失败!使用慢速截图。")
class BaseMixin: """ 基础插片:包含设备信息(u2),账户信息(account) 辅助功能:日志,静态存储 基本操作 (click,find_img,guochang,click_img,lock_img,lock_no_img,chulijiaocheng) 需要在Automator中手动初始化,传入address和account参数。 """ def __init__(self): self.appRunning = False self.account = "debug" self._d: Optional[u2.Device] = None self.d: Optional[SafeU2Handle] = None self.dWidth = 960 self.dHeight = 540 self.log: Optional[log_handler.pcr_log] = None self.AR: Optional[AutomatorRecorder] = None self.ms: Optional[moveset] = None self.debug_screen = None # 如果debug_screen为None,则正常截图;否则,getscreen函数使用debug_screen作为读取的screen self.last_screen = None # 每次调用getscreen会把图片暂存至last_screen self.fastscreencut_retry = 0 # 快速截图失败次数 self.address = None self.today_date = datetime.date.today() self.cpu_occupy = 0 self.change_time = 0.5 self.last_screen_time = 0 self.async_juqingtiaoguo_switch = False self.last_star = 0 # 上次战斗的星数 self._move_method = "" # 接收其它线程发送的处理方法 self._move_msg = "" # 接收其它线程发送的信息 # fastscreencap if fast_screencut: self.lport: Optional[int] = None self.receive_minicap: Optional[ReceiveFromMinicap] = None def save_last_screen(self, filename): if self.last_screen is not None: try: cv2.imwrite(filename, self.last_screen) except Exception as e: self.log.write_log("error", f"保存最后一次截图失败:{e}") def do_nothing(self): # 啥事不干 self.log.write_log("info", "Do nothing.") pass def init_fastscreen(self): if fast_screencut and Multithreading({}).program_is_stopped(): from core.get_screen import ReceiveFromMinicap self.receive_minicap = ReceiveFromMinicap(self.address) self.receive_minicap.start() print("Device:", self._d.serial, "快速截图已打开,测试中……") for retry in range(3): try: data = self.receive_minicap.receive_img() if data is None: raise Exception("读取数据超过最大尝试次数") self.fastscreencut_retry = 0 print("Device:", self._d.serial, "快速截图运行正常。") break except Exception as e: self.receive_minicap.stop() time.sleep(1) if retry < 2: print("Device:", self._d.serial, f"尝试重新开启快速截图...{e}") self.receive_minicap = ReceiveFromMinicap(self.address) self.receive_minicap.start() else: self.fastscreencut_retry = 3 if force_fast_screencut: raise FastScreencutException("快速截图打开失败!") else: print("Device:", self._d.serial, f"快速截图打开失败!使用慢速截图。") def init_device(self, address): """ device: 如果是 USB 连接,则为 adb devices 的返回结果;如果是模拟器,则为模拟器的控制 URL 。 """ self.appRunning = False self.address = address if address != "debug": self._d = safe_u2_connect(address) self.d = SafeU2Handle(self._d) self.init_fastscreen() def init_account(self, account, rec_addr="users"): self.account = account self.log = log_handler.pcr_log(account) # 初始化日志 self.AR = AutomatorRecorder(account, rec_addr) def init(self, address, account, rec_addr="users"): # 兼容 self.init_device(address) self.init_account(account, rec_addr) def force_kill(self): """ 强制结束Automator :return: """ self.send_move_method("forcekill", "") @staticmethod def _get_at(at): # at参数的转换 if isinstance(at, PCRelement): return at.at else: return at def send_move_method(self, method, msg): """ 给主线程发送一条消息 :param method: 处理方法 restart: 重启 :param msg: 附带信息 restart: 重启时显示的错误提示 """ while self._move_method != "": pass self._move_msg = msg self._move_method = method while self._move_method != "": pass def _move_check(self): """ 作为最小执行单元,接收暂停、退出等信息 :return: False:无影响 True:造成影响 """ try: from automator_mixins._async import block_sw if block_sw == 1: print("脚本暂停中~") while block_sw == 1: from automator_mixins._async import block_sw time.sleep(1) return True except Exception as error: print('暂停-错误:', error) return True if self._move_method == "restart": self._move_method = "" raise Exception(self._move_msg) if self._move_method == "forcekill": self._move_method = "" raise ForceKillException() def click_img(self, screen, img, threshold=0.84, at=None, pre_delay=0., post_delay=0., method=cv2.TM_CCOEFF_NORMED): """ try to click the img :param screen: :param threshold: :param img: :return: success """ self._move_check() at = self._get_at(at) position = UIMatcher.img_where(screen, img, threshold, at, method) if position: self.click(*position, pre_delay, post_delay) return True else: return False def click(self, *args, pre_delay=0., post_delay=0., **kwargs): """ 点击函数 2020-07-28 TheAutumnOfRice:把x,y参数换程args参数以遍兼容各种点击类型 1. 若args为数字的x,y,则点击该位置。 如:self.click(100,200) 2. 若args为PCRelement类型(见core.constant),则: 点击其坐标 :param pre_delay: 前置延时 :param post_delay: 后置延时 :return: True """ self._move_check() time.sleep(pre_delay) if len(args) >= 2 and isinstance(args[0], (int, float)) and isinstance( args[1], (int, float)): # (x,y)型:点击坐标 x = args[0] y = args[1] self.d.click(x, y) time.sleep(post_delay) return True elif len(args) == 1 and isinstance(args[0], PCRelement): # 点击一个PCRelement元素 pe = args[0] self.d.click(pe.x, pe.y) time.sleep(post_delay) return True @staticmethod def _get_img_at(img, at): at = BaseMixin._get_at(at) if isinstance(img, PCRelement): if at is None: at = img.at img = img.img return img, at def is_exists(self, img, threshold=0.84, at=None, screen=None, is_black=False, black_threshold=1500, method=cv2.TM_CCOEFF_NORMED): """ 判断一个图片是否存在。 :param black_threshold: 判断暗点的阈值 :param is_black: 是否判断为暗色图片(多用于检测点击按钮后颜色变暗)灰色返回Ture,默认需要配合at,否则自行调整阈值 :param method: :param img: 一个字符串,表示图片的地址;或者为PCRelement类型。 当img为PCRelement时,如果at参数为None,则会使用img.at。 :param threshold: 判定阈值 :param at: 搜素范围 :param screen: 若设置为None,则重新截图;否则使用screen为截图 :return: 是否存在 """ if screen is None: screen = self.getscreen() img, at = self._get_img_at(img, at) return UIMatcher.img_where(screen, img, threshold, at, method, is_black, black_threshold) is not False def img_prob(self, img, at=None, screen=None, method=cv2.TM_CCOEFF_NORMED): """ 返回一个图片存在的阈值 通过比较两幅图片的阈值大小可以分辨它“更”是什么图 :param img: 一个字符串,表示图片的地址;或者为PCRelement类型。 当img为PCRelement时,如果at参数为None,则会使用img.at。 :param at: 搜素范围 :param screen: 若设置为None,则重新截图;否则使用screen为截图 :return: 是否存在 """ if screen is None: screen = self.getscreen() img, at = self._get_img_at(img, at) return UIMatcher.img_prob(screen, img, at, method) def img_where_all(self, img, threshold=0.9, at=None, screen=None, method=cv2.TM_CCOEFF_NORMED): """ 返回一个图片所有的位置 :param img: 一个字符串,表示图片的地址;或者为PCRelement类型。 当img为PCRelement时,如果at参数为None,则会使用img.at。 :param threshold: 阈值 :param at: 搜素范围 :param screen: 若设置为None,则重新截图;否则使用screen为截图 :return: list[(x,y,at)] """ if screen is None: screen = self.getscreen() img, at = self._get_img_at(img, at) return UIMatcher.img_all_where(screen, img, threshold, at, method) def img_equal(self, img1, img2, at=None, similarity=0.01) -> float: """ 输出两张图片对应像素相似程度 要求两张图片大小一致 :return: 相似度 0~1 """ if isinstance(img1, str): img1 = cv2.imread(img1) if isinstance(img2, str): img2 = cv2.imread(img2) at = self._get_at(at) if at is not None: img1 = UIMatcher.img_cut(img1, at) img2 = UIMatcher.img_cut(img2, at) img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) / 255 img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) / 255 eqt = np.sum(np.abs(img1 - img2) < similarity) / img1.size if debug: print("EQT:", eqt) return eqt def wait_for_stable(self, delay=0.5, threshold=0.2, similarity=0.001, max_retry=0, at=None, screen=None): """ 等待动画结束,画面稳定。此时相邻两帧的相似度大于threshold :param similarity: 近似程度0~1 :param delay: 每次刷新间隔。 :param max_retry: 最大重试次数 :param at: 缩小范围 :param screen: 设置为None时,参照图截图获得,否则参照图 :return: True:动画结束 False:动画未结束 """ sc = self.getscreen() if screen is None else screen retry = 0 at = self._get_at(at) while retry < max_retry or max_retry == 0: self._move_check() retry += 1 time.sleep(delay) sc2 = self.getscreen() value = self.img_equal(sc, sc2, at, similarity) if debug: print("Stable : ", value, " >? ", threshold) if value > threshold: return True sc = sc2 return False def wait_for_change(self, delay=0.5, threshold=0.10, similarity=0.01, max_retry=0, at=None, screen=None): """ 等待画面跳转变化,此时尾帧与头帧的相似度小于threshold :param similarity: 近似程度0~1 :param delay: 每次刷新间隔。 :param max_retry: 最大重试次数 :param at: 缩小范围 :param screen: 设置为None时,参照图截图获得,否则参照图 :return: True:动画改变 False:动画未改变 """ sc = self.getscreen() if screen is None else screen retry = 0 at = self._get_at(at) while retry < max_retry or max_retry == 0: self._move_check() retry += 1 time.sleep(delay) sc2 = self.getscreen() value = self.img_equal(sc, sc2, at, similarity) if debug: print("Stable : ", value, " <? ", threshold) if value < threshold: return True return False def wait_for_loading(self, screen=None, delay=0.5, timeout=30): """ 等待黑屏loading结束 :param screen: 设置为None时,截图,否则使用screen :param delay: 检测间隔 :param timeout: 超过timeout,报错 Add 2020-08-15: 增加对Connect的检测。 """ time.sleep(delay) sc = self.getscreen() if screen is None else screen last_time = time.time() while True: self._move_check() if self.is_exists(img='img/connecting.bmp', at=(748, 20, 931, 53), screen=sc): time.sleep(delay) sc = self.getscreen() continue sc_cut = UIMatcher.img_cut(sc, MAIN_BTN["loading_left"].at) if not (sc_cut == 1).all(): break if time.time() - last_time > timeout: raise Exception("Loading 超时!") time.sleep(delay) sc = self.getscreen() def check_dict_id(self, id_dict, screen=None, max_threshold=0.8, diff_threshold=0.05): """ 识别不同图的编号,比较其概率 :param id_dict: 字典,{key:PCRElement},表示{编号:图片} :param screen: 设置为None时,第一次重新截图 :param max_threshold: 最大阈值,获得图片最大概率必须超过max_threshold :param diff_threshold: 相差阈值,第一大的概率和第二大的概率差必须超过diff_threshold :return: None: 识别失败 Else: 识别的key """ sc = self.getscreen() if screen is None else screen pdict = {} for i, j in id_dict.items(): pdict[i] = self.img_prob(j, screen=sc) tu = max(pdict, key=lambda x: pdict[x]) l = sorted(pdict.values(), reverse=True) if debug: print(tu) print(l) if l[0] < max_threshold or l[0] - l[1] < diff_threshold: return None else: return tu def run_func(self, th_name, a, fun, async_sexitflag=False): if async_sexitflag: th_name.exit() pass else: self.do(a, fun) def do(self, a, fun): # 自定义,在此定义你要运行的参数 getattr(asyncio, 'run')(fun) # getattr获取asyncio中run对象,然后进行调用 # 凄凄惨惨的替代eval这类危险的函数 pass def c_async(self, a, account, fun, sync=False, async_sexitflag=False): _async_infodic = { 'a': a, 'account': account, 'fun': fun, '"pack_Thread-" + str(account)': "pack_Thread-" + str(account), 'async_sexitflag': async_sexitflag } th = Multithreading(kwargs=_async_infodic) # print(threading.currentThread().ident) # id, name th.start() if sync: # 线程同步异步开关,True/False th.join() # 线程等待,执行完才能进入下一个线程 pass else: # 异步,推荐 pass pass def getscreen(self, filename=None): """ 包装了self.d.screenshot 如果self.debug_screen为None,则 :return: 截图的opencv格式 """ # 如果debug_screen为None,则正常截图; # 否则,getscreen函数使用debug_screen作为读取的screen if self.debug_screen is None: if fast_screencut and self.fastscreencut_retry < 3: try: data = self.receive_minicap.receive_img() if data is None: raise Exception("读取数据超过最大尝试次数") # 改用内存缓存 self.last_screen = data # 如果传入了文件路径参数,则保存文件 if filename is not None: cv2.imwrite(filename, self.last_screen) self.fastscreencut_retry = 0 except Exception as e: if force_fast_screencut: raise FastScreencutException(*e.args) else: self.log.write_log("warning", f"快速截图出错 {e}, 使用低速截图") self.fastscreencut_retry += 1 if self.fastscreencut_retry == 3: self.log.write_log("error", f"快速截图连续出错3次,关闭快速截图。") self.receive_minicap.stop() self.last_screen = self.d.screenshot(filename, format="opencv") else: self.last_screen = self.d.screenshot(filename, format="opencv") self.last_screen_time = time.time() return UIMatcher.AutoRotateClockWise90(self.last_screen) else: if isinstance(self.debug_screen, str): return cv2.imread(self.debug_screen) else: return self.debug_screen def find_img(self, img, at=None, alldelay=0.5, ifclick=None, ifbefore=0.5, ifdelay=1, elseclick=None, elsedelay=0.5, retry=0): """ 前身:_lock_img 匹配图片并点击指定坐标 Parameters: img (str): 要匹配的图片目录 at (:tuple: `(int: 左上x, int: 左上y, int: 右下x, int: 右下y)`): 查找范围 ifbefore (float): 识别成功后延迟点击时间 ifclick (:list: ``): 在识别到图片时要点击的坐标,列表,列表元素为坐标如(1,1) ifdelay: 上述点击后延迟的时间 elseclick: 在找不到图片时要点击的坐标,列表,列表元素为坐标如(1,1) elsedelay: 上述点击后延迟的时间 retry: elseclick最多点击次数, `0为无限次` Returns: success (bool): 是否在retry次内点击成功 """ # 2020-07-12 Add: 增加了ifclick,elseclick参数对Tuple的兼容性 # 2020-07-14 Add: added retry if elseclick is None: elseclick = [] if ifclick is None: ifclick = [] if type(ifclick) is tuple: ifclick = [ifclick] if type(elseclick) is tuple: elseclick = [elseclick] inf_attempt = True if retry == 0 else False attempt = 0 while inf_attempt or attempt < retry: self._move_check() screen_shot = self.getscreen() if UIMatcher.img_where(screen_shot, img, at=at): # 成功匹配图片 for clicks in ifclick: self.click(clicks[0], clicks[1], pre_delay=ifbefore, post_delay=ifdelay) break for clicks in elseclick: self.click(clicks[0], clicks[1], post_delay=elsedelay) time.sleep(alldelay) attempt += 1 return True if inf_attempt or attempt < retry else False def guochang(self, screen_shot, template_paths, suiji=1): # suji标号置1, 表示未找到时将点击左上角, 置0则不点击 # 输入截图, 模板list, 得到下一次操作 # 2020-08-08 建议弃用该函数。 screen_shot = screen_shot template_paths = template_paths active_path = UIMatcher.imgs_where(screen_shot, template_paths) if active_path: # print(active_path) if 'img/juqing/tiaoguo_1.bmp' in active_path: x, y = active_path['img/juqing/tiaoguo_1.bmp'] self.click(x, y) else: for name, (x, y) in active_path.items(): # print(name) self.click(x, y) time.sleep(0.5) else: if suiji: # print('未找到所需的按钮,将点击左上角') self.click(0.1 * self.dWidth, 0.1 * self.dHeight) else: # print('未找到所需的按钮,无动作') pass def lock_fun(self, RTFun, *args, ifclick=None, ifbefore=0., ifdelay=1., elseclick=None, elsedelay=0.5, alldelay=0.5, retry=0, is_raise=False, timeout=None, elseafter=0., **kwargs): """ 任意方法锁定 @RTFun 锁定的函数 返回False,锁定失败 返回其它,锁定成功,返回值为函数返回值 """ if elseclick is None: elseclick = [] if ifclick is None: ifclick = [] if type(ifclick) is not list: ifclick = [ifclick] if type(elseclick) is not list: elseclick = [elseclick] attempt = 0 lasttime = time.time() ec_time = 0 # else click time: 上次点elseclick的时间 if timeout is None: timeout = lockimg_timeout while True: self._move_check() lasttime = time.time() if debug: print("FUN:", RTFun) print("FUNOUT:", RTFun()) out = RTFun(*args, **kwargs) if debug: print("OUT:", out) if out: if ifclick != []: for clicks in ifclick: time.sleep(ifbefore) self.click(clicks[0], clicks[1], post_delay=elseafter) time.sleep(ifdelay) return out if ec_time == 0: # 第一次:必点 # 此后每次等待elsedelay ec_time = time.time() - elsedelay if time.time() - ec_time >= elsedelay: if elseclick != []: for clicks in elseclick: self.click(clicks[0], clicks[1], post_delay=elseafter) attempt += 1 ec_time = time.time() time.sleep(alldelay) if retry != 0 and attempt > retry: return False if timeout != 0 and time.time() - lasttime > timeout: if is_raise: if disable_timeout_raise: continue raise Exception("lock_fun 超时!") return False def _lock_img(self, img: Union[PCRelement, str, dict, list], ifclick=None, ifbefore=0., ifdelay=1., elseclick=None, elsedelay=0.5, alldelay=0.5, retry=0, side_check=None, at=None, is_raise=False, lock_no=False, timeout=None, method=cv2.TM_CCOEFF_NORMED, threshold=0.84, elseafter=0.): """ @args: img:要匹配的图片目录 2020-07-31: TheAutumnOfRice Add: img可以传入dict类型 {PCRElement:return_value} 或者: {(img,at):return_value} 此时,at参数不起作用。 2020-08-06: TheAutumnOfRice Add: img可以传入list类型 [PCRElement]或者[(img,at)] 此时,每一个找到的PCRElement,都会对应True 2020-07-28:TheAutumnOfRice Add: img支持兼容PCRelement格式 传入PCRelement后,自动填充img和at。 如果PCRelement含有at属性而外部设置了at,以lockimg的参数为准 ifbefore:识别成功后延迟点击时间 ifclick:在识别到图片时要点击的坐标,列表,列表元素为坐标如(1,1) ifdelay:上述点击后延迟的时间 elseclick:在找不到图片时要点击的坐标,列表,列表元素为坐标如(1,1) elsedelay:上述点击后延迟的时间 retry:elseclick最多点击次数,0为无限次 is_raise: 失败时,是否弹出错误 lock_no: False: lock_img True: lock_no_img timeout: 设置为None时,使用pcr_config中的lockimg_timeout,否则用自己的。 side_check:传入字符串然后调用字符串里边的基于_base的函数方法 elseafter: 点击elseclick后等待的时间 @pcr_config: lockimg_timeout: 设置为0时,不做超时处理;否则,如果超过该时间,报错 @return:是否在retry次内点击成功 """ # 2020-07-12 Add: 增加了ifclick,elseclick参数对Tuple的兼容性 # 2020-07-14 Add: added retry # 2020-07-30 Add: 整合了lockimg 和 lock_no_img,增加timeout # 2020-08-01 Add: 取消了elseclick两个click之间的间隔,elsedelay表 # 示elseclick操作之后的等待时间,该时间内会一直检测。 # 2020-08-01 Add: 增加了局部timeout参数 # 2020-08-06 Add: img可以传入list了 # 2020-8-19 Add:暂停+方法调用 if elseclick is None: elseclick = [] if ifclick is None: ifclick = [] if type(ifclick) is not list: ifclick = [ifclick] if type(elseclick) is not list: elseclick = [elseclick] if isinstance(img, list): tmp = img img = {} for i in tmp: img[i] = True if not isinstance(img, dict): img = {(img, at): True} attempt = 0 lasttime = time.time() ec_time = 0 # else click time: 上次点elseclick的时间 if timeout is None: timeout = lockimg_timeout while True: screen_shot = self.getscreen() # 方法配对,如有需要可以加个验证side_check是否合法 if side_check is not None: # 感谢Sisphyus大佬分享的文章 # side_check理论支持调用_base的所有子类方法 # _method = getattr(self, side_check) determine = side_check(screen_shot) if determine: lasttime = time.time() if self._move_check(): lasttime = time.time() for i, j in img.items(): if not isinstance(i, PCRelement): _img, _at = self._get_img_at(i[0], i[1]) else: _img, _at = self._get_img_at(i, None) if self.is_exists(_img, at=_at, screen=screen_shot, method=method, threshold=threshold) is not lock_no: if ifclick != []: for clicks in ifclick: time.sleep(ifbefore) self.click(clicks[0], clicks[1], post_delay=elseafter) time.sleep(ifdelay) return j if ec_time == 0: # 第一次:必点 # 此后每次等待elsedelay ec_time = time.time() - elsedelay if time.time() - ec_time >= elsedelay: if elseclick != []: for clicks in elseclick: self.click(clicks[0], clicks[1], post_delay=elseafter) attempt += 1 ec_time = time.time() time.sleep(alldelay) if retry != 0 and attempt > retry: return False if timeout != 0 and time.time() - lasttime > timeout: if is_raise: if disable_timeout_raise: continue raise Exception("%s——lock_img 超时!" % img) return False def lock_img(self, img, ifclick=None, ifbefore=0., ifdelay=1., elseclick=None, elsedelay=2., alldelay=0.5, retry=0, at=None, is_raise=True, timeout=None, method=cv2.TM_CCOEFF_NORMED, threshold=0.84, side_check=None, elseafter=0.): """ 锁定图片,直到该图出现。 图片出现后,点击ifclick;未出现,点击elseclick """ return self._lock_img(img, ifclick=ifclick, ifbefore=ifbefore, ifdelay=ifdelay, elseclick=elseclick, elsedelay=elsedelay, alldelay=alldelay, retry=retry, at=at, is_raise=is_raise, lock_no=False, timeout=timeout, method=method, threshold=threshold, side_check=side_check, elseafter=elseafter) def lock_no_img(self, img, ifclick=None, ifbefore=0., ifdelay=1., elseclick=None, elsedelay=2., alldelay=0.5, retry=0, at=None, is_raise=True, timeout=None, method=cv2.TM_CCOEFF_NORMED, threshold=0.84, side_check=None, elseafter=0.): # 锁定指定图像 """ 锁定图片,直到该图消失 图片消失后,点击ifclick;未消失,点击elseclick """ return self._lock_img(img, ifclick=ifclick, ifbefore=ifbefore, ifdelay=ifdelay, elseclick=elseclick, elsedelay=elsedelay, alldelay=alldelay, retry=retry, at=at, is_raise=is_raise, lock_no=True, timeout=timeout, method=method, threshold=threshold, side_check=side_check, elseafter=elseafter) def click_btn(self, btn: PCRelement, elsedelay=8., timeout=30., wait_self_before=False, until_appear: Optional[Union[PCRelement, dict, list]] = None, until_disappear: Optional[Union[str, PCRelement, dict, list]] = "self", retry=0, is_raise=True, method=cv2.TM_CCOEFF_NORMED, elseafter=None, side_check=None): """ 稳定的点击按钮函数,合并了等待按钮出现与等待按钮消失的动作 :param side_check: 检测 :param retry: 尝试次数,少用 :param btn: PCRelement类型,要点击的按钮 :param elsedelay: 尝试点击按钮后等待响应的间隔 :param timeout: lockimg和lock_no_img所用的超时参数 :param wait_self_before: 是否等待本按钮出现,再进行点击 :param until_appear: 是否在点击后等待该元素出现,再返回 设置为None(默认)时不等待按钮出现 设置为PCRelement的时候,检测该元素是否出现,出现则返回 :param until_disappear: 是否在点击后等待该元素消失,再返回 设置为None时不等待按钮消失 设置为"self"(默认)时等待按钮自己消失 设置为PCRelement的时候,检测该元素是否消失 若指定元素没有消失,则每过elsedelay的时长点击一次按钮 (until_disappear,until_appear不要同时使用) :param is_raise: 是否报错。设置为False时,匹配失败,返回False :param method: 用于lockimg的方法 :param elseafter: 默认值None,此时,若条件为until_disappear="self",则设置为0.8,否则为0. 点击之后的等待时间。 """ r = 0 if isinstance(until_disappear, str): assert until_disappear == "self" if wait_self_before is True: r = self.lock_img(btn, timeout=timeout, retry=retry, is_raise=is_raise, method=method, side_check=side_check) if until_disappear is None and until_appear is None: self.click(btn, post_delay=0.5) # 这边不加延迟,点击的波纹会影响到until_disappear自己 else: if until_appear is not None: r = self.lock_img( until_appear, elseclick=btn, elsedelay=elsedelay, timeout=timeout, retry=retry, is_raise=is_raise, method=method, elseafter=0 if elseafter is None else elseafter, side_check=side_check) elif until_disappear == "self": r = self.lock_no_img( btn, elseclick=btn, elsedelay=elsedelay, timeout=timeout, retry=retry, is_raise=is_raise, method=method, elseafter=0.8 if elseafter is None else elseafter, side_check=side_check) elif until_disappear is not None: r = self.lock_no_img( until_disappear, elseclick=btn, elsedelay=elsedelay, timeout=timeout, retry=retry, is_raise=is_raise, method=method, elseafter=0 if elseafter is None else elseafter, side_check=side_check) return r def chulijiaocheng(self, turnback="shuatu"): # 处理教程, 最终返回刷图页面 """ 这个处理教程函数是给chushihua.py用的 有引导点引导 有下一步点下一步 有主页点主页 有圆menu就点跳过,跳过 有跳过点跳过 都没有就点边界点 # 有取消点取消 :turnback: shuatu: 返回刷图页面 None: 不返回任何页面 :return: """ count = 0 # 出现主页的次数 while True: screen_shot_ = self.getscreen() num_of_white, _, x, y = UIMatcher.find_gaoliang(screen_shot_) if num_of_white < 77000: try: self.click(x * self.dWidth, y * self.dHeight + 20) except: pass time.sleep(1) continue if UIMatcher.img_where(screen_shot_, 'img/liwu.bmp', at=(891, 413, 930, 452)): count += 1 if count > 2: break time.sleep(1) continue elif UIMatcher.img_where(screen_shot_, 'img/jiaruhanghui.jpg'): break elif self.click_img(screen_shot_, 'img/xiayibu.jpg'): time.sleep(2) elif self.click_img(screen_shot_, 'img/niudan_jiasu.jpg', at=(700, 0, 960, 100)): pass elif self.click_img(screen_shot_, 'img/wuyuyin.jpg', at=(450, 355, 512, 374)): time.sleep(3) elif self.click_img(screen_shot_, 'img/juqing/tiaoguo_2.bmp'): time.sleep(3) elif self.click_img(screen_shot_, 'img/zhuye.jpg', at=(46, 496, 123, 537)): pass elif self.click_img(screen_shot_, 'img/juqing/caidanyuan.bmp', at=(898, 23, 939, 62)): time.sleep(0.7) self.click(804, 45) time.sleep(0.7) self.click(593, 372) time.sleep(2) elif UIMatcher.img_where(screen_shot_, 'img/qianwanghuodong.bmp'): for _ in range(3): self.click(390, 369) time.sleep(1) else: self.click(1, 100) count = 0 time.sleep(1) if turnback == "shuatu": # 返回冒险 self.click(480, 505) time.sleep(2) self.lock_img('img/zhuxianguanqia.jpg', elseclick=[(480, 513), (390, 369)], elsedelay=0.5) while True: screen_shot_ = self.getscreen() if UIMatcher.img_where(screen_shot_, 'img/zhuxianguanqia.jpg', at=(511, 286, 614, 314)): self.click(562, 253) time.sleep(0.5) else: break time.sleep(3) while True: screen_shot_ = self.getscreen() if UIMatcher.img_where(screen_shot_, 'img/normal.jpg', at=(660, 72, 743, 94)): break self.click(704, 84) time.sleep(0.5) def task_start(self): # 标记这个用户开始重新刷图了 d = self.AR.get_run_status() d["finished"] = False d["current"] = "..." self.AR.set_run_status(d) def task_finished(self): # 标记这个用户已经刷完了图 d = self.AR.get_run_status() d["finished"] = True self.AR.set_run_status(d) def task_current(self, title): # 标记这个用户当前正在进行的项目 d = self.AR.get_run_status() d["current"] = title self.AR.set_run_status(d) def task_error(self, error): # 标记某一项错误,并停止刷图 d = self.AR.get_run_status() d["finished"] = True d["error"] = error self.AR.set_run_status(d) def juqing_kkr(self, screen_shot=None): """ 处理剧情+剧情版的可可萝 :return: """ if screen_shot is None: screen_shot = self.getscreen() if self.is_exists(JUQING_BTN["caidanyuan"], screen=screen_shot): self.click_btn(JUQING_BTN["caidanyuan"], wait_self_before=True, until_appear=JUQING_BTN["tiaoguo_1"]) # 菜单 self.click_btn(JUQING_BTN["tiaoguo_1"], until_appear=JUQING_BTN["tiaoguo_2"]) # 跳过 self.click_btn(JUQING_BTN["tiaoguo_2"], until_disappear=JUQING_BTN["tiaoguo_2"]) # 蓝色跳过 return True elif self.is_exists(img='img/kekeluo.bmp', at=(181, 388, 384, 451), screen=screen_shot): # 防妈骑脸 self.lock_no_img('img/kekeluo.bmp', elseclick=[(1, 1)], at=(181, 388, 384, 451)) return True return False def right_kkr(self, screen=None): """ 处理提示kkr。一般在右边。 处理方法:点屏幕 :param screen: """ flag = False if screen is None: screen = self.getscreen() cnt = 0 while self.is_exists(MAIN_BTN["right_kkr"], screen=screen): self.click(1, 1, post_delay=1) flag = True cnt += 1 if cnt >= 10: raise Exception("点了10次,可可罗依然没有消失!") screen = self.getscreen() return flag def phone_privacy(self): """ 2020/7/10 模拟器隐私函数 '高'匿名 防记录( By:CyiceK :return: """ def luhn_residue(digits): return sum( sum(divmod(int(d) * (1 + i % 2), 10)) for i, d in enumerate(digits[::-1])) % 10 def _get_imei(n): part = ''.join(str(random.randrange(0, 9)) for _ in range(n - 1)) res = luhn_residue('{}{}'.format(part, 0)) return '{}{}'.format(part, -res % 10) # print("》》》匿名开始《《《", self.address) tmp_rand = [] tmp_rand = random.sample(range(1, 10), 3) phone_model = { 1: 'LIO-AN00', 2: 'TAS-AN00', 3: 'TAS-AL00', 4: 'AUSU-AT00', 5: 'AAA-SN00', 6: 'GMI1910', 7: 'G-OXLPix', 8: 'AM-1000', 9: 'G7', } phone_manufacturer = { 1: 'HUAWEI', 2: 'MEIZU', 3: 'XIAOMI', 4: 'OPPO', 5: 'VIVO', 6: 'MOTO', 7: 'GooglePix', 8: 'Redmi', 9: 'LG', } os.system('cd adb & adb -s %s shell setprop ro.product.model %s' % (self.address, phone_model[tmp_rand[0]])) os.system( 'cd adb & adb -s %s shell setprop ro.product.manufacturer %s' % (self.address, phone_manufacturer[tmp_rand[1]])) os.system('cd adb & adb -s %s shell setprop phone.imei %s' % (self.address, _get_imei(15))) os.system('cd adb & adb -s %s shell setprop ro.product.name %s' % (self.address, phone_model[tmp_rand[2]])) os.system('cd adb & adb -s %s shell setprop phone.imsi %s' % (self.address, _get_imei(15))) os.system('cd adb & adb -s %s shell setprop phone.linenum %s' % (self.address, _get_imei(11))) os.system('cd adb & adb -s %s shell setprop phone.simserial %s' % (self.address, _get_imei(20)))