diff --git a/config/world_patrol/P02_YLL6/R03_BYTL_R01_GDJZ.yml b/config/world_patrol/P02_YLL6/R03_BYTL_R01_GDJZ.yml index 3285546d..ceb72989 100644 --- a/config/world_patrol/P02_YLL6/R03_BYTL_R01_GDJZ.yml +++ b/config/world_patrol/P02_YLL6/R03_BYTL_R01_GDJZ.yml @@ -14,7 +14,7 @@ route: - op: 'move' data: [693, 510] - op: 'move' - data: [670, 516] + data: [665, 516] - op: 'move' data: [662, 635] - op: 'patrol' diff --git a/config/world_patrol/P03_XZLF/R03_HXG_R02_ZCQMJ.yml b/config/world_patrol/P03_XZLF/R03_HXG_R02_ZCQMJ.yml index 5e3bd7fc..39a1b17e 100644 --- a/config/world_patrol/P03_XZLF/R03_HXG_R02_ZCQMJ.yml +++ b/config/world_patrol/P03_XZLF/R03_HXG_R02_ZCQMJ.yml @@ -1,7 +1,7 @@ planet: '仙舟罗浮' region: '廻星港' level: 1 -tp: '植船区-萌甲' +tp: '植船区萌甲' route: - op: 'move' data: [441, 489] diff --git a/config/world_patrol/P03_XZLF/R03_HXG_R03_ZCQMJ_2.yml b/config/world_patrol/P03_XZLF/R03_HXG_R03_ZCQMJ_2.yml index b8185bf0..72c6d586 100644 --- a/config/world_patrol/P03_XZLF/R03_HXG_R03_ZCQMJ_2.yml +++ b/config/world_patrol/P03_XZLF/R03_HXG_R03_ZCQMJ_2.yml @@ -1,7 +1,7 @@ planet: '仙舟罗浮' region: '廻星港' level: 1 -tp: '植船区-萌甲' +tp: '植船区萌甲' route: - op: 'move' data: [455, 488] diff --git a/config/world_patrol/P03_XZLF/R03_HXG_R04_ZCQMJ_3.yml b/config/world_patrol/P03_XZLF/R03_HXG_R04_ZCQMJ_3.yml index 5ffb07c1..28e560eb 100644 --- a/config/world_patrol/P03_XZLF/R03_HXG_R04_ZCQMJ_3.yml +++ b/config/world_patrol/P03_XZLF/R03_HXG_R04_ZCQMJ_3.yml @@ -1,7 +1,7 @@ planet: '仙舟罗浮' region: '廻星港' level: 1 -tp: '植船区-萌甲' +tp: '植船区萌甲' route: - op: 'move' data: [442, 488] diff --git a/src/gui/app.py b/src/gui/app.py index 8bbbc475..d5b46c96 100644 --- a/src/gui/app.py +++ b/src/gui/app.py @@ -7,7 +7,7 @@ def run_app(page: ft.Page): ctx = get_context() - page.title = gt('崩坏:星穹铁道 自动代理器') + ' v0.3.3' + page.title = gt('崩坏:星穹铁道 自动代理器') + ' v0.3.4' display_part = ft.Container(padding=20, content=world_patrol_view.get(page, ctx).component) diff --git a/src/sr/app/world_patrol.py b/src/sr/app/world_patrol.py index b86bd08d..bef97377 100644 --- a/src/sr/app/world_patrol.py +++ b/src/sr/app/world_patrol.py @@ -73,6 +73,9 @@ def file_path(self): return os.path.join(dir_path, '%s.yml' % self.raw_id) + def __str__(self): + return '%s_%s' % (self.planet.cn, self.raw_id) + class WorldPatrolRoute(ConfigHolder): @@ -132,8 +135,11 @@ def __init__(self, ctx: Context, restart: bool = False, route_id_list: List = No def init_app(self): self.route_list = load_all_route_id() if self.route_id_list is None else self.route_id_list log.info('共加载 %d 条线路', len(self.route_list)) - self.record = WorldPatrolRecord(os_utils.get_dt(), restart=self.restart) - log.info('之前已完成线路 %d 条', len(self.record.finished)) + try: + self.record = WorldPatrolRecord(os_utils.get_dt(), restart=self.restart) + log.info('之前已完成线路 %d 条', len(self.record.finished)) + except Exception: + log.info('读取运行记录失败 重新开始', exc_info=True) self.route_iterator = iter(self.route_list) @@ -144,23 +150,27 @@ def run(self) -> int: log.info('所有线路执行完毕') return Operation.SUCCESS - self.run_one_route(route_id) - self.first = False + if self.run_one_route(route_id): + self.first = False return Operation.WAIT - def run_one_route(self, route_id): + def run_one_route(self, route_id: WorldPatrolRouteId) -> bool: + """ + :param route_id: + :return: 是否执行成功当前线路 + """ route: WorldPatrolRoute = WorldPatrolRoute(route_id) log.info('准备执行线路 %s %s %s %s', route_id, route.tp.planet.cn, route.tp.region.cn, route.tp.cn) - if route_id in self.record.finished: - log.info('线路 %s 之前已执行 跳过', route_id) - return + if self.record is not None and route_id.display_name in self.record.finished: + log.info('线路 %s 之前已执行 跳过', route_id.display_name) + return False log.info('准备传送 %s %s %s', route.tp.planet.cn, route.tp.region.cn, route.tp.cn) op = Transport(self.ctx, route.tp, self.first) if not op.execute(): - log.error('传送失败 即将跳过本次路线 %s', route_id) - return + log.error('传送失败 即将跳过本次路线 %s', route_id.display_name) + return False else: log.info('传送完成 开始寻路') @@ -175,7 +185,7 @@ def run_one_route(self, route_id): next_route_item is None or next_route_item['op'] != 'move') if not result: log.error('寻路失败 即将跳过本次路线 %s', route_id) - return + return False current_pos = next_pos if next_lm_info is not None: @@ -186,12 +196,12 @@ def run_one_route(self, route_id): result = self.interact(route_item['data']) if not result: log.error('交互失败 即将跳过本次路线 %s', route_id) - return + return False elif route_item['op'] == 'wait': result = self.wait(route_item['data']) if not result: log.error('等待失败 即将跳过本次路线 %s', route_id) - return + return False elif route_item['op'] == 'update_pos': next_pos = route_item['data'] if len(next_pos) > 2: @@ -200,17 +210,18 @@ def run_one_route(self, route_id): current_pos = next_pos[:2] else: log.error('错误的锄大地指令 %s 即将跳过本次路线 %s', route_item['op'], route_id) - return + return False self.save_record(route_id) + return True - def save_record(self, route_id): + def save_record(self, route_id: WorldPatrolRouteId): """ 保存当天运行记录 :param route_id: 路线ID :return: """ - self.record.finished.append(route_id) + self.record.finished.append(route_id.display_name) self.record.save() def move(self, p, lm_info: LargeMapInfo, current_pos, stop_afterwards: bool): diff --git a/src/sr/constants/map.py b/src/sr/constants/map.py index 7e5697fd..de19fae7 100644 --- a/src/sr/constants/map.py +++ b/src/sr/constants/map.py @@ -133,8 +133,8 @@ def another_floor(self) -> bool: P02_R08_L2 = Region(8, "JWQSYC", "旧武器试验场", P02, level=2) P02_R09 = Region(9, "PYZ", "磐岩镇", P02) P02_R10 = Region(10, "DKQ", "大矿区", P02) -P02_R11_L1 = Region(11, "MDZ", "铆钉镇", P02, level=1) -P02_R11_L2 = Region(11, "MDZ", "铆钉镇", P02, level=2) +P02_R11_L1 = Region(11, "MDZ", "铆钉镇", P02, level=1, ocr_str='钉镇') +P02_R11_L2 = Region(11, "MDZ", "铆钉镇", P02, level=2, ocr_str='钉镇') P02_R12_L1 = Region(12, "JXJL", "机械聚落", P02, level=1) P02_R12_L2 = Region(12, "JXJL", "机械聚落", P02, level=2) @@ -252,7 +252,7 @@ def __str__(self): P02_R02_SP01 = TransportPoint('CP', '长坡', P02_R02, 'mm_tp_03', (1035, 319)) P02_R02_SP02 = TransportPoint('ZLD', '着陆点', P02_R02, 'mm_tp_03', (1283, 367)) P02_R02_SP03 = TransportPoint('XLZL', '巡猎之蕾', P02_R02, 'mm_tp_07', (946, 244)) -P02_R02_SP04 = TransportPoint('HYZL', '回忆之蕾', P02_R02, 'mm_tp_08', (1098, 391)) +P02_R02_SP04 = TransportPoint('HYZL', '回忆之蕾', P02_R02, 'mm_tp_08', (1098, 391), ocr_str='回忆') P02_R02_SP05 = TransportPoint('XZQ', '行政区', P02_R02, 'mm_sp_02', (444, 109)) P02_R02_SP06 = TransportPoint('LK', '玲可', P02_R02, 'mm_sp_03', (1032, 342)) @@ -275,7 +275,7 @@ def __str__(self): P02_R04_SP08 = TransportPoint('CXHL', '残响回廊', P02_R04, 'mm_sp_02', (314, 589)) # 雅利洛 - 残响回廊 -P02_R05_SP01 = TransportPoint('ZCLY', '筑城领域', P02_R05, 'mm_tp_03', (770, 442)) +P02_R05_SP01 = TransportPoint('ZCLY', '筑城领域', P02_R05, 'mm_tp_03', (770, 442), ocr_str='筑城') P02_R05_SP02 = TransportPoint('WRGC', '污染广场', P02_R05, 'mm_tp_03', (381, 655)) P02_R05_SP03 = TransportPoint('ZZZHS', '作战指挥室', P02_R05, 'mm_tp_03', (495, 856), ocr_str='作战') P02_R05_SP04 = TransportPoint('GZCQX', '古战场前线', P02_R05, 'mm_tp_03', (570, 1243)) @@ -317,7 +317,7 @@ def __str__(self): # 雅利洛 - 大矿区 P02_R10_SP01 = TransportPoint('RK', '入口', P02_R10, 'mm_tp_03', (333, 166)) P02_R10_SP02 = TransportPoint('LLZBNS', '流浪者避难所', P02_R10, 'mm_tp_03', (778, 349)) -P02_R10_SP03 = TransportPoint('FKD', '俯瞰点', P02_R10, 'mm_tp_03', (565, 641)) +P02_R10_SP03 = TransportPoint('FKD', '俯瞰点', P02_R10, 'mm_tp_03', (565, 641), ocr_str='俯') P02_R10_SP04 = TransportPoint('ZKD', '主矿道', P02_R10, 'mm_tp_03', (530, 757)) P02_R10_SP05 = TransportPoint('FMZX', '锋芒之形', P02_R10, 'mm_tp_06', (561, 536)) P02_R10_SP06 = TransportPoint('FZZX', '燔灼之形', P02_R10, 'mm_tp_06', (836, 630)) @@ -442,7 +442,7 @@ def __str__(self): # 仙舟罗浮 - 鳞渊境 P03_R09_SP01 = TransportPoint('GXSC', '宫墟深处', P03_R09, 'mm_tp_03', (891, 425), ocr_str='深处') -P03_R09_SP02 = TransportPoint('GHGX', '古海宫墟', P03_R09, 'mm_tp_03', (1113, 425)) +P03_R09_SP02 = TransportPoint('GHGX', '古海宫墟', P03_R09, 'mm_tp_03', (1113, 425), ocr_str='古海') P03_R09_SP03 = TransportPoint('XLDYD', '显龙大雩殿', P03_R09, 'mm_tp_03', (1599, 444)) P03_R09_SP04 = TransportPoint('NSZX', '孽兽之形', P03_R09, 'mm_tp_06', (917, 169), ocr_str='兽之形') P03_R09_SP05 = TransportPoint('DDS', '丹鼎司', P03_R09, 'mm_sp_02', (1891, 391)) diff --git a/src/sr/control/__init__.py b/src/sr/control/__init__.py index efac34a4..ad1ab10c 100644 --- a/src/sr/control/__init__.py +++ b/src/sr/control/__init__.py @@ -9,11 +9,10 @@ class GameController: def __init__(self, ocr: OcrMatcher): - self.ocr: OcrMatcher = None + self.ocr: OcrMatcher = ocr self.turn_dx: float = None self.walk_speed: float = None self.is_moving: bool = False - pass def init(self): pass diff --git a/src/sr/image/cnocr_matcher.py b/src/sr/image/cnocr_matcher.py index 178be093..e20ae4ba 100644 --- a/src/sr/image/cnocr_matcher.py +++ b/src/sr/image/cnocr_matcher.py @@ -23,11 +23,10 @@ def __init__(self, except Exception: log.error('OCR模型加载出错', exc_info=True) - def ocr_for_single_line(self, image: MatLike, threshold: float = 0.5) -> str: + def ocr_for_single_line(self, image: MatLike, threshold: float = None) -> str: result = self.ocr.ocr_for_single_line(image) log.debug('OCR结果 %s', result) - if result['score'] > threshold: - return result['text'] + return result['text'] if threshold is None or result['score'] >= threshold else None def run_ocr(self, image: MatLike, threshold: float = 0.5) -> dict: """ diff --git a/src/sr/image/sceenshot/large_map.py b/src/sr/image/sceenshot/large_map.py index f95c948d..73c7af02 100644 --- a/src/sr/image/sceenshot/large_map.py +++ b/src/sr/image/sceenshot/large_map.py @@ -11,7 +11,7 @@ from basic.log_utils import log from sr import constants from sr.config.game_config import get_game_config -from sr.constants.map import Planet, Region, region_with_another_floor +from sr.constants.map import Planet, Region, region_with_another_floor, PLANET_LIST from sr.image import OcrMatcher, TemplateImage, ImageMatcher, get_large_map_dir_path from sr.image.image_holder import ImageHolder from sr.image.sceenshot import LargeMapInfo @@ -37,15 +37,12 @@ def get_planet(screen: MatLike, ocr: OcrMatcher) -> Planet: upper_color = np.array([255, 255, 255], dtype=np.uint8) white_part = cv2.inRange(planet_name_part, lower_color, upper_color) # cv2_utils.show_image(white_part, win_name='white_part') - result = ocr.run_ocr(planet_name_part, threshold=0.4) - log.debug('屏幕左上方获取星球结果 %s', result.keys()) - for word in result.keys(): - if word.find(gt(constants.map.P01.ocr_str)) > -1: - return constants.map.P01 - if word.find(gt(constants.map.P02.ocr_str)) > -1: - return constants.map.P02 - if word.find(gt(constants.map.P03.ocr_str)) > -1: - return constants.map.P03 + planet_name_str: str = ocr.ocr_for_single_line(white_part) + log.debug('屏幕左上方获取星球结果 %s', planet_name_str) + if planet_name_str is not None: + for p in PLANET_LIST: + if planet_name_str.find(gt(p.ocr_str)) != -1: + return p return None diff --git a/src/sr/operation/unit/choose_planet.py b/src/sr/operation/unit/choose_planet.py index 4de54c66..04a81f1a 100644 --- a/src/sr/operation/unit/choose_planet.py +++ b/src/sr/operation/unit/choose_planet.py @@ -64,7 +64,8 @@ def choose_planet(self, screen) -> bool: if len(km) == 0: return False for v in km.values(): - x, y = v.max.cx, v.max.cy - 100 - self.ctx.controller.click((x, y)) - self.ctx.controller.click((x, y), press_time=1.5) + x, y = v.max.cx, v.max.cy + self.ctx.controller.click((x, y - 100)) + time.sleep(0.1) + self.ctx.controller.click((x, y - 110), press_time=1) return True diff --git a/src/sr/operation/unit/choose_transport_point.py b/src/sr/operation/unit/choose_transport_point.py index 540b281b..ea55ea11 100644 --- a/src/sr/operation/unit/choose_transport_point.py +++ b/src/sr/operation/unit/choose_transport_point.py @@ -88,9 +88,10 @@ def check_and_click_transport(self, screen: MatLike): upper_color = np.array([255, 255, 255], dtype=np.uint8) gold_part = cv2.inRange(tp_name_part, lower_color, upper_color) # gold_part = cv2_utils.dilate(gold_part, 1) - tp_name_ocr = self.ctx.ocr.match_words(gold_part, [gt(self.tp.ocr_str)], threshold=0.39) + tp_name_str: str = self.ctx.ocr.ocr_for_single_line(gold_part) + log.info('当前选择传送点名称 %s', tp_name_str) # cv2_utils.show_image(gold_part, win_name='gold_part') - if len(tp_name_ocr) > 0: + if tp_name_str is not None and tp_name_str.find(gt(self.tp.ocr_str)) != -1: # 点击传送 tx = large_map.TP_BTN_RECT[0] ty = large_map.TP_BTN_RECT[1] diff --git a/src/sr/operation/unit/enter_auto_fight.py b/src/sr/operation/unit/enter_auto_fight.py index 1b7e011a..321e3815 100644 --- a/src/sr/operation/unit/enter_auto_fight.py +++ b/src/sr/operation/unit/enter_auto_fight.py @@ -36,7 +36,8 @@ def run(self) -> int: eaf = EnableAutoFight(self.ctx) eaf.execute() time.sleep(0.5) # 战斗部分 - self.last_alert_time = time.time() + self.last_in_battle_time = time.time() + self.last_alert_time = self.last_in_battle_time return Operation.WAIT mm = mini_map.cut_mini_map(screen) diff --git a/src/sr/win.py b/src/sr/win.py index f52bc989..4794d682 100644 --- a/src/sr/win.py +++ b/src/sr/win.py @@ -60,7 +60,7 @@ def get_win_rect(self): ctypes.windll.user32.GetClientRect(self.hWnd, ctypes.byref(client_rect)) left_top_pos = ctypes.wintypes.POINT(client_rect.left, client_rect.top) ctypes.windll.user32.ClientToScreen(self.hWnd, ctypes.byref(left_top_pos)) - return WinRect(left_top_pos.x.value, left_top_pos.y.value, client_rect.right.value, client_rect.bottom.value) + return WinRect(left_top_pos.x, left_top_pos.y, client_rect.right, client_rect.bottom) def game_pos(self, pos: tuple, inner: bool = True, rect: WinRect = None) -> tuple: """