def copyItem(self, i_from='', i_to=''): if self.check(i_from): self.set(i_to, self.get(i_from)) return True else: logger.error('不存在名为%s的数据') % i_from return False
def _parseGetStageDrop(self, ver: bytes): ver = int.from_bytes(ver, 'little') try: return getattr(self, f"_getStageDrop_Ver{ver}") except AttributeError: logger.error(f"解析中断:未知的关卡掉落解析器版本:Ver{ver}") raise AttributeError(f"Unknown Parser Version:{ver}")
def import_from_data(self, datain): if type(datain) == dict: self._imp_data_dict(datain) elif type(datain) == list: self._imp_data_list(datain) else: logger.error('数据非list/dict形!')
def seek(self, name): if name == '_root': self.read = self.cfg self.__u = [] return True elif name == '..': u = self.__u if u.__len__() == 0: self.read = self.cfg logger.error("当前目录已达到_root!") return False else: self.read = self.cfg u.pop(-1) for i in u: self.read = getattr(self.read, i) self.__u = u return True elif name in self.read.folder: self.__u.append(name) self.read = getattr(self.read, name) return True else: logger.error('当前分支下不存在名为"%s"的分支' % name) return False
def addRawItem(self, raw_name, quantity): for field in self.__allKnownFields__: realName = field.get(raw_name, None) if realName is not None: return self._direct_add(realName, quantity) logger.error(f"0:不存在名为'{raw_name}'的物品") return self
def recognizeOperation(image, map_dict=None) -> Tuple[str, str]: if not map_dict: map_dict = getMapCost() opidtext = fix_known_data(load_data()[1].recognize2( image, subset='0123456789abcdefghijklmnopqrstuvwxyz-')[0]) where_ = map_dict.where(opidtext) if where_: return opidtext, where_ # 无法识别,尝试使用tesseract logger.warning("无法识别地图信息" + opidtext) debug_ret = [] import pytesseract for index in range(10): ret = pytesseract.image_to_string(image, lang="eng") \ .replace("\n", "").replace("\x0c", "") where_ = map_dict.where(ret) debug_ret.append(ret) if where_: logger.debug("识别信息:%s" % str(debug_ret)) return ret, where_ logger.error("在10次识别后依旧无法识别出当前关卡信息。") logger.debug("识别信息:%s" % str(debug_ret)) return "", ""
def _detect_image(self, dobj, image, sub_area=None): # {"type": type_, # "image": imagePath, # "threshold": threshold, # "area": list(locationarea) if locationarea else None, # "diff": diff} # read with x,y,w,h dump x1,x2,y1,y2 if sub_area is None: if dobj["area"] is not None: x, y, w, h = dobj["area"] img = image[y:y + h, x:x + w] else: img = image else: img = image if (sub_area[0] > dobj["area"][0] and sub_area[1] > dobj["area"][1]) or \ (sub_area[2] < dobj["area"][2] and sub_area[3] < dobj["area"][3]): return 'I', dobj["diff"], 0, True try: result = np.max( self.__gameTemp__.matchDifference(img, self.__gameTemp__.getTemplate(dobj["image"])[0], method=2)) except ValueError: logger.error(f"Image load failed:{dobj['image']}") result = 0 except cv2.error: logger.error(f"Image compare failed:{dobj['image']}") result = 0 return 'I', dobj["diff"], 0 if result > dobj["threshold"] else 1, False
def getSkillUpgradeCost(self, skillID=0, level_from=1, level_to=7, show=False): from ArkType.ItemStack import ItemStack skillID -= 1 if len(self["skills"]) < skillID: logger.error(f"该角色无第{skillID}技能 最大技能:{len(self['skills'])}") return ItemStack() ret = ItemStack() for level in range(level_from, level_to): try: if level <= 6: for item in self["allSkillLvlup"][level - 1]['lvlUpCost']: ret.addItemFromCharCost(item) elif 6 < level <= 9: for item in self["skills"][skillID]["levelUpCostCond"][ level - 7]["levelUpCost"]: ret.addItemFromCharCost(item) except Exception as e: logger.error( f"CHAR={self['name']},SKILL={skillID},LVL={level},ERR={str(e)}" ) if show: logger.notice( f"{self['name']}{skillID}技能 {level_from}->{level_to} " f"消耗{ret.formatItems('%item%(%quantity%) ')}") return ret
def getStageInfo(self, stageName: str): if stageName is None: return [None] for name, data in self.maps.items(): if stageName in [i for i, v in data['stages']]: return name, data logger.error(f"未知关卡名称'{stageName}',请检查!")
def clickEpNearist(self, mapId: int): targMap = mapId targStage = None currMap = None currStage = None for stage, include in ArkMap_MainStage.items(): if mapId in include: targStage = int(stage[-1]) if self.__ark.gameTemp.dingwei( f"main\\epstage\\{stage}.png", self.__ark.getScreenShot(121, 208, 86, 47)): currStage = int(stage[-1]) for inc in include: if self.__ark.gameTemp.dingwei( f"main\\epstage\\{inc}.png", self.__ark.getScreenShot(871, 383, 149, 68)): currMap = inc logger.debug(f"[{targStage}-{targMap} {currStage}-{currMap}]") if not (targMap and targStage and currMap and currStage): logger.error( f"未找到地图![{targStage}-{targMap} {currStage}-{currMap}]") raise KeyError(f"未找到地图") if currStage == targStage: self.__ark.clicker.mouse_click( 945 - 312 * min(3, max(currMap - targMap, 0)), 367, t=1.3) return -1 dist = targStage - currStage clk = (64, 133) if dist < 0 else (65, 517) for rg in range(abs(dist)): self.__ark.clicker.mouse_click(*clk, t=0.7) logger.debug(f"{clk},{dist}") return self.clickEpNearist(mapId)
def fromActivityMapMainToActivityMap(self, targMap: str, targStage: str): logger.debug(f"Activity MapMain To Map:{targMap} for {targStage}") if targMap in ACTIVITY_MAP: # TODO:适配所有的活动地图 time.sleep(1.5) if targMap == 'CB': return self.activityMapAdapter((1098, 438), 'CB-', (1061, 613), 'CB-EX-', 2, 2, 0, targStage, targMap) if targMap == 'MB': return self.activityMapAdapter((1140, 162), 'MB-', (1140, 295), 'MB-EX-', 2, 2, 1, targStage, targMap) if targMap == 'WR': return self.activityMapAdapter((1157, 598), 'WR-', (1030, 630), 'WR-EX-', 1.7, 1.7, 1.7, targStage, targMap) if targMap == 'OD': return self.activityMapAdapter((205, 317), 'OD-', (205, 397), 'OD-EX-', 2, 2, 1.5, targStage, targMap) if targMap == 'DM': return self.activityMapAdapter((789, 523), 'DM-', (870, 640), 'DM-EX-', 1.3, 1.5, 1.5, targStage, targMap) logger.error(f"当前地图'{targMap}'尚未适配进入模式,请在ArkMap中进行适配后再次运行") return False return True
def addChild(self, name=None, data=None): if name: if not hasattr(self, name): setattr(self, name, configTree(name)) self.folder.append(name) return True elif getattr(self, name) == None: setattr(self, name, configTree(name)) self.folder.append(name) return True elif name in self.folder: logger.error("子分支名称重复了") return False else: logger.error('禁止使用子数组名称命名') return False elif data: if hasattr(data, '_root'): if data._root not in self.folder: self.folder.append(data._root) setattr(self, data._root, data) return True else: logger.error("子分支名称重复了") return False else: logger.error('分支数据错误') self.wrong = data return False else: logger.error('?ErrSomewhere...') return False
def listall(self): try: logger.common('[item]' + str(self.item)[1:-1:]) print('[folder]' + str(self.folder)[1:-1:]) return True except: logger.error("不存在参数!") return False
def check(self, data): if data == '' or data is None: logger.error('数据不能为空!') return False if data in self._keylist or data in self._vallist: logger.error('禁止存在相同数据!') return False return True
def addItem(self, name, quantity, check=True): if not check: return self._direct_add(name, quantity) for field in self.__allKnownFields__: if name in field.values(): return self._direct_add(name, quantity) logger.error(f"0:不存在名为'{name}'的物品") return self
def fromMaptoMapMain(self, mapName: str = None): if mapName is None: # 自动定位当前位置 loc = self.__ark.getLocation(self.__ark.getScreenShot(), self.RECO, addon=True) logger.debug(f"获得当前定位于{loc}") if len(loc) == 0: if not self.toMain(): logger.error('无法定位当前位置且无法返回主界面!请检查!') # raise ValueError("cannot locate current location") return False else: self.__ark.clicker.mouse_click(923, 201, t=1.7) return True if loc[0] == 'map_atk': # 在攻击界面 但是不知道在哪个关卡的攻击界面 # 因此还需要返回后再次进行识别 self.__ark.clicker.mouse_click(86, 42, t=1) loc = self.__ark.getLocation(self.__ark.getScreenShot(), self.RECO, addon=True) logger.debug("在攻击界面中,返回后执行识别:" + str(loc)) if not loc: if not self.toMain(): logger.error("请切换至任一地图、主界面或地图主界面再试一次!") return None else: self.__ark.clicker.mouse_click(923, 201, t=1.7) return True if loc[0] == 'map_main': return True if loc[0] == 'main': self.__ark.clicker.mouse_click(923, 201, t=1.7) return True if loc[0] in ['map_ep', 'map_mat', 'map_exterm']: if 'map_exterm.inmap' in loc: self.__ark.clicker.mouse_click(86, 42, t=1.5) self.__ark.clicker.mouse_click(86, 42, t=1) self.__ark.clicker.mouse_click(80, 658, t=1) return True if loc[0] in ArkMap_ACTIVITY: self.__ark.clicker.mouse_click(86, 42, t=1) self.__ark.clicker.mouse_click(86, 42, t=1) self.__ark.clicker.mouse_click(80, 658, t=1) return True else: # TODO: 存在mapName 进行位置检测 # 否则需要有开始行动标志的界面介入 if mapName in ACTIVITY_MAP: # 需要额外返回上一级的特殊地图 self.__ark.clicker.mouse_click(86, 42, t=1.6) self.__ark.clicker.mouse_click(86, 42, t=1) self.__ark.clicker.mouse_click(86, 42, t=1) self.__ark.clicker.mouse_click(80, 658, t=1) return True
def _detect_condition(self, result, condition, suc, show): _cond = self._replace_condition_value(condition, result, suc, show) if _cond == '': return True try: return bool(eval(_cond)) except Exception as e: logger.error(f"Detect ERROR!(cond='{_cond}'):{e}") return None
def _readfromdict(self, dictin): if isinstance(dictin, dict): for key in dictin.keys(): value = dictin.get(key) if self.check(key) and self.check(value): self._keylist.append(key) self._vallist.append(value) else: logger.error('输入非dict类型')
def autoAddItem(self, name, quantity): for field in self.__allKnownFields__: if name in field.values(): return self._direct_add(name, quantity) for field in self.__allKnownFields__: realName = field.get(name, None) if realName is not None: return self._direct_add(realName, quantity) logger.error(f"-1:不存在名为'{name}'的物品") return self
def delPoint(self, name: str, index: int = None, x: int = None, y: int = None): if self.config.get(name) is None: logger.error("不存在明文%s的数据集!") return False if index is not None: return self.config.get(name).pop(index) else: for _ in self.config.get(name): if _[0] == x and _[1] == y: self.config.get(name).remove(_) return _
def dingwei(self, name, image, threshold=None): template, tbd, default_th, tbd = self.getTemplate(name) if template.all() is None: logger.error("未找到名为%s的定位标志" % name) return [] else: threshold = threshold or default_th return self.matchDifference(image, template, threshold, method=self.TEMPLATE)
def getStageDrop(self, stageId: str): if not os.path.isfile(f"{DROPFOLDER_PATH}{stageId}.drp"): return list() data = [] with open(f"{DROPFOLDER_PATH}{stageId}.drp", 'rb') as f: while (_ver := f.read(1)) != b'': try: data.append(self._parseGetStageDrop(_ver)(stageId, f)) except AttributeError: logger.error(f"got Unparsed data at {len(data) + 1},Version={_ver}. break") break
def delPoint(self, name, index=None, x=None, y=None): assert self.checkMapExist(name) _detector = self.getMap(name).get("detector") if index is not None: _detector.delDetector_Index(index) elif x is not None and y is not None: _detector.delDetector_XY(x, y) else: logger.error("index and (x,y) can not be None at sametime") return False return True
def detect(self, image, condition, sub_area=None, type='L', show=False): result = [] suc = {'I': 0, 'C': 0} for dobj in self: ret = self._auto_detect(dobj, image, sub_area=sub_area) if ret is None: logger.error("Wrong type of detector!%s" % dobj.get("type")) continue suc[ret[0]] += (1 if ret[2] < 0.2 else 0) result.append(ret) return result, self._detect_condition(result, condition, [suc['I'], suc['C']], show)
def getTemplate(self, name) -> [np.ndarray, str, float, bool]: try: v = getattr(self, name) if not v[3]: v[0] = self.loadImage(v[1]) v[3] = True return v except (NameError, AttributeError): return [None, None, None, None] except ValueError: logger.error("图像" + name + "路径不存在") return [None, None, None, None]
def _check_value(self): for k, v in self.items(): if isinstance(v, (int, float)): continue if isinstance(v, str): try: self[k] = float(v) except: logger.error( f"cannot convert {v} to an float format. remove {k} instead" ) self.pop(k)
def stageInSameMap(self, stage1, stage2, mapName=None): if mapName is not None: if stage2 in [name for name, pos in self.maps[mapName]["stages"]]: return True return False for mapName, data in self.maps.items(): stagelist = [name for name, pos in data["stages"]] if stage1 in stagelist: if stage2 in stagelist: return True return False logger.error(f"{stage1} not in the MapData") return False
def fromPlanner(planned_data, require_request=False): if not isinstance(planned_data, dict): logger.error( f"规划数据并非dict形式,请检查(获得了{planned_data.__class__.__name__})") return StageSet() stages = planned_data.get("stages", []) if not stages: logger.warning("规划数据关卡列表为空!") return StageSet() ret = StageSet() for stage in stages: ret.addStage(stage['stage'], int(float(stage['count']) + 0.9), stage['items'], require_request) return ret
def getEvolveCost(self, now=1, target=2): from ArkType.ItemStack import ItemStack if target < now: logger.error(f"角色目标精英化阶段需要大于当前精英化阶段") return ItemStack() ret = ItemStack() for targ in range(now, target): _UM = targ + 1 try: for item in self["phases"][_UM]["evolveCost"]: ret.addItemFromCharCost(item) except Exception as e: logger.error(f"CHAR={self['name']},EVOLVE={_UM},ERR={str(e)}") return ret
def update(self, filter_freq=200, filter_stages=[], url_stats='result/matrix?show_closed_zone=true', url_rules='formula', path_stats=MATRIX_FILE_DIR + '/data/matrix.json', path_rules=MATRIX_FILE_DIR + '/data/formula.json', force=True): """ To update parameters when probabilities change or new items added. Args: url_stats: string. url to the dropping rate stats data. url_rules: string. url to the composing rules data. path_stats: string. local path to the dropping rate stats data. path_rules: string. local path to the composing rules data. """ if os.path.isfile(f"{MATRIX_FILE_DIR}/data/matrix.json") and force: mtime = os.path.getmtime(f"{MATRIX_FILE_DIR}/data/matrix.json") logger.debug(f"planner MTime is {int(mtime)},creating backup folder") if not os.path.exists(f"{MATRIX_FILE_DIR}/data/b_{int(mtime)}/"): os.mkdir(f"{MATRIX_FILE_DIR}/data/b_{int(mtime)}/") for _ in os.listdir(f"{MATRIX_FILE_DIR}/data/"): if _ != ".gitkeep" and os.path.isfile(f"{MATRIX_FILE_DIR}/data/{_}"): shutil.move(f"{MATRIX_FILE_DIR}/data/{_}", f"{MATRIX_FILE_DIR}/data/b_{int(mtime)}/{_}") logger.debug("file backup successful") logger.notice(f'Start to update Planning data {time.asctime(time.localtime(time.time()))}.') if not force: # if not force to update, try loading data from file. try: material_probs, self.convertion_rules = load_data(path_stats, path_rules) except: # loading failed, try loading from server. force = True if force: # load from server. try: logger.common('Requesting data from web resources (i.e., penguin-stats.io)...') material_probs, self.convertion_rules = request_data(penguin_url + url_stats, penguin_url + url_rules, path_stats, path_rules) logger.common('done.') except: logger.error("Request data error.") return if filter_freq: filtered_probs = [] for drop in material_probs['matrix']: if drop['times'] >= filter_freq and drop['stageId'] not in filter_stages: filtered_probs.append(drop) material_probs['matrix'] = filtered_probs if self._pre_processing(material_probs, forceupdate=force) != -1: self._set_lp_parameters()