def recognizeEndItems(ark, stageCode, quantity=True): drop_list = getDropList(stageCode) for i in getActivityOpen()[1]: drop_list.add((i, getItemTag()['items'][i].get('name', "未知物品:" + i))) # drop_list = list(drop_list) # return drop_list screen = ark.getScreenShot(470, 520, 800, 160) drop_reco = [] for item, name in drop_list: try: rep, where = ark.gameTemp.matchDifference( screen, cv2.resize( ark.gameTemp.getTemplate("lootitem\\" + item + ".png")[0], itemReco.STAGE_DROP)[29:29 + 46, 34:34 + 68], method=1) except cv2.error as cverr: logger.warning( f"处理掉落物'{name}'失败:(code={cverr.code}){cverr.err} in function '{cverr.func}'" ) continue y, x, num = -1, -1, -1 if rep >= 0.9: y, x = int(where[0]), int(where[1]) x += 26 y += 63 if quantity: imgraw = Image.fromarray(screen[y:y + 27, x:x + 53]) numimg = imgops.crop_blackedge2(imgraw, 120) if numimg is None or numimg.size < (5, 5): numimg = imgops.clear_background(imgraw, threshold=180) # cv2.imshow("d",np.asarray(numimg)); cv2.waitKey(0) img = imgops.clear_background(numimg, threshold=120) # cv2.imshow("i", np.asarray(img)); cv2.waitKey(0) reco = ark.reconizerN.recognize2(img, subset="0123456789万") try: num = int(reco[0]) if reco != '' else 0 except: num = 0 else: num = -1 err = rep > 0.9 and num <= 0 if err: logger.warning(f"识别到物品\"{name}\"数量出现异常,已置零,该物品将不计入统计中") # drop_reco.append([name, rep > 0.9, rep, [x, y], num]) drop_reco.append({ "name": name, "have": rep > 0.9, "_acq": rep, "_pos": (x, y), "quantity": num, "error": err }) return drop_reco
def UpgradeDropFromVer1_ToVer2(ark, stage, force=False): drp = getStageTag().getStage(stage).getDropInfo().getDropList() li = list(i[1] for i in drp) se = set(i[1] for i in drp) if len(li) != len(se): logger.warning('Unable to upgrade the level with different drop overlaps from Ver.1 to Ver.2!') if not force: return False drop_info = ark.dropLinker.getStageDrop(stage) drp_wname = {} for drop_type, game_id in drp: drop_name = getItemTag()['items'].get(game_id)['name'] drop_id = ark.dropLinker.get(drop_name) drp_wname.update({drop_name: [drop_name, drop_id, drop_type]}) for index in range(len(drop_info)): cur_drop: DropInfo = drop_info[index] if cur_drop.getVersion() != 1: continue if cur_drop.isEmpty(): logger.warning(f"Find Empty Attack at Index:{index} in Stage:{stage},Set to None.") drop_info[index] = None continue new_drop = DropItemStack() ERR_G = [None, None, None] for type_, drp_li in cur_drop.dropList.items(): for drp_name, drop_q in drp_li: new_drop.addItem(drp_name, drop_q, drp_wname.get(drp_name, ERR_G)[2] or 253) drop_info[index] = DropInfo(2, stage, cur_drop.attackTime, new_drop) # Write file Structure:([version \x02][len(droplist)<1>][[itemid<2>][quantity<2>][type<1>]]..[atk_time<3>][time<4>]) # save raw file to backup os.rename(f"{DROPFOLDER_PATH}{stage}.drp", f"{DROPFOLDER_PATH}{stage}.drp.U12.{randomstr()}") ttl_upg = 0 with open(f"{DROPFOLDER_PATH}{stage}.drp", 'wb') as fd: for dropstack in drop_info: if dropstack is None: continue fd.write(b'\x02') all_items = dropstack.dropList.getAllItems() fd.write(len(all_items).to_bytes(1, 'little')) for name, quantity, type_ in all_items: fd.write(ark.dropLinker.get(name).to_bytes(2, 'little')) fd.write(quantity.to_bytes(2, 'little')) fd.write((type_ + 1).to_bytes(1, 'little')) cost_time = dropstack.atk_in_t or 0 try: fd.write(int(cost_time * 100).to_bytes(3, 'little')) except OverflowError: logger.warning(f"cannot convert cost_time({cost_time}) into byte!") fd.write(b'\xff\xff\xff') fd.write(dropstack.attackTime.to_bytes(4, 'little')) ttl_upg += 1 logger.notice(f"Upgrade Finished![STAGE {stage},{ttl_upg}TUI]") return drop_info
def addItemFromRawDict(self, dumpdict: dict): if dumpdict.get('type') in ['FURN', 'CHAR', 'NONE', 'ET_STAGE']: logger.warning( f"cannot add type:{dumpdict.get('type')} into ItemStack") return self try: return self.addItem( getItemTag()['items'].get(dumpdict.get('id'))['name'], int(dumpdict.get('count'))) except: logger.warning( f"cannot add [T:{dumpdict.get('type')} I:{dumpdict.get('id')}] into ItemStack" ) return self
def recognizeEndItemsWithTag(ark, stageCode_or_dropList, quantity=True): def removeClosePos(gps: list): if len(gps) <= 1: return gps gps.sort() final = [gps[0]] prev_x = gps[0][0] for _x, _y in gps: if -7 < prev_x - _x < 7: continue prev_x = _x final.append(( _x, _y, )) return final if isinstance(stageCode_or_dropList, str): drop_list = getDropList(stageCode_or_dropList) else: drop_list = stageCode_or_dropList for i in getActivityOpen()[1]: drop_list.add((i, getItemTag()['items'][i].get('name', "未知物品:" + i))) screen = ark.getScreenShot(470, 520, 800, 160) drop_reco = [] for item, name in drop_list: dumped = False try: gps = ark.gameTemp.matchDifference( screen, cv2.resize( ark.gameTemp.getTemplate("lootitem\\" + item + ".png")[0], itemReco.STAGE_DROP)[29:29 + 46, 34:34 + 68], threshold=0.9) except cv2.error as cverr: try: gps = ark.gameTemp.matchDifference( screen, ark.gameTemp.getTemplate("lootitem\\dumped\\" + item + ".png")[0][29:29 + 46, 34:34 + 68], threshold=0.9) dumped = True except (cv2.error, TypeError): logger.warning( f"处理掉落物'{name}<{item}>'失败:(code={cverr.code}){cverr.err} in function '{cverr.func}'" ) continue gps = removeClosePos(gps) for x, y in gps: if dumped: y = 28 # 检测所有位置的掉落信息,分别根据不同位置判断不同掉落属性dropType num = -1 x += 26 y += 63 if quantity: imgraw = Image.fromarray(screen[y:y + 27, x:x + 53]) # cv2.imshow('r', np.array(imgraw)) # cv2.waitKey(0) numimg = imgops.crop_blackedge2(imgraw, 150) # cv2.imshow('n', np.array(numimg)) # cv2.waitKey(0) if numimg is None or numimg.size < (5, 5): numimg = imgops.clear_background(imgraw, threshold=180) img = imgops.clear_background(numimg, threshold=120) # cv2.imshow('g', np.array(img)) # cv2.waitKey(0) reco = ark.reconizerN.recognize2(img, subset="0123456789万") # print(reco) try: num = int(reco[0]) if reco != '' else 0 except: num = 0 else: num = -1 err = num <= 0 if err: logger.warning(f"识别到物品\"{name}\"数量出现异常({num}),已置零,该物品将不计入统计中") else: drop_reco.append({ "name": name, "have": True, "_acq": 0.9, "type": recognizeEndItemDropType(screen, x), "_pos": (x, y), "quantity": num, "error": err }) return drop_reco
class ItemStack(dict): __itemType__ = ItemType() __roguList__ = getRogueLikeItemNameDict() __itemList__ = getItemNameDict() __charList__ = getCharNameDict() __skinList__ = getSkinNameDict() __furnList__ = getFurniItemNameDict() __allKnownFields__ = [ __itemList__, __furnList__, __charList__, __skinList__, __roguList__ ] __itemtag__ = getItemTag()["items"] def __init__(self, *val, **kwargs): # ItemStack({"扭转醇":1}) # ItemStack(扭转醇=1,...) # ItemStack("扭转醇:1","固源岩:1") if len(val) == 0: super(ItemStack, self).__init__() elif isinstance(val[0], dict): super(ItemStack, self).__init__(val[0]) elif isinstance(val[0], str): _MT = {} for value in val: try: k, v = value.replace('=', ':').split(":") _MT.update({k: float(v)}) except ValueError: logger.error( f"Unresolved string:{value},expect \'NAME:NUM\' or \'NAME=NUM\'" ) super(ItemStack, self).__init__(_MT) self.addItemFromDict(kwargs) self._check_value() def raiser(self, other, operation): raise TypeError( f"'{operation}' not supported between instances of '{self.__class__.__name__}'" f" and '{other.__class__.__name__}'") 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 _direct_add(self, name, quantity): self.update({name: self.get(name, 0) + quantity}) if self.get(name) == 0: self.pop(name) return self def addItems(self, droplist=None): if droplist is not None: for _ in droplist: self.addItem(_["name"], _["quantity"]) return self 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 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 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 addItemFromRawDictList(self, dumplist: list): for val in dumplist: self.addItemFromRawDict(val) return self def addItemFromRawDict(self, dumpdict: dict): if dumpdict.get('type') in ['FURN', 'CHAR', 'NONE', 'ET_STAGE']: logger.warning( f"cannot add type:{dumpdict.get('type')} into ItemStack") return self try: return self.addItem( getItemTag()['items'].get(dumpdict.get('id'))['name'], int(dumpdict.get('count'))) except: logger.warning( f"cannot add [T:{dumpdict.get('type')} I:{dumpdict.get('id')}] into ItemStack" ) return self def addItemFromDict(self, dictobj): for k, v in dictobj.items(): self.autoAddItem(k, v) return self def addItemFromCharCost(self, cost): self.addItem(self.__itemtag__[cost["id"]]['name'], cost['count']) return self # def addItemFromDropReco(self,reco_list): def addItemFromList_NameQuantity(self, li: list): for name, quantity in li: self.addItem(name, quantity) return self def registItem(self, drop_list, value=1): if isinstance(drop_list, (list, set)): for _id, name in drop_list: self.addItem(name, value) elif isinstance(drop_list, str): self.addItem(drop_list, value) return self def delItem(self, k): if self.get(k, None) is not None: return self.pop(k) return None def __contains__(self, item): if isinstance(item, (dict, list)): for _ in item: if _ not in self: return False return True if isinstance(item, str): if self.get(item, None) is not None: return True return False def formatItems(self, format_='%item%(%quantity%) ', skip_zero=True): format_ = format_.replace('%item%', '{item}').replace('%quantity%', '{quantity}') opt_ = '' for item, quantity in self.items(): if quantity == 0 and skip_zero: continue opt_ += format_.format(item=item, quantity=quantity) return opt_ def format_rich(self): _ = [] for k_name, v_quantity in self.items(): _.append(f"[yellow1]{k_name}[/]([blue]{v_quantity}[/])") return "Items{" + ' '.join(_) + '}' def __add__(self, other): if isinstance(other, ItemStack): that = self.copy() for k, v in other.items(): that.update({k: that.get(k, 0) + v}) return ItemStack(that) elif isinstance(other, DropItemStack): that = self.copy() for k, v in other.items(): for name, quantity in v: that.update({name: that.get(name, 0) + quantity}) return ItemStack(that) raise ValueError('other expected a ItemStack-Type') def __sub__(self, other): if isinstance(other, ItemStack): that = self.copy() for k, v in other.items(): if self.get(k, None) is None: continue val = self.get(k) - v if val > 0: that.setdefault(k, val) else: that.pop(k) return ItemStack(that) raise ValueError('other expected a ItemStack-Type') # def __eq__(self, other): # print('__eq__ function is proceeded!') # # def __ne__(self, other): # print('__nq__ function is proceeded!') def __gt__(self, other): # self > other called if not isinstance(other, (dict, int)): self.raiser(other, ">") for k, v in self.items(): if v <= other.get(k, 0): return False return True def __ge__(self, other): # self >= other called if not isinstance(other, (dict, int)): self.raiser(other, ">=") for k, v in self.items(): if v < other.get(k, 0): return False return True def __lt__(self, other): # self < other called if not isinstance(other, (dict, int)): self.raiser(other, "<") for k, v in self.items(): if v >= other.get(k, 0): return False return True def __le__(self, other): # self <= other called if not isinstance(other, (dict, int)): self.raiser(other, "<=") for k, v in self.items(): if v > other.get(k, 0): return False return True def __str__(self): if self: return super(ItemStack, self).__str__().replace('\'', '').replace(' ', '') else: return '{无掉落物}'