From f395b8fd0b8f6e8453e0607f1b1ecf17ef01b65e Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sat, 15 Apr 2023 22:38:23 -0700 Subject: [PATCH 01/49] =?UTF-8?q?fix:=20=E9=93=85=E8=B8=9D=20=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/data/ocr.json | 3 ++- arknights_mower/utils/character_recognize.py | 2 ++ arknights_mower/utils/operators.py | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arknights_mower/data/ocr.json b/arknights_mower/data/ocr.json index 7d68cb6ca..e94b42160 100644 --- a/arknights_mower/data/ocr.json +++ b/arknights_mower/data/ocr.json @@ -28,5 +28,6 @@ "Castle3": "Castle-3", "Lancet2": "Lancet-2", "THRMEX": "THRM-EX", - "U-Officia": "U-Official" + "U-Officia": "U-Official", + "铅跟": "铅踝" } \ No newline at end of file diff --git a/arknights_mower/utils/character_recognize.py b/arknights_mower/utils/character_recognize.py index dd2adab26..77ed50506 100644 --- a/arknights_mower/utils/character_recognize.py +++ b/arknights_mower/utils/character_recognize.py @@ -228,6 +228,8 @@ def agent_name(__img, height,reverse = False, draw: bool = False): try: if len(ocr) > 0 and ocr[0][1] in agent_list and ocr[0][1] not in ['砾', '陈']: name = ocr[0][1] + elif ocr[0][1] in ocr_error.keys(): + name = ocr_error[ocr[0][1]] else: res = sift_recog(__img, height, draw, reverse) if (res is not None) and res in agent_list: diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 0be832d24..3030b0d5e 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -28,6 +28,10 @@ def update_detail(self,name, mood, current_room, current_index,update_time = Fal if agent.current_room.startswith('dorm') and not current_room.startswith('dorm') and agent.is_high(): self.refresh_dorm_time(agent.current_room,agent.current_index,{'agent':''}) agent.time_stamp = None + if self.get_dorm_by_name(name)[0] is not None and not current_room.startswith('dorm') and agent.is_high(): + _dorm = self.get_dorm_by_name(name)[1] + _dorm.name = '' + _dorm.time = None agent.current_room = current_room agent.current_index = current_index agent.mood = mood From 02953dc5ea40287f5ca4db532a53bc280436595f Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sun, 16 Apr 2023 17:11:25 -0700 Subject: [PATCH 02/49] =?UTF-8?q?fix:=20=E9=93=85=E8=B8=9D=20=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/utils/character_recognize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arknights_mower/utils/character_recognize.py b/arknights_mower/utils/character_recognize.py index 77ed50506..e9150ae0c 100644 --- a/arknights_mower/utils/character_recognize.py +++ b/arknights_mower/utils/character_recognize.py @@ -228,7 +228,7 @@ def agent_name(__img, height,reverse = False, draw: bool = False): try: if len(ocr) > 0 and ocr[0][1] in agent_list and ocr[0][1] not in ['砾', '陈']: name = ocr[0][1] - elif ocr[0][1] in ocr_error.keys(): + elif len(ocr) > 0 and ocr[0][1] in ocr_error.keys(): name = ocr_error[ocr[0][1]] else: res = sift_recog(__img, height, draw, reverse) From 031f6f088a39381b16848f02af2bdd7bbe4462e0 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sun, 16 Apr 2023 21:07:07 -0700 Subject: [PATCH 03/49] =?UTF-8?q?fix:=E6=97=A0=E4=BA=BA=E6=9C=BA=E4=B8=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 31621d01f..394ff707c 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -344,8 +344,6 @@ def infra_main(self): if self.drone_room is not None: if self.drone_time is None or self.drone_time < datetime.now()- timedelta(hours=self.drone_execution_gap): self.drone(self.drone_room) - logger.info(f"记录本次无人机使用时间为:{datetime.now()}") - self.drone_time = datetime.now() if self.party_time is None: self.clue() if notification is None: @@ -536,7 +534,7 @@ def plan_solver(self): if op.mood > int((op.upper_limit - op.lower_limit) * self.resting_treshhold + op.lower_limit): continue if op.name in self.op_data.exhaust_agent: - if op.mood <= 2: + if op.mood <= 0: if next((e for e in self.tasks if 'type' in e.keys() and op.name in e['type']), None) is None: self.enter_room(op.current_room) @@ -746,7 +744,7 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) return __str except Exception as e: logger.exception(e) - return limit + return limit+1 def read_time(self, cord, upperlimit, error_count=0): # 刷新图片 @@ -1064,9 +1062,9 @@ def drone(self, room: str, not_customize=False, not_return=False): if accelerate: drone_count = self.read_screen(self.recog.img, type='drone_mood', cord=( int(self.recog.w * 1150 / 1920), int(self.recog.h * 35 / 1080), int(self.recog.w * 1295 / 1920), - int(self.recog.h * 72 / 1080)), limit=201) + int(self.recog.h * 72 / 1080)), limit=200) logger.info(f'当前无人机数量为:{drone_count}') - if drone_count< self.drone_count_limit or drone_count == 201: + if drone_count < self.drone_count_limit or drone_count > 200: logger.info(f"无人机数量小于{self.drone_count_limit}->停止") return logger.info('制造站加速') @@ -1082,6 +1080,8 @@ def drone(self, room: str, not_customize=False, not_return=False): else: self.tap_element('all_in') self.tap(accelerate, y_rate=1) + logger.info(f"记录本次无人机使用时间为:{datetime.now()}") + self.drone_time = datetime.now() else: accelerate = self.find('bill_accelerate') while accelerate: @@ -1096,7 +1096,7 @@ def drone(self, room: str, not_customize=False, not_return=False): if not_customize: drone_count = self.read_screen(self.recog.img, type='drone_mood', cord=( int(self.recog.w * 1150 / 1920), int(self.recog.h * 35 / 1080), int(self.recog.w * 1295 / 1920), - int(self.recog.h * 72 / 1080)), limit=201) + int(self.recog.h * 72 / 1080)), limit=200) logger.info(f'当前无人机数量为:{drone_count}') self.recog.update() self.recog.save_screencap('run_order') From e953084a818d343267c57e1ac07bd6fd85daf737 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 17 Apr 2023 09:39:29 -0700 Subject: [PATCH 04/49] =?UTF-8?q?revert:=E6=97=A0=E4=BA=BA=E6=9C=BA?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E8=AE=B0=E5=BD=95=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 394ff707c..2da0f0504 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -344,6 +344,8 @@ def infra_main(self): if self.drone_room is not None: if self.drone_time is None or self.drone_time < datetime.now()- timedelta(hours=self.drone_execution_gap): self.drone(self.drone_room) + logger.info(f"记录本次无人机使用时间为:{datetime.now()}") + self.drone_time = datetime.now() if self.party_time is None: self.clue() if notification is None: @@ -1080,8 +1082,6 @@ def drone(self, room: str, not_customize=False, not_return=False): else: self.tap_element('all_in') self.tap(accelerate, y_rate=1) - logger.info(f"记录本次无人机使用时间为:{datetime.now()}") - self.drone_time = datetime.now() else: accelerate = self.find('bill_accelerate') while accelerate: From 1332c480ab8524bc40f72d13eb5e304e03566a18 Mon Sep 17 00:00:00 2001 From: Ksnow <1048879349@qq.com> Date: Tue, 18 Apr 2023 01:15:18 +0800 Subject: [PATCH 05/49] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=90=AF=E7=94=A8=E7=BA=BF=E7=B4=A2=E6=94=B6=E9=9B=86=20fix:?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=BB=E5=8F=96=E6=97=A0=E4=BA=BA=E6=9C=BA?= =?UTF-8?q?=E4=B8=80=E7=9B=B4=E5=BE=AA=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 1 + arknights_mower/solvers/base_schedule.py | 9 ++++++--- menu.py | 8 +++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 7fc5d3b4c..e518cf914 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -61,6 +61,7 @@ def inialize(tasks, scheduler=None): base_scheduler.max_resting_count = conf['max_resting_count'] base_scheduler.drone_count_limit = conf['drone_count_limit'] base_scheduler.tasks = tasks + base_scheduler.enable_party = conf['enable_party'] == 1 # 是否使用线索 # 读取心情开关,有菲亚梅塔或者希望全自动换班得设置为 true base_scheduler.read_mood = conf['run_mode'] == 1 # 干员宿舍回复阈值 diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 394ff707c..66702894f 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -55,6 +55,7 @@ def __init__(self, device: Device = None, recog: Recognizer = None) -> None: self.party_time = None self.drone_time = None self.run_order_delay=10 + self.enable_party = True def run(self) -> None: """ @@ -344,7 +345,9 @@ def infra_main(self): if self.drone_room is not None: if self.drone_time is None or self.drone_time < datetime.now()- timedelta(hours=self.drone_execution_gap): self.drone(self.drone_room) - if self.party_time is None: + logger.info(f"记录本次无人机使用时间为:{datetime.now()}") + self.drone_time = datetime.now() + if self.party_time is None and self.enable_party : self.clue() if notification is None: self.sleep(1) @@ -1080,8 +1083,8 @@ def drone(self, room: str, not_customize=False, not_return=False): else: self.tap_element('all_in') self.tap(accelerate, y_rate=1) - logger.info(f"记录本次无人机使用时间为:{datetime.now()}") - self.drone_time = datetime.now() + # logger.info(f"记录本次无人机使用时间为:{datetime.now()}") + # self.drone_time = datetime.now() else: accelerate = self.find('bill_accelerate') while accelerate: diff --git a/menu.py b/menu.py index 7cf49559b..d23815af9 100644 --- a/menu.py +++ b/menu.py @@ -57,6 +57,7 @@ def load_conf(): conf['drone_count_limit'] = conf['drone_count_limit'] if 'drone_count_limit' in conf.keys() else 92 # 无人机阈值 conf['run_order_delay'] = conf['run_order_delay'] if 'run_order_delay' in conf.keys() else 10 # 跑单提前10分钟运行 conf['drone_room'] = conf['drone_room'] if 'drone_room' in conf.keys() else '' # 无人机使用房间 + conf['enable_party'] = conf['enable_party'] if 'enable_party' in conf.keys() else 1 # 是否启用收取线索 def write_conf(): @@ -186,7 +187,11 @@ def menu(): key='radio_ling_xi_2', enable_events=True) ling_xi_3 = sg.Radio('均衡模式', 'ling_xi', default=conf['ling_xi'] == 3, key='radio_ling_xi_3', enable_events=True) - + enable_party_title = sg.Text('线索收集:', size=25) + enable_party_1 = sg.Radio('启用', 'enable_party', default=conf['enable_party'] == 1, + key='radio_enable_party_1', enable_events=True) + enable_party_0 = sg.Radio('禁用', 'enable_party', default=conf['enable_party'] == 0, + key='radio_enable_party_0', enable_events=True) max_resting_count_title = sg.Text('最大组人数:', size=25, key='max_resting_count_title') max_resting_count = sg.InputText(conf['max_resting_count'], size=5, key='int_max_resting_count', enable_events=True) @@ -250,6 +255,7 @@ def menu(): plan_tab = sg.Tab(' 排班表 ', [[left_area, central_area, right_area], [setting_area]], element_justification="center") setting_tab = sg.Tab(' 高级设置 ', [[run_mode_title, run_mode_1, run_mode_2], [ling_xi_title, ling_xi_1, ling_xi_2, ling_xi_3], + [enable_party_title,enable_party_1,enable_party_0], [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title, run_order_delay], [drone_room_title, drone_room, sg.Text('', size=7), drone_count_limit_title, From 8a560360bfcc75774843eb680978286c51090ed4 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 17 Apr 2023 21:55:30 -0700 Subject: [PATCH 06/49] =?UTF-8?q?#159=20=E4=BC=98=E5=85=88=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=A5=BD=E5=8F=8B=E7=BA=BF=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/data/ocr.json | 1 + arknights_mower/resources/clue_unselect.png | Bin 0 -> 9245 bytes arknights_mower/solvers/base_schedule.py | 77 +++++++++++++------- 3 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 arknights_mower/resources/clue_unselect.png diff --git a/arknights_mower/data/ocr.json b/arknights_mower/data/ocr.json index e94b42160..2fde70d58 100644 --- a/arknights_mower/data/ocr.json +++ b/arknights_mower/data/ocr.json @@ -29,5 +29,6 @@ "Lancet2": "Lancet-2", "THRMEX": "THRM-EX", "U-Officia": "U-Official", + "UOfficial": "U-Official", "铅跟": "铅踝" } \ No newline at end of file diff --git a/arknights_mower/resources/clue_unselect.png b/arknights_mower/resources/clue_unselect.png new file mode 100644 index 0000000000000000000000000000000000000000..415ab1c3e13aed883da5270eb8d77d5c4bdd1dba GIT binary patch literal 9245 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 literal 0 HcmV?d00001 diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 2da0f0504..78c3c00ed 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -791,6 +791,9 @@ def todo_list(self) -> None: self.tap((self.recog.w * 0.05, self.recog.h * 0.95)) self.todo_task = True + def share_clue(self): + pass + def clue(self) -> None: # 一些识别时会用到的参数 global x1, x2, x3, x4, y0, y1, y2 @@ -808,6 +811,13 @@ def clue(self) -> None: # 如果是线索交流的报告则返回 self.find('clue_summary') and self.back() + # 关闭掉房间总览 + error_count = 0 + while self.find('clue_func') is None: + if error_count > 5: + raise Exception('未成功进入线索详情界面') + self.tap((self.recog.w * 0.1, self.recog.h * 0.9), interval=3) + error_count += 1 # 识别右侧按钮 (x0, y0), (x1, y1) = self.find('clue_func', strict=True) @@ -819,12 +829,25 @@ def clue(self) -> None: logger.info('领取会客室线索') self.tap(((x0 + x1) // 2, (y0 * 5 - y1) // 4), interval=3) obtain = self.find('clue_obtain') + clue_inventory_full = False + if self.find('clue_full') is not None: + clue_inventory_full = True if obtain is not None and self.get_color(self.get_pos(obtain, 0.25, 0.5))[0] < 20: self.tap(obtain, interval=2) if self.find('clue_full') is not None: self.back() else: self.back() + if not clue_inventory_full: + pass + # self.back() + # self.tap((x1, y1), interval=0.5) + # self.recog_bar() + # # 获得和线索视图相关的数据 + # self.recog_view(only_y2=False) + # for i in range(1, 8): + # # 切换阵营 + # self.tap(self.switch_camp(i)) logger.info('放置线索') clue_unlock = self.find('clue_unlock') @@ -845,51 +868,49 @@ def clue(self) -> None: get_all_clue = True for i in range(1, 8): # 切换阵营 - self.tap(self.switch_camp(i), rebuild=False) - - # 清空界面内被选中的线索 - self.clear_clue_mask() - - # 获得和线索视图有关的数据 - self.recog_view() - - # 检测该阵营线索数量为 0 - if len(self.ori_clue()) == 0: + self.tap(self.switch_camp(i)) + if self.find('clue_notfound') is not None: logger.info(f'无线索 {i}') get_all_clue = False break - - # 检测是否拥有全部线索 - if get_all_clue: - for i in range(1, 8): - # 切换阵营 - self.tap(self.switch_camp(i), rebuild=False) - - # 获得和线索视图有关的数据 - self.recog_view() - - # 放置线索 - logger.info(f'放置线索 {i}') - self.tap(((x1 + x2) // 2, y1 + 3), rebuild=False) - - # 返回线索主界面 - self.tap((self.recog.w * 0.05, self.recog.h * 0.95), interval=3, rebuild=False) + if self.find('clue_unselect') is not None: + logger.debug('检验到线索已放置') + continue + # 获得和线索视图有关的数据 + self.recog_view() + ori_results = self.ori_clue() + last_ori = ori_results[len(ori_results) - 1] + if len(ori_results) == 3: + # 下滑选择最后一个 优先赠送线索 + for swiptimes in range(1,3): + self.swipe((self.recog.w * 0.8, self.recog.h * 0.8), (0, -self.recog.h * 0.4),rebuild=False) + self.recog.update() + logger.info(f"放置线索{i}") + self.place_clue(last_ori) # 线索交流开启 if clue_unlock is not None and get_all_clue: self.tap(clue_unlock) self.party_time = datetime.now() + timedelta(days=1) - logger.info("为期一天的趴体开始") + logger.info("为期一天的impart开始") elif clue_unlock is None: # 记录趴体时间 self.back(interval=2) self.party_time = self.double_read_time((1765, 422, 1920, 515)) - logger.info(f"趴体结束时间为: {self.party_time}") + logger.info(f"impart结束时间为: {self.party_time}") else: self.back(interval=2) logger.info('返回基建主界面') self.back(interval=2) + def place_clue(self,last_ori): + error_count =0 + while self.find('clue_unselect') is None: + if error_count > 3: + raise Exception('未成功放置线索') + self.tap(((last_ori[0][0] + last_ori[2][0]) / 2, (last_ori[0][1] + last_ori[2][1]) / 2)) + error_count += 1 + def switch_camp(self, id: int) -> tuple[int, int]: """ 切换阵营 """ x = ((id + 0.5) * x2 + (8 - id - 0.5) * x1) // 8 From d6ce7a15b87ba7d4f7e8807a88dc9ffea77fb23b Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 17 Apr 2023 23:10:54 -0700 Subject: [PATCH 07/49] =?UTF-8?q?improvement:=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E5=8C=B9=E9=85=8D=E8=AF=BB=E5=8F=96=E6=97=B6?= =?UTF-8?q?=E9=97=B4+=E6=97=A0=E4=BA=BA=E6=9C=BA=20credit:=20E=E4=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/resources/clue_notfound.png | Bin 0 -> 3528 bytes arknights_mower/resources/drone_count/0.png | Bin 0 -> 1194 bytes arknights_mower/resources/drone_count/1.png | Bin 0 -> 1089 bytes arknights_mower/resources/drone_count/2.png | Bin 0 -> 809 bytes arknights_mower/resources/drone_count/3.png | Bin 0 -> 847 bytes arknights_mower/resources/drone_count/4.png | Bin 0 -> 808 bytes arknights_mower/resources/drone_count/5.png | Bin 0 -> 637 bytes arknights_mower/resources/drone_count/6.png | Bin 0 -> 841 bytes arknights_mower/resources/drone_count/7.png | Bin 0 -> 703 bytes arknights_mower/resources/drone_count/8.png | Bin 0 -> 1057 bytes arknights_mower/resources/drone_count/9.png | Bin 0 -> 855 bytes arknights_mower/resources/orders_time/0.png | Bin 0 -> 1009 bytes arknights_mower/resources/orders_time/1.png | Bin 0 -> 822 bytes arknights_mower/resources/orders_time/2.png | Bin 0 -> 861 bytes arknights_mower/resources/orders_time/3.png | Bin 0 -> 885 bytes arknights_mower/resources/orders_time/4.png | Bin 0 -> 905 bytes arknights_mower/resources/orders_time/5.png | Bin 0 -> 680 bytes arknights_mower/resources/orders_time/6.png | Bin 0 -> 731 bytes arknights_mower/resources/orders_time/7.png | Bin 0 -> 638 bytes arknights_mower/resources/orders_time/8.png | Bin 0 -> 976 bytes arknights_mower/resources/orders_time/9.png | Bin 0 -> 950 bytes arknights_mower/solvers/base_schedule.py | 31 ++++---- arknights_mower/utils/digit_reader.py | 74 ++++++++++++++++++++ 23 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 arknights_mower/resources/clue_notfound.png create mode 100644 arknights_mower/resources/drone_count/0.png create mode 100644 arknights_mower/resources/drone_count/1.png create mode 100644 arknights_mower/resources/drone_count/2.png create mode 100644 arknights_mower/resources/drone_count/3.png create mode 100644 arknights_mower/resources/drone_count/4.png create mode 100644 arknights_mower/resources/drone_count/5.png create mode 100644 arknights_mower/resources/drone_count/6.png create mode 100644 arknights_mower/resources/drone_count/7.png create mode 100644 arknights_mower/resources/drone_count/8.png create mode 100644 arknights_mower/resources/drone_count/9.png create mode 100644 arknights_mower/resources/orders_time/0.png create mode 100644 arknights_mower/resources/orders_time/1.png create mode 100644 arknights_mower/resources/orders_time/2.png create mode 100644 arknights_mower/resources/orders_time/3.png create mode 100644 arknights_mower/resources/orders_time/4.png create mode 100644 arknights_mower/resources/orders_time/5.png create mode 100644 arknights_mower/resources/orders_time/6.png create mode 100644 arknights_mower/resources/orders_time/7.png create mode 100644 arknights_mower/resources/orders_time/8.png create mode 100644 arknights_mower/resources/orders_time/9.png create mode 100644 arknights_mower/utils/digit_reader.py diff --git a/arknights_mower/resources/clue_notfound.png b/arknights_mower/resources/clue_notfound.png new file mode 100644 index 0000000000000000000000000000000000000000..b933994dd743613bcbaaa4809644838006d7eb77 GIT binary patch literal 3528 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 PvH}wP&^g5ksK zGd=Ux^!6CEYkqNHDShRy?xG~1bNVZbpD|bJ<>K0=dtVsW=@(up)!nu`OkZm{`=om} zltm(%rs-e1C&JuXP|DW#Wxq6=hJH0cFut+7MMGCuDD*zi}&yIv$9S-|12ylEN@ryp;kU? z%l7TxzkM?^Hy7_dnq&6+!9nK2-`{fAmPSY4zP>*G^2;w*u3R~FitEaaoyE@`t^%!L zeDM7I{Kt{ipeR2-|9rdJs=B&+5|8Ixj?!K_BT_(6 z$?AEJ;kBp;eG#s^yGmEDU%x&^Z~5hyzrVkix2XuoUOOcT$u;_4zkUUV$;ODB|Ns78 zzI-`3IhmWAJIHJ8)}XGLtb&S*iqA^8tKk4L?#qRy5o*IRC zYHq#erI{w?($aCxGP!4~7=u~4HO28njard zoH%iFb9(X4J1<_m=oZ)4n#zTt@K#$}+w1G=@9!v77T`!Rni-pmZ_Q9zkh#!?_U+Pk_D6yt*opbef)88vHQ%(J3EWn1*4;) z7!pcLORK7?YHI$Ro~|E|e0iDg+O=z$nVFxToBO%eexgSQP}qI(#d-7Q1!z2(Q~l$^ z!^_M4Ywx#9_4f9LuaA5C>Qz*9boJ+FzFJd-<~=txH-{(&23U;V^z+X_>H9+?GyAn` z*W&iq&GlOP?AbG5=4KG!YhQfv#nEnY=Y;|}YeKa4R(;i)>v#U_S;mGBHvFrAnLmdKI;Vst0E**K7ytkO literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/1.png b/arknights_mower/resources/drone_count/1.png new file mode 100644 index 0000000000000000000000000000000000000000..a85e6f058247d43a3e947e793685becb99443230 GIT binary patch literal 1089 zcmeAS@N?(olHy`uVBq!ia0vp^B0wy|!2~4V?cgwHU|`|!ba4!^5G*}-K3h0bg8jq$ zay5G&&ZO>+>21>%E#4rOGpX{Zx2B&|;p5Z*zcmLMh$k`Su%HS#D=hvqnGb1)KGBPG&hk^C)mzS5@+tr=< zns2$lqWNrEbSNW>0OtXmnW5cXv3DxpC29Vp4;4P&&Vp0UXZ%9wSLN> zpxkBKHf;Fu<73+HyX&r}hdjKqZflu^3=@~exrEiJE@~>NN|U^IUw!xe_t`LG4kp2s zVcO^3MrH5)uEKCsvgh{pO`dL>!dBn?@%C7AJO8z7VeN+(AN-e4miO(}))PBpv)6u~ z#{zUw;q8>kJv@5x`}W*@|9{`ckFT$)l$Cs9R z-``*V|JT>-#TP4neR;XJ`um(>pfX!epJbWiN=~1?eAyDTaze;e1&(LWpU=0cy!5tg zE>yu{LpK+%rI#vf)?I(SeEIUoX;V)>{rU4}-TwQiY7QBQ2!^U!&h!B)e)Q-O(4X6H zm!69R1%qMlF$qD=CI^>*6Q6B(4liB0G;aO&ef!?c*?g_)J%LU&^;`ZJNv^3$jA260A`RcmDxNTBgIpDGfr(*Kpvcn9St^~y=b~QkRqxC+Io83! z6~*9S)V0XOcd|+$k^>waxfwj%0;ep?oTPHj5)|wz%PvYND`{jfGMv=tx@6)z>4;_e z+OPK}A2E?ic41-FWl)fG4V<;ibCSjLHCyjhPnzMD+|#jO!77H3sVO3^nX}Y9AE7vN z6;nVc*g>~mmH-`k>+oUcNi&XF^nJE*cMSD>R_O&}l=4OF~jiu$v5G|EZQC73rzM-NMi=UrkRG9g^ za$4%?)2E}OqqpbZulxGy>gVU@_kLeBD>YJpH6{S-o6dh5@pEQ8s#XkV8ga;WzWye-MQ29&-9NKe;yz22RZ!T fpGu(De{gpPSbmpVQfLY+8W=oX{an^LB{Ts5^~)N| literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/2.png b/arknights_mower/resources/drone_count/2.png new file mode 100644 index 0000000000000000000000000000000000000000..734a9eef99533721528e2862ee4ce7be752397ee GIT binary patch literal 809 zcmV+^1J?YBP) z%S$40902g|PeC&Y8?{4bga-*ylloTVo!o-7L$7LLo_#2qHp1CMPFZmR(+6mL!QFBJ|8)Fa!dD z-Q8WE&v$fmL=X{rV=x#z9#1?TUs_sH6h#mOf{4%qqtWQ`cy@Mng2AAoDA{aQ6h(rF z@J~9O&SJ4lPfy2UvBkwjMNzWZtSE}*a+x3^bT=?CFg7-}va+(izV387UteEyx!mF5 zVYyre0D_3{9i2``QIy~B-`d)mpPvVShlhuJJ}=91rBZ>P2qMB?OeWL#_;@%RW*BC4 zbhO!Q-rU^CvV3uI(Q38e7lMfJ8@*mnQPj-LOf(vuot@P*?f(8gpUz6v)Sx&xgwFs>guY^W_x*gDV0j8RH|4kb~+vCj)cQunx-;1=o#U8p5r*9(I|@I+1VNNOi>iV^E}6KR;%^y?yg?1L(d9@0^xa{<2Z-I0ezAr niR|z1Z*Fed?RMx>KA-;qF^fG3J?m$j00000NkvXXu0mjf2N`>F literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/3.png b/arknights_mower/resources/drone_count/3.png new file mode 100644 index 0000000000000000000000000000000000000000..06c960001b2f55f82a8fd12fd753fc2040b45069 GIT binary patch literal 847 zcmV-V1F-ywP) zOG_$Y7y#h+OUr9!b|tYQgCGm6w}p_4q(xUw3mqFMqM#V}t=qKgH+;1+C?j;BD58x7 zVYE^h0$YSFlB^tuZqT630Ub@F)#%d&laeL9^E%JKO47>~!v>gsAB5NK#US9V3e6_W;@IP9uwyv(uXfy&qGMS{55|77Yu~^hGMmjFkH_!#cXV{5(`laP z_xAQgQ3L>ji0}uqXkN~Kb}ySqn6N6*jCP(% zWHK2Fg`&~u+uIv_AczS6P^;Cgt*u_KcWi8|va&LfNNjI!pPilM^LZ#i5D`ABs;cVj z?DYHn!^6XcLgD=Ud~0hf9*--E0-q5?gc4e<*5PolEbDf=UtV5LPEJChP%@c>uMk9p z65ZY1i;IhHx0?`>NF?_6_ph(7p-52_Q50`)Z)I7AB7%reVq|0_5D3_8HULnH;6tHM zh{a-?o120l$g&Io1QDUc(9qD#%uGv53w%ZhF&GRQjV2b01%p9B5M)^UMED)6)#~&4CMG6KCQ~#T-PqV5hzP%CwOZ%r z=O-s8Z*FcVr34Y791O#794AQNt9B8h)@oO zVK|PHB#BZ=5E073Fbv0Wk|a?|2_nL;>2x}lW#{JRve_)9lnf3I>h*eAmS10A-{0Ti zdpeyC5oc#-`}_MZE-u#B*U7@dg3IN~<#Lyomy#sq^Lh9RA*8FTYkGRx>2%)T--p9t zp6AKh+S=06QcX=wCX>0kx_Wwgg0HC6YP;Ru*4B1+cNd97c%IK@vt(suWol}wv9Zx? zHX96vii!&OhN38$OeP!-^E@w#A^?zqfdPxf(%ajMi0$p|8jS|NkEak-AvpJ-zl(954Eu-g z$Ip1^?(5{+tf%R<+`ry0R_S74$!n39Q~t#yUCEjFZ$iJ)T&r3oN$dJ)yIfL#ISU=t zvsT&Ud~`-+^^Z>%9#_6H-+#S(hU9-$0gf-*MrWERfm+*j(uNrF~dgg{p;7OL$nSi2sCu8(6UKN zt698uZEj*>VnxM{pp|#-+~MKlV-gSyZFN7>Q=gfcIdk5;zN1N3vrMO-e*5N)jEs!H zM2NmWsxo~3K0ZEve%G?L?%uuIMJZ5g>Y1Jn7njh7g2s>id3kv^M&zWWsR?k{*xIU2 zK6(7O`|~+71)+}*{+#hn)hEDVTPrQ5ZmuJ9ei-%!i7th zf`WrDpFVy1+O=yhUuxPQnNiW`&@glI$&~Eu?2Qq3Zr?tgV)WyzWqO*6iqa~s{uz=C zf?vOUSrW7|!{pb$f9qEL{{8#MAtY%BclYC;J{6Uhm#+*tm11=J_U)@#qVX2b;hu0; znpk0DXJ8PZH~nl*ZSCF|y~qCNERB_w1Or1WOw7#8%+1Y>jDl8%oI7_eEG*2<&hCRa z+<8`3R#Niv>%&%Gzka>b<SkeK&vpe1>=L-wSuTEDShcKBqX%%|&U^st+r| zR@>U!FArMT-p*cg-g5fMl#Yz@^6wu$2srGFSr)antfpqp>8BqSA3JvJ=FLb3b#?XW z)2B1&>FEJAKCGWPfBy0syM8Mcrp9mI${3C&eSG_t_rR@NQog>v3;E8TJu59O?J~u0 z`R1EC4K;TDXL_uV{JNMA?z1CjRx}r%JJaC-Nl34dBL!8jJCUY3~6ZvD>9 YawTl@mdKI;Vst0EOIgy8r+H literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/5.png b/arknights_mower/resources/drone_count/5.png new file mode 100644 index 0000000000000000000000000000000000000000..e549427c075bff5f01c64a0dd3ddcd6969944d8a GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0vp^B0wy|!2~4V?cgwHU|@3bba4!^5S)6@+FQj@fZ>5w zgn*fKqNtes!kLG*rTKR5oOmH^QBvW_i0QZsZe zD_Ec5C{^GPzjN&CSin zkGrR&DOJ_i-@kQBNN~low{LR|BovH=133;#C@Tf98yO3>3iKE%F_n@gIBS`-w6qe_ zVP3Z8MH&zIftFr*|J~o;-<74Uy0&)j?%k(9%hUml6buna_LfPMkqt}M@7(-AS6+pR3w{PEGq!FOWdUegZ zb?erz@9*tBDzW=+-mGOSrZkvfs{ecFA7*U2bYnfbZgq z5s{HM@7;3)i-?Ph&pw;B|Gxfdp|)%jsp8_|-@kufzI@s6Sls&WU%s^L-o1OS-}8U} z?0heuKkqNG=x*Now{LxYeN!XLN=r*CDk7$--n(;0M_0G=#OKeSPoM7YIB@^WxpUiY zztuUdr?21N*LP|Y3xkcl{rs6Te}2tPNnvR_z3I)PM~{B|*rDV7qs?pO$&)8rTUnQe qtiIaxP)<(H&(Ck)zI_jl=Rdt=`C`$X&n3WQ#o+1c=d#Wzp$Pz|dL>u@ literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/6.png b/arknights_mower/resources/drone_count/6.png new file mode 100644 index 0000000000000000000000000000000000000000..2fae56c72b1aa637f959b98028f7d7724e1d1506 GIT binary patch literal 841 zcmeAS@N?(olHy`uVBq!ia0vp^B0wy|!2~4V?cgwHU|<&Tba4!^5S)5&uXk0h1jB>h zek~IMI)z1C3l)@tax8e;mv!ZIyGXY*WmtZnfAN}qLH>DTk=hpmCO4GaS8@(9xFI)8GI7`*-K+uT_7)ef#$B-@l(fe}4Tcs(aeW z<*-50#t0j^_b*>I%7?DL>a?(+tZdnoL!F(RhYiHU#2$UDFpyXiqO~=OcVBbI+_`fb z9Tu!!y*fgNOR*p?Pfx5{Rj4z;V8;39#xs2u1~j~{u$g!7-aQW$BP**}=br;DEzHgB z?ch1QW5C*!pIt#3Tz;}RYozB1(1pFejV ze{=wPZg1FX)7id1nt(D>y;SF)-@Wej=bsB~*M7Zt@#5F7rK_(pF{Gp^eX82a@Zml8 zmd1{CujSQAgVM92ogrGK#l_7) z1?A=C(b3U2bH4rkD|?Hh{qX72rzcOI%rN0>T6tL+!pZ$g6HlBv)s=g@*Uj0h6R0mL zTd^gGtFEPE^XAQck9qj`yfi1mJ(!z58g=;)}r8+k0=~#EDCnE`9m( z<@W97nyPwwdTNtTW|+MC{BufBb#?XABFTN1uV0_;p|Wh*vY6|(wzj^@FK0wf%bayG z#Yn36SB>4;(v=}i?|FE6dHMNwud6O9n&h`!Utj;?CLIO?Utl6}TO7FmKL6Xjd-ll4 z%P+s2xz?0nL2BfOqb6s8X|lkA=dCDLYjZR6TGN`J{K{6#67miPp8;kO22WQ%mvv4F FO#t~6jqU&d literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/7.png b/arknights_mower/resources/drone_count/7.png new file mode 100644 index 0000000000000000000000000000000000000000..b67e3b3211fa521e8808c402afef6607e82eebf4 GIT binary patch literal 703 zcmeAS@N?(olHy`uVBq!ia0vp^B0wy|!2~4V?cgwHU|?$Vba4!^5S)6@U%MnwhW*2R zNoAi?3R8MnXWyK#FGy@k~ETgiB@vApoy+>`q?q*PNCxw%hfid_~w z+Z5!rXibmjr{^n|Pg(xj==}4;K`XC3c#serEd00MYiUwXVt04<&75tE7dQVqe)eo{ zP?xTbj*p+;wr$&jau;39sILBf_wL-FuHOFs?OV6D9!^~4Ya_QkcX!lUt)&tSt0FCA zw&mU~oa420(Uc^H6=}A%wsStaC>7S#=`BrRSYg)N+j}y_Xs(~T(!{lE*KXZv%GQu| zK;rfL_vNwW6%{)obgJfsYfS|jD$;a8xJSaEE5Ny(NFEzPA}N0n-m7&Ib^i;K0U&YCx`uC_Kd zHumnFJ2iE6%lvs5SUFmql$Dj|e2&m5tEiZ9`l+6t-V1KF2Bwm-vNWTaDMppm)w54O z{r2tKz5DlH0wwkZ$H&k2P%)b66CQs3+_`g?E?xTj*YEM1~XX#d<9kwzgA)=FOQCz`)i}WAWUHBe`cv zP_{3l1jDC?bGQ|I41>JZnzAN96dN4#(A;`Wq=8XE{@hN1LlVkMuS5l7YTT%kos{(G j)2E{H^6fEt!438&jk)*7b(<#u6DEVFtDnm{r-UW|NhLso literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/drone_count/8.png b/arknights_mower/resources/drone_count/8.png new file mode 100644 index 0000000000000000000000000000000000000000..a3e2581eee3539142b15c9c1ff6d43014646c05a GIT binary patch literal 1057 zcmV++1m63JP)7iyC`@I@`tetKZuhpASR`f&WO7Y;A3AYilD(5)|?J`g(PBl}sjcxf}oh zB7^_{BuO$1Gdnx$bUF!w07ZO!eC+M*sjB+)^pwlxAVP>FNrqwO=H@y(JKx{m)9Lir z*B2;IQBhG{U7gKlx3{;W(dhH@GwkZ>Vi;zAe!jD_Go4QF@9!TT9_qRd3beJg`Fy^P zjt*Vdx3;#T(I^ZA0*i}_{r&yvbb51hGZu@bQYr8gv)SC;-Mz4|V7J@f-`{0fh8)LX zj9Hf5+1ZgK>G}B?6lXS@M@B|Cj;pP$RTKqs9EUMxSvD99N|Iz42KbfB<-!;{91cZM zAjfeSW0qxu!Js5bhGBqTxm+%cvBTj|6a{h|hcRYZHW&;_l4KYL_?64$!WcUo4n7^8NJJu$lamu&*TGK+ zf~c>rpPHH)9UV29Op2nwzP`Tk@o~T3UsF?)NF<`s=+)KL_xCp_P+3{&^?FA}MoLOb zE-x=bp%6p}Q4}>cHa0OaQCnO4@bGYZdz;B*K!Jva2D{x}T3UK>aS;xOPft%FLI?mr z(=^ZX9*+n7<>loi6bi*+v1~RA5keM=#q0G>PEJ~_)>JC>`udv7CdcD)r(^jkX{{DV_ef{w8&@c>8ps}$r5D4`5_m`KK9~~X7tgOK0 z~2)zyW=;ZP`)$z;H< z7>27CCjp^s^Bj)P4hhO@pv>%gQ6%3fEUT&t{zB6<&+{ISN7FPYilQJ06h+Chtg0&b3r*7)W4GI_X&Mwo zQ4j>H)w;H}77mAXT?fUPOeTh5IF55Votmb>rKKgF=Q}z&5{bm>>gvhKiLUG5Cnl4r zsi|pdYHE0R*laedstWu1`g}g0-|x3tt=HGr8yg#mL?V~VfdZA4m7}AhLqkIZL7bnT zM zu`fGO902g|YkMTpo(NY$NM3@QN_fijQicu|+8X5y4e$LWR^tu#6^o&kMzrZ7BnHE+ zlG85eAkiAGi4saK*I#1&xnF-iAHo;|078hSX>)UP6B82%~aV*QSZ5w*woC_f+rHDvO z)09#=j$>JtZQIZb=UfOuDMdtLnx>S}aU9FCY}@dc@zP`%k^6BZR>$(si91e5N4Z|28A4f#8^vy7g#l^)=r(@f8 ztyY5o0|NtzL}Gq^J{%4sB4LaXLY9}84Z~PiSm^KXhkxpJy8!U{`H6^xF$MskP-tak zC6~)hPEJBF&-42F`r`3;BoaYH!We^Zp-@QEw2_e!2=@N|uIu{t_BN#y5eZ`qeuHx^ zgrJlnB4LcdZ*b0q5R_6xB#bfm4bHg`f>MfzgfRxc!8sQ~P)ZSzFvj4&DTGMRjPd#l&$jYh-wefY`L)YSC!bf?p~xVR`3 z3iW!O?CtI4ayebshlYlt(P$(Rfne=+`||R#P$)b+JOBV;jH#-s>pEj>c6K%zjY6<$ hwOTHh@9*#7+aEQ+Ze?3pBqRU;002ovPDHLkV1jTBlDq%_ literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/orders_time/0.png b/arknights_mower/resources/orders_time/0.png new file mode 100644 index 0000000000000000000000000000000000000000..a704de0eaa5400a53cb91786de51f93217e4bfb1 GIT binary patch literal 1009 zcmVOz@farV~*#AU@+M0^}5}z$L(c^gb>E2U!T4*WP}hz z20!h;5k=8vvxURq)z#GV^AHgkV}uX@-~~b8`RnVOr>6m>wAb&!+jqbCe7>cnrC2QH zbUIDb1c1R{;BvVLAr8kJ$MK9!@9yqR(=-eN{`m8+_=|X8F<`UVTCG;U-?!WC{eGV@ zhKM$s&FOR&i$%+_o}Zu3&d%WA@b6?YiHL?_P^tlNFoTGUP5u6bU@(}=<>u$-N25`z z)q;{-E=UDk*DI9@0N@NEgyXp3a2S6P-`?70jPX40^?Ef;gOXg9@{+FW)oK+02qB0_ z2oVI{=ksT?*jT@ z?M|gqjYb1Xa#_ktx~?mV!t>l@G6euaNFWf1#bVKDv{tK`=1n*p+1uMYJw1hzT$b{Z zuIq}T2!b#gjR3&qa%D0Zzu({KbW~Lx4u@-NYnz*!s;WXsE=zey*L6ivc%GX~rcUR) z&*xuTUmK6cjYfk~>h*dhNm^N1QB@U6a#_ktx~?mVLI@E>F&d3VA`zd@r)gTF(HM_M zf*|Je`D`|;sw$M^azQFkN)<(6j5!>RL?W@gylh$4dHuX?w%u;`moMF1E-y*>^Yc2C zdZABts zO7-L8WAe>-GR|dliNq^PbtuW@jlu?{v|6pMq*hWZslj0I;lqCq4_)%jbUMjqbLn)t zdC`QDT>h?D)HGVDRQC7x?RNX8>rWTW3(K+yA&3Y7h?q{Ni^Za!qtoehyAPsh0}cow9B=@TOeQ@Z&;9-V$;k=4e*2E&xW&cAjg7*>!s64@ zKoo7FC=x;#V~9);#BR4+sZ{Rn?hp~ScYY8AJ`@VSeD%`hbcv$Kkg+KvGXTKze6QE5 f*XxgukBIm`K_T?aT?X>>00000NkvXXu0mjfCA;$` literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/orders_time/1.png b/arknights_mower/resources/orders_time/1.png new file mode 100644 index 0000000000000000000000000000000000000000..c499f6478d850a960889133736833db5752d2051 GIT binary patch literal 822 zcmV-61Ihe}P)2tp0%UYKl)3W&?zEK6T4+5TY@U1Bm&NTw7pn$~K} zh$T+tzR%W6Nc?=bU9EebYpurPu`z}u07>)n^TXjk0IU_B;nq$qnM_Ld>1hlg2!c!| zlS-xL(sTV@|LW?qwfY}P#JF9p`@Rq0>FH^DdU|1D;q~h4*_m0A7Z(?YhlcDgE^nT(?7^78WF;D971j3Iyf{g0dLYuELbmX->ILS&=S*AakB zCUbdtd31DSz9A;~{f}F|@266!APh?DrQvY+>GP-D%iQeT?8olMUa#l6j2A0C<;ztRS&{%G0bp%+PZDC1Ncz5CEEX%3 z%Hf}fXQyY9NJ>JCwcR}ck^o2|83a>r^ZBJ0OPx;V{QTS)LsAlAtnKarkOV*y$sm|| zo6qN7=DOYP+1VKYl9CW(ZFdiVBmj~~hGDq2wzj;yeD=+$wZeoXR_hItiUA-wGc&VR zSWC~Pd%a$_+eJ(gVyxC1h>-*!DUnFz^Z9HxI~WXly&j&C#GTqM07)dnFu1?}*KwTp z-@Olma4_ii`vU-sNwU_mT5m`K;JVI2CgVD8GMQX`vzlGZ_WS+8U|@{7zrVk|y#+8H zkNL~5AMWn%f?z6}eX+T@>3QC0Gz!BIfVB~69LKr1xY*y{e|&t5qKMno`oqJ6@B6u2 zZuQNo=X!}mBC?T8>`Qc6K)GKrX(GLlJ>gqiWx53gO!Dy0q%4vaAu7Z>>aMZ<9%%n%Y}EL&?60I=2qfKsZmQ}Orx zAPDg2+wTFuT8oGPAR^XU5e5(dKtupgN>z3${=Ods0UjQGm!=i~L`0DS5EcdiW{VjB zAi_#z$M^jp2(bS0*fPT-t=0Ygz2~`66cLfu%34;6DwQ4I_k$q7=Pw!}0vSX!Mn_Sk zwGt7>F^Ck$@zTT26tGiAEs&QI5}pHqR{g^M2zFu zb=`8gT&YxYx!hKX@7rzI2<&atj)*8lg+g&}Z_o2Q$8q}o{>{xzyWO5nr$hu9tRFUJvzalD=Xo0& z8>_3Ug+d`ok{}3rSG{l?20@^;&gF8D!IzC=L@bp`>vLseoNl+<>2!L%9sn@2hyVZ) zK?Yy{^rl>1f4ce9Xfv5ihQnd2)x5hK#7Ru}fbbDy@b|YT+uPfY;{-v_Y&OT^@oYB3 zjEK-20syl-008{+{fFJ%-NA71@$Zk<*VjadNDr({tz{8`jEF!6-=4gyR;$zL^z7^` zPU3}Jj#<87W^1iHVz$;YzW?yo^2+kc@`{K6fH8)MtWBBa3;2(2uZzF@`dhJBbX^w_ nl~zU@A`%g177_TrPN(xPnjNa@g_c>@00000NkvXXu0mjfQ9qp` literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/orders_time/3.png b/arknights_mower/resources/orders_time/3.png new file mode 100644 index 0000000000000000000000000000000000000000..5df5a531908a0aeba5bf84d8a0621915ed08b6f8 GIT binary patch literal 885 zcmV-*1B(2KP)E|@I=G_GG*Jg z=eeGj9*suF$H%n0_a>1@Ff+|4r2r5?!~n?Ua`}9IX=yPCf{TmGR;xvOuYZi=n1}#~ z7%^f*n289!@0UuYY&JVLHy1_G(b3UhFrY^B2LK{MM1WvM#H7>d)z#HPp^!?Y_V@QE zlgW5I);gy8&Msy|gqgIC9mnxJcX@ebadB}x9$#Ny_xpXV_UYE|<%NLcwvI4}X8S>D~;7L)Ue~FdUACaTI4VY1*zg zm9j)648!%x*VT;;$8qlN?rhthOdcmez{I1w(fQeVzu&iQn`(_F03r^8U~TQI=g-$B zL2%Q($>;OQWYV%MV~k~~PUoMg+uK{JHJTzaH#g_|{$MaD7K@X~1b|X1ilZouT-U8u zH^MOL%us#jrOW^j5h7w{rI?666OmG>w7k5W$z;yY&#Aui5&#h?r9=!76Hy$;T5HS@ zQ7-4NuUCBEKR7s`TBC^>W(L4an9EXWHMQ)R2CK%PESv%)@X_d0A?m4W->;m zj4?!n8QZpBeDmUqY_{FLpzZpOF&Y4~VrBqJu`!~x#uMANx3;!YsZ_h&rf z7yw3uX^H_bGoGZ=>1wr_$z;yX&S-bM4cIl5l|FUg6o6S0olSm}+f4Vo_ z@!k0H^78)vp5FfQKAB9quIo&t93}=pMEH+Rr}Oae(ChUcA0Ph(LGhRp4aN@=00000 LNkvXXu0mjf>O!We literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/orders_time/4.png b/arknights_mower/resources/orders_time/4.png new file mode 100644 index 0000000000000000000000000000000000000000..464cd48293f4e8e9545561d4ffcd8efc3c4f5a3d GIT binary patch literal 905 zcmV;419tq0P)VIs37<2b^VZUk>^=`3m?iiUA_4#+NGUky!5~)@PDF!2UkHf@W(mGT|B-<} z!1Kq^g=jn;Urn#R_%ElYr=!sb506fW2tGqZ0E7s^U@(Z)8W2LcQL5LrH-*LA&Gt2(xW-yR-u zu4tN;&E`_6)L<}pXg^pNR=?kqk^q1)+}kVYx?ZhS?YfO0KK|f&-r9ucdA4KU-`zhy zKO-Vz2ormI1;a3`2|W4kdri|eH#d{X`_3IV{=(^DW2U<~p7hmX6vyPofn zBq0P5F~;zJ3>mWVc)S=}j4njm?Y8T>XckMcSnTn!EhW7I0Ga{-A~`b?%IEWjVK|Os z+cuiTl9ZA$Mno`$h(r_!FhnMVC=?2*RH{;`IF60Q(g^@aNv~i65g9`%i7`ZEL~>_m zH=RyjUS2wmgT>N`l=KRwhzI}}V=%!OzJ2>{W@hI4`np!D;o;FSOb`)#1`%OuV`GB{ f`TgB}tJV4!!?L{tFWc$}00000NkvXXu0mjfszH@b literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/orders_time/5.png b/arknights_mower/resources/orders_time/5.png new file mode 100644 index 0000000000000000000000000000000000000000..9dd107b1aefdcead186e75f20c2b6f511d72991d GIT binary patch literal 680 zcmV;Z0$2TsP)5fNv;^x_q9+@Bu7`8{QIY2}nqscUV{eV^+F z{tzgAK6rld0{}202nZ2GfrujtFcpR&=iK*wJUXc-lS#ucbX}JuiHO4-h{E079oCLd zGnq`GP*4KJ}i~1mStr!nP#)e7y|$zg8A^UQnM^8olZBK zO~x1i5E0CWhm~5fSTqcy)oL-u0Dy>K7DNO9tkjNncP+y(I-Sl#_aP?6D8h*Y01vq! z3Zfv6Mnl(q1pqv$pA`y)d_GUa$KyZ{1eiiZQ4~0*Uaxm`b@ll8D2gIhYDb1)Y;Jy* zWqCXvyRM5701!oy6IbJEB9Z9#`;OyuyItJdKS-rgnx+kh!ypI{k){wa2m)1&@9cb8 zUtfRz``q}|z*4yiA5j#=jM%n~rE(QMq9}?Pv27bmxVJJkxFoan&P21YqGEMXL_7+d-XRhl`!igGJecwk!B7*mHU0+*UD;A44e{QgL zd>RCSC7Jje>ui}uBwZp(MVAgNs?g7^Iq@o z9~zB@<2ZQm?J$)}X_~f@Tv>=M2%_NozO*34VlkK+3; O0000 zLAjijOeUE_{Kxn2KSraG@B72ykhWjET3TAt7Pb5L?gv4DUkM?IC>9fnGCvp$I-L&f zynLO>WD*OBL4R;@ae--6Rb5B7`|aD`olb`Y0pO4Ua0CD|ODRVY0JQtAu(`Q8J3H(9zW9j%5DAI^AR^!QPft%9 zjfN0{_6m0Xx4e{cI2>MGT@eug`j;R8g2c+oO26N~yu56;TlC@6=amN!YPIuvz0S-4 zm>B?b7={dhnN8DNUteeDYPCuqKYy_-tNK^9^hYTci(wi?QS?ZyR-@vI3;kw_#qHa2u!_dJgZ?>}U-8P97R9UaZg%pk%X5(y$=W&oO|rBbP_t*yFSC%br% z$r!Cx`|$8kQ4~y*NF?;1(v?b;cHb2Y!)UP^Yin)UT=AM88^n`>sG5> zE|=zj4{U8D;RC;wQdi3a4CabBPFW`33oAJ zD%8#MTN5r!rk@YqfA~m5m=Xd+1PEFTpH4pS?Cb(ar34_DE&XRS8cQjko}PNW9!|b| z-Q3*73jqN^^9UgvCk2R3r-L_d-z_gM19*Op9VbomIF3`TR*S`A>!O9jqhrTO5z*u0 zVEDSCF=EU-}eWD!RhHKls2@O<2b9UtNZ)=*=)Ak z?S^3pr420rAe+rrURU;Z_wMiS&(6*UgI`eE&;sdnx?C=8ZB;XwOc?&Sxw&;+7fKsi z!1KIXtyZa2I)7aaha({bls2?Lb;?@XZnyjWejLYmp|qiSJkM)18f$B7*Vosb&ed=@ z5<(CWlr}U^qtPgpO5^c348y@-5XUh9B7)L}W-)WISZp?%Qp)r5^Ioq9z*-A{h@iBg zS)S)@Y;4qOwSK>UanTwMM?wfnKxsn>W_De7eSN)NuL~hst=8S$Z7SsepahgQlwjsu zE?3{KmrLbtw|jZno=hwe0bpjDg3^W(*4jd$;QPLmG6;ewiYUR%GzFy%C9JiDLc#Za zDP<4@Q4~>vnQ0128%i*9KA-n}UrHGSK@>&IOtYZ0p#(GM^LgL*rIbMsJUslIOf1cU z(uV#~DwPfn4$^7o+qdt-;qS@B(iAfj5ndb~9TO1%A_B0ok}H?jUDpl6Fpi%l6HBxH Y0FFoKbVi3HQ~&?~07*qoM6N<$f^A?KR{#J2 literal 0 HcmV?d00001 diff --git a/arknights_mower/resources/orders_time/8.png b/arknights_mower/resources/orders_time/8.png new file mode 100644 index 0000000000000000000000000000000000000000..bd2fe098b947fe1b5fda58c111c7d64b1a50eb6e GIT binary patch literal 976 zcmV;>126oEP);Ns`Y zs;YXu-pEKK9*Yx^>$-@jX*vK9aR9JwyHqL_i$%^kuB^WD`Fych{DCaXwOY+_oNl)p z2>3ZC#v~#U36h*nezb8R%*A+tOy8hzD zERkrnTA54+fB)mXnJ^VuDVNJfM@K>kNs<6S2+{3!Js!jF4}?OY(a}-EFmkyZzW?*D z>FKF%*WKCKX*3#=BoPrJb~+tZRYRdrwOaLfjA(Q;kw}~u&T(yHb8&I8)9Gw)Z{OYB zK@TD-iUI(JVU){dpU;~}Bo`JI4i67;>%+&HnVH+$+r7R2S}hv@h)7ixSyli55nHX6 zrfCxs6SK3k`FtM#{^#FRYPwdt-QVA@*Ka$W?gLHJR8=M7uFHiGs;W**OeB-ZVzG#? zfBb1~ZY~%MmdoX{v$I<5hDaEO4giP}A_BnJ*jO|g1%Q*26MXsQ*WqwDl}bgUQOmNf zudj*7FbwEnjFF&#KfpP^y1u$7Uf@?NtA77LGC5_Mrfu7f;|L+(340_VO3h}|vaEdm z1i$_MbtDoQ8XofYdn=VnyWN%*82|(c#+afiGLwBh7Z(=?2M73O{nvCl4FH#=%lt{6 zh%`;(oD&fu0staTnv>6h&xVJGK7GpK+jm>b%gZ-6H#<8!wrvv;03ad&FeV{N05C8x z5RFD7k>OIQj9VW*E-futmbJUP%NP?v5E18G2mw!Aw`-b-bUIzBRB-d{yL38TsZ_Gr zY`fhC07;TK=ZFXZLI^};jE#?v&(F^n3I$x>{O$Q?&#$hoj*gBv=aM9G?h*;kxex*X z5K+^#vGOrBJltbC(X&R(J{j?a=9F?tiCeMglU>ByHz+Z0D$P>oCAOm0ukf! zxX-Yo!5Roxfuh)-{kL&e10Q?UJ)#4oCDbig40000IH0@%ls!44{tKLr2{$c=) z3j|pvB@hzvp%eo_`5^N-=iO#$(w+y`%IiW1P18~--Lle-<3v$(cXwx}Gl~cRl#+w~ zK#_uf5k7lf)->HT&AGX`>FL~HFhoQEFbop_l#&227!1zN&Q4BFq?EYvVl$idf&>vo zQKXcL<9K4il~Qrel%i}ldwhJ{Xf)2wPVv?2pMxOqJa04_9UUDB5i`bny&mIC#Da)S z(+tCsQq=GFcXxMj>%+$&2>Shgv)R13xX?5W01%Og;y6yHE!Um!eLtViTb5O=R`KoD z`>+(YTCGZ@f`~+}0%wr%^qUnmr&rlvZb4!+%bU;4b%YPGhvw-FHlhzJ0> z-LB&}V`F2Z(a3Qe&-a!;TRuNO$2ae`!Z2*LT01*C0HBm2B1kaCeBbYMI+kS>3WbG* zg?hb?Z{BT%Vc2T5c6N3UQ3$~~*EEeW1^}s4>ipu|9Up)2U}1H2_2A$DfBE&dTrO9y z*K4&ul%hEPOG;&$rmpLd7>!1{uHP@*fAsKSqj7{=A3la*sq^X6;o)I)84ZR5Qe@jU z07xl?5Jbu}tzxmbxVYGCHu2@R->s~yIF563b8~oj*zfm=$hK`FC8ZJ~mQwk?9|Xb7 z%uMai8a{ctRwxvLAn?3w6kQF6Lq*C?+lVNoj1#tPyRMtbWcK&>vAn)PM6T=RXY*dx z8xDttVF)2~U55lB4u`|>@o~?~{=T<|<@Jrhpr20LlarI2^Ior)$z+5Onx?`3D;y8wcQVJ0%fry4-EG;b+i^X=kjnAH! z5gF%PN;w*hAR(1xh*BydLPW=LmJ{uE8#i8TA~M4;uCA^Cz%UFV0staHL;yg<{A_+U zKWkZ5wOYmRfB5lU?%squahYJ8amI;Akz&XI01=DDqT@JG6z%Qp;ZLt#&(F`huA53A zA^=bV0Em>P>DSlSl}hFE@{)+~>& None: self.drone_time = None self.run_order_delay=10 self.enable_party = True + self.digit_reader = DigitReader() def run(self) -> None: """ @@ -688,7 +690,7 @@ def get_run_roder_time(self, room): self.tap((self.recog.w * 0.05, self.recog.h * 0.95), interval=1) error_count += 1 execute_time = self.double_read_time((int(self.recog.w * 650 / 2496), int(self.recog.h * 660 / 1404), - int(self.recog.w * 815 / 2496), int(self.recog.h * 710 / 1404))) + int(self.recog.w * 815 / 2496), int(self.recog.h * 710 / 1404)),use_digit_reader=True) execute_time = execute_time - timedelta(seconds=(60*self.run_order_delay)) logger.info('下一次进行插拔的时间为:' + execute_time.strftime("%H:%M:%S")) logger.info('返回基建主界面') @@ -696,11 +698,11 @@ def get_run_roder_time(self, room): self.back(interval=2) return execute_time - def double_read_time(self, cord, upperLimit=None): + def double_read_time(self, cord, upperLimit=None,use_digit_reader = False): if upperLimit is not None and upperLimit < 36000: upperLimit = 36000 self.recog.update() - time_in_seconds = self.read_time(cord, upperLimit) + time_in_seconds = self.read_time(cord, upperLimit,use_digit_reader) if time_in_seconds is None: return datetime.now() execute_time = datetime.now() + timedelta(seconds=(time_in_seconds)) @@ -749,10 +751,13 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) logger.exception(e) return limit+1 - def read_time(self, cord, upperlimit, error_count=0): + def read_time(self, cord, upperlimit, error_count=0,use_digit_reader = False): # 刷新图片 self.recog.update() - time_str = self.read_screen(self.recog.img, type='time', cord=cord) + if use_digit_reader: + time_str = self.digit_reader.get_time(self.recog.gray) + else: + time_str = self.read_screen(self.recog.img, type='time', cord=cord) try: h, m, s = str(time_str).split(':') if int(m) > 60 or int(s) > 60: @@ -768,7 +773,7 @@ def read_time(self, cord, upperlimit, error_count=0): logger.exception(f"读取失败{error_count}次超过上限") return None else: - return self.read_time(cord, upperlimit, error_count + 1) + return self.read_time(cord, upperlimit, error_count + 1,use_digit_reader) def todo_list(self) -> None: """ 处理基建 Todo 列表 """ @@ -1084,9 +1089,7 @@ def drone(self, room: str, not_customize=False, not_return=False): accelerate = self.find('factory_accelerate') if accelerate: - drone_count = self.read_screen(self.recog.img, type='drone_mood', cord=( - int(self.recog.w * 1150 / 1920), int(self.recog.h * 35 / 1080), int(self.recog.w * 1295 / 1920), - int(self.recog.h * 72 / 1080)), limit=200) + drone_count = self.digit_reader.get_drone(self.recog.gray) logger.info(f'当前无人机数量为:{drone_count}') if drone_count < self.drone_count_limit or drone_count > 200: logger.info(f"无人机数量小于{self.drone_count_limit}->停止") @@ -1116,9 +1119,7 @@ def drone(self, room: str, not_customize=False, not_return=False): if self.drone_room is not None: break if not_customize: - drone_count = self.read_screen(self.recog.img, type='drone_mood', cord=( - int(self.recog.w * 1150 / 1920), int(self.recog.h * 35 / 1080), int(self.recog.w * 1295 / 1920), - int(self.recog.h * 72 / 1080)), limit=200) + drone_count = self.digit_reader.get_drone(self.recog.gray) logger.info(f'当前无人机数量为:{drone_count}') self.recog.update() self.recog.save_screencap('run_order') @@ -1534,7 +1535,7 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): self.back(interval=0.5) self.back(interval=0.5) self.tasks.append({'time': self.tasks[0]['time'], 'plan': replace_plan}) - self.skip() + self.skip(False) if fia_data is not None: replace_agent = fia_data[1] fia_change_room = self.op_data.operators[replace_agent].room @@ -1548,9 +1549,11 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): self.skip() logger.info('返回基建主界面') - def skip(self): + def skip(self,skip_all=True): self.todo_task = True self.planned = True + if skip_all: + self.todo_task = True @Asst.CallBackType def log_maa(msg, details, arg): diff --git a/arknights_mower/utils/digit_reader.py b/arknights_mower/utils/digit_reader.py new file mode 100644 index 000000000..013878ba2 --- /dev/null +++ b/arknights_mower/utils/digit_reader.py @@ -0,0 +1,74 @@ +import cv2 as cv +import numpy as np +from pathlib import Path +import os +from .image import loadimg +from .. import __rootdir__ + + +class DigitReader: + def __init__(self, template_dir=None): + if not template_dir: + template_dir = Path(os.path.dirname(os.path.abspath(__file__))) / Path("templates") + if not isinstance(template_dir, Path): + template_dir = Path(template_dir) + self.time_template = [] + self.drone_template = [] + for i in range(10): + self.time_template.append( + loadimg(f'{__rootdir__}/resources/orders_time/{i}.png', True) + ) + self.drone_template.append( + loadimg(f'{__rootdir__}/resources/drone_count/{i}.png', True) + ) + + def get_drone(self, img_grey): + drone_part = img_grey[32:76, 1144:1225] + result = {} + for j in range(10): + res = cv.matchTemplate( + drone_part, + self.drone_template[j], + cv.TM_CCORR_NORMED, + ) + threshold = 0.95 + loc = np.where(res >= threshold) + for i in range(len(loc[0])): + offset = loc[1][i] + accept = True + for o in result: + if abs(o - offset) < 5: + accept = False + break + if accept: + result[loc[1][i]] = j + l = [str(result[k]) for k in sorted(result)] + return int("".join(l)) + + def get_time(self, img_grey): + digit_part = img_grey[510:543, 499:1920] + result = {} + for j in range(10): + res = cv.matchTemplate( + digit_part, + self.time_template[j], + cv.TM_CCOEFF_NORMED, + ) + threshold = 0.85 + loc = np.where(res >= threshold) + for i in range(len(loc[0])): + x = loc[1][i] + accept = True + for o in result: + if abs(o - x) < 5: + accept = False + break + if accept: + if len(result) == 0: + digit_part = digit_part[:, loc[1][i] - 5 : loc[1][i] + 116] + offset = loc[1][0] - 5 + for m in range(len(loc[1])): + loc[1][m] -= offset + result[loc[1][i]] = j + l = [str(result[k]) for k in sorted(result)] + return f"{l[0]}{l[1]}:{l[2]}{l[3]}:{l[4]}{l[5]}" From b23ce81041f3e67c36652de3111a34dcf97a0ebd Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 17 Apr 2023 23:42:07 -0700 Subject: [PATCH 08/49] =?UTF-8?q?improvement:=20=E4=BC=98=E5=85=88?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=A3=9E=E6=A1=A8=E9=AA=8C=E8=AF=81=E5=B9=B2?= =?UTF-8?q?=E5=91=98=E5=90=8D=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 4328c8bf9..989e8db91 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -737,7 +737,6 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) if len(line_conf) == 0 and 'mood' in type: return -1 x = [i[0] for i in line_conf] __str = max(set(x), key=x.count) - print(__str) if "mood" in type: if '.' in __str: __str = __str.replace(".", "") @@ -746,6 +745,9 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) elif 'time' in type: if '.' in __str: __str = __str.replace(".", ":") + elif 'name' in type and __str not in agent_list: + __str = character_recognize.agent_name(img, self.recog.h * 1.1) + logger.debug(__str) return __str except Exception as e: logger.exception(e) @@ -1382,16 +1384,14 @@ def get_agent_from_room(self, room, read_time_index=None): self.swipe((self.recog.w * 0.8, self.recog.h * 0.8), (0, -self.recog.h * 0.4), interval=1, rebuild=True) swiped = True data = {} - _name = character_recognize.agent_name( - self.recog.img[name_p[i][0][1]:name_p[i][1][1], name_p[i][0][0]:name_p[i][1][0]], self.recog.h * 1.1) + _name = self.read_screen(self.recog.img[name_p[i][0][1]:name_p[i][1][1], name_p[i][0][0]:name_p[i][1][0]],type="name") error_count = 0 while i >= 3 and _name != '' and ( next((e for e in result if e['agent'] == _name), None)) is not None: logger.warning("检测到滑动可能失败") self.swipe((self.recog.w * 0.8, self.recog.h * 0.8), (0, -self.recog.h * 0.4), interval=1, rebuild=True) - _name = character_recognize.agent_name( - self.recog.img[name_p[i][0][1]:name_p[i][1][1], name_p[i][0][0]:name_p[i][1][0]], - self.recog.h * 1.1) + _name = self.read_screen( + self.recog.img[name_p[i][0][1]:name_p[i][1][1], name_p[i][0][0]:name_p[i][1][0]], type="name") error_count += 1 if error_count > 4: raise Exception("超过出错上限") From 25444aeb390f3c2c07a3f671a6cfcfdf349999bd Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Tue, 18 Apr 2023 00:34:31 -0700 Subject: [PATCH 09/49] =?UTF-8?q?fix:=20=E7=A9=BA=E5=B9=B2=E5=91=98?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 989e8db91..10a3c1845 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -734,7 +734,11 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) else: line_conf.append(res[1]) logger.debug(line_conf) - if len(line_conf) == 0 and 'mood' in type: return -1 + if len(line_conf) == 0 : + if 'mood' in type: + return -1 + else: + return "" x = [i[0] for i in line_conf] __str = max(set(x), key=x.count) if "mood" in type: @@ -916,7 +920,10 @@ def place_clue(self,last_ori): while self.find('clue_unselect') is None: if error_count > 3: raise Exception('未成功放置线索') - self.tap(((last_ori[0][0] + last_ori[2][0]) / 2, (last_ori[0][1] + last_ori[2][1]) / 2)) + self.tap(((last_ori[0][0] + last_ori[2][0]) / 2, (last_ori[0][1] + last_ori[2][1]) / 2),interval=1) + self.recog.update() + while self.get_infra_scene() == Scene.CONNECTING: + self.sleep(2) error_count += 1 def switch_camp(self, id: int) -> tuple[int, int]: From c0ef7c712010ccdc4189a6fd233c34faaeecba58 Mon Sep 17 00:00:00 2001 From: Ksnow <1048879349@qq.com> Date: Wed, 19 Apr 2023 00:38:36 +0800 Subject: [PATCH 10/49] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E3=80=90=E9=9C=80?= =?UTF-8?q?=E7=94=A8=E5=B0=BD=E5=BF=83=E6=83=85=E7=9A=84=E5=B9=B2=E5=91=98?= =?UTF-8?q?=E3=80=91=E3=80=90=E5=AE=BF=E8=88=8D=E4=BD=8E=E4=BC=98=E5=85=88?= =?UTF-8?q?=E7=BA=A7=E5=B9=B2=E5=91=98=E3=80=91=E3=80=90=E5=8D=8F=E5=8A=A9?= =?UTF-8?q?=E4=BB=A4=E5=A4=95=E5=BF=83=E6=83=85=E8=B0=83=E9=85=8D=E7=9A=84?= =?UTF-8?q?=E5=B9=B2=E5=91=98=E3=80=91=E7=9A=84=E8=AE=BE=E7=BD=AE=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20fix:=E8=A7=A3=E5=86=B3=E8=BE=93=E5=85=A5=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E5=89=8D=E5=90=8E=E6=9C=89=E7=A9=BA=E6=A0=BC?= =?UTF-8?q?=E6=8D=A2=E8=A1=8C=E7=AC=A6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 26 ++++++++++++++++++++++---- menu.py | 34 ++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index e518cf914..c12cfd56c 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -25,17 +25,35 @@ def main(c, p, child_conn): init_fhlr(child_conn) if conf['ling_xi'] == 1: agent_base_config['令']['UpperLimit'] = 11 - agent_base_config['夕']['UpperLimit'] = 11 - agent_base_config['夕']['LowerLimit'] = 13 + assist = '夕' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] + if assist in agent_base_config.keys(): + agent_base_config[assist]['UpperLimit'] = 11 + agent_base_config[assist]['LowerLimit'] = 13 + else: + agent_base_config[assist] = {'UpperLimit': 11,'LowerLimit':13} elif conf['ling_xi'] == 2: agent_base_config['夕']['UpperLimit'] = 11 - agent_base_config['令']['UpperLimit'] = 11 - agent_base_config['令']['LowerLimit'] = 13 + assist = '令' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] + if assist in agent_base_config.keys(): + agent_base_config[assist]['UpperLimit'] = 11 + agent_base_config[assist]['LowerLimit'] = 13 + else: + agent_base_config[assist] = {'UpperLimit': 11,'LowerLimit':13} for key in list(filter(None, conf['rest_in_full'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestInFull'] = True else: agent_base_config[key] = {'RestInFull': True} + for key in list(filter(None, conf['exhaust_require'].replace(',', ',').split(','))): + if key in agent_base_config.keys(): + agent_base_config[key]['ExhaustRequire'] = True + else: + agent_base_config[key] = {'ExhaustRequire': True} + for key in list(filter(None, conf['resting_priority'].replace(',', ',').split(','))): + if key in agent_base_config.keys(): + agent_base_config[key]['RestingPriority'] = 'low' + else: + agent_base_config[key] = {'RestingPriority': 'low'} logger.info('开始运行Mower') simulate() diff --git a/menu.py b/menu.py index d23815af9..313e908f2 100644 --- a/menu.py +++ b/menu.py @@ -37,7 +37,10 @@ def load_conf(): conf['free_blacklist'] = conf['free_blacklist'] if 'free_blacklist' in conf.keys() else '' conf['run_mode'] = conf['run_mode'] if 'run_mode' in conf.keys() else 1 conf['ling_xi'] = conf['ling_xi'] if 'ling_xi' in conf.keys() else 1 - conf['rest_in_full'] = conf['rest_in_full'] if 'rest_in_full' in conf.keys() else '' + conf['rest_in_full'] = conf['rest_in_full'] if 'rest_in_full' in conf.keys() else '' # 需回满心情的干员 + conf['exhaust_require'] = conf['exhaust_require'] if 'exhaust_require' in conf.keys() else '' # 需用尽心情的干员 + conf['resting_priority'] = conf['resting_priority'] if 'resting_priority' in conf.keys() else '' # 宿舍低优先级干员 + conf['ling_xi_assist'] = conf['ling_xi_assist'] if 'ling_xi_assist' in conf.keys() else '' # 协助令夕心情调配的干员 conf['mail_enable'] = conf['mail_enable'] if 'mail_enable' in conf.keys() else 0 conf['account'] = conf['account'] if 'account' in conf.keys() else '' conf['pass_code'] = conf['pass_code'] if 'pass_code' in conf.keys() else '' @@ -208,6 +211,18 @@ def menu(): rest_in_full = sg.InputText(conf['rest_in_full'], size=60, key='conf_rest_in_full', enable_events=True) + exhaust_require_title = sg.Text('需用尽心情的干员:', size=25) + exhaust_require = sg.InputText(conf['exhaust_require'], size=60, + key='conf_exhaust_require', enable_events=True) + + resting_priority_title = sg.Text('宿舍低优先级干员:', size=25) + resting_priority = sg.InputText(conf['resting_priority'], size=60, + key='conf_resting_priority', enable_events=True) + ling_xi_assist_title = sg.Text('协助令夕心情调配的干员:', size=25) + ling_xi_assist = sg.InputText(conf['ling_xi_assist'], size=60, + key='conf_ling_xi_assist', enable_events=True) + + # --------外部调用设置页面 # mail mail_enable_1 = sg.Radio('启用', 'mail_enable', default=conf['mail_enable'] == 1, @@ -256,11 +271,14 @@ def menu(): setting_tab = sg.Tab(' 高级设置 ', [[run_mode_title, run_mode_1, run_mode_2], [ling_xi_title, ling_xi_1, ling_xi_2, ling_xi_3], [enable_party_title,enable_party_1,enable_party_0], - [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title, - run_order_delay], - [drone_room_title, drone_room, sg.Text('', size=7), drone_count_limit_title, - drone_count_limit], - [rest_in_full_title, rest_in_full]], pad=((10, 10), (10, 10))) + [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title,run_order_delay], + [drone_room_title, drone_room, sg.Text('', size=7), drone_count_limit_title,drone_count_limit], + [rest_in_full_title, rest_in_full], + [exhaust_require_title, exhaust_require], + [resting_priority_title, resting_priority], + [ling_xi_assist_title, ling_xi_assist] + ], pad=((10, 10), (10, 10))) + other_tab = sg.Tab(' 外部调用 ', [[mail_frame], [maa_frame]], pad=((10, 10), (10, 10))) window = sg.Window('Mower', [[sg.TabGroup([[main_tab, plan_tab, setting_tab, other_tab]], border_width=0, @@ -283,11 +301,11 @@ def menu(): drag_task.clear() # 拖拽事件连续不间断,若未触发事件,则初始化 if event.startswith('conf_'): key = event[5:] - conf[key] = window[event].get() + conf[key] = window[event].get().strip() elif event.startswith('int_'): key = event[4:] try: - conf[key] = int(window[event].get()) + conf[key] = int(window[event].get().strip()) except ValueError: println(f'[{window[key + "_title"].get()}]需为数字') elif event.startswith('radio_'): From 7e41ccdd600e3546f0593d12bc91d37ff262cb4e Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Tue, 18 Apr 2023 23:35:06 -0700 Subject: [PATCH 11/49] =?UTF-8?q?fix:=20=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 8 ++++++-- arknights_mower/utils/operators.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 10a3c1845..1a46498ba 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -349,7 +349,7 @@ def infra_main(self): self.drone(self.drone_room) logger.info(f"记录本次无人机使用时间为:{datetime.now()}") self.drone_time = datetime.now() - if self.party_time is None and self.enable_party : + if self.party_time is None and self.enable_party: self.clue() if notification is None: self.sleep(1) @@ -418,7 +418,7 @@ def agent_get_mood(self, skip_dorm=False, force=False): continue if not (_name == plan[key][idx]['agent'] or ( (_name in plan[key][idx]["replacement"]) and len(plan[key][idx]["replacement"]) > 0) or not - self.op_data.operators[_name].need_to_refresh()): + self.op_data.operators[_name].need_to_refresh(1.5)): if not need_fix: fix_plan[key] = ['Current'] * len(plan[key]) need_fix = True @@ -737,6 +737,9 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) if len(line_conf) == 0 : if 'mood' in type: return -1 + elif 'name' in type: + logger.debug("使用老版识别") + return character_recognize.agent_name(img, self.recog.h * 1.1) else: return "" x = [i[0] for i in line_conf] @@ -750,6 +753,7 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) if '.' in __str: __str = __str.replace(".", ":") elif 'name' in type and __str not in agent_list: + logger.debug("使用老版识别") __str = character_recognize.agent_name(img, self.recog.h * 1.1) logger.debug(__str) return __str diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 3030b0d5e..c1ae2a7c7 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -204,5 +204,5 @@ def not_valid(self): return True else: return False - return self.need_to_refresh() or self.current_room != self.room or self.index != self.current_index + return self.need_to_refresh(1.5) or self.current_room != self.room or self.index != self.current_index return False From f8f7cddb7877ff451d6c5de7f7c7bee83e752413 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Wed, 19 Apr 2023 08:44:43 -0700 Subject: [PATCH 12/49] =?UTF-8?q?fix:=20=E6=97=B6=E9=97=B4=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 2 +- arknights_mower/utils/operators.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 1a46498ba..cac8c5ff7 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -418,7 +418,7 @@ def agent_get_mood(self, skip_dorm=False, force=False): continue if not (_name == plan[key][idx]['agent'] or ( (_name in plan[key][idx]["replacement"]) and len(plan[key][idx]["replacement"]) > 0) or not - self.op_data.operators[_name].need_to_refresh(1.5)): + self.op_data.operators[_name].need_to_refresh(2.5)): if not need_fix: fix_plan[key] = ['Current'] * len(plan[key]) need_fix = True diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index c1ae2a7c7..3db7f20f1 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -204,5 +204,5 @@ def not_valid(self): return True else: return False - return self.need_to_refresh(1.5) or self.current_room != self.room or self.index != self.current_index + return self.need_to_refresh(2.5) or self.current_room != self.room or self.index != self.current_index return False From 8d0476cf2435d3a1d3e06bd3d13d8b46b537760e Mon Sep 17 00:00:00 2001 From: Ksnow <1048879349@qq.com> Date: Thu, 20 Apr 2023 22:57:05 +0800 Subject: [PATCH 13/49] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E5=B9=B2=E5=91=98?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - arknights_mower/__main__.py | 1 + arknights_mower/utils/character_recognize.py | 2 +- menu.py | 19 ++++++++++++------- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index cbaaa07e0..2fc6deb14 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,6 @@ MANIFEST # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest -*.spec # Installer logs pip-log.txt diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index c12cfd56c..fcaceb3d7 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -55,6 +55,7 @@ def main(c, p, child_conn): else: agent_base_config[key] = {'RestingPriority': 'low'} logger.info('开始运行Mower') + logger.debug(agent_base_config) simulate() diff --git a/arknights_mower/utils/character_recognize.py b/arknights_mower/utils/character_recognize.py index e9150ae0c..09f3da2e4 100644 --- a/arknights_mower/utils/character_recognize.py +++ b/arknights_mower/utils/character_recognize.py @@ -168,7 +168,7 @@ def agent(img, draw=False): ret_agent.append(res) ret_succ.append(poly) continue - logger.warning( + logger.debug( f'干员名称识别异常:{x[1]} 为不存在的数据,请报告至 https://github.com/Konano/arknights-mower/issues' ) saveimg(__img, 'failure_agent') diff --git a/menu.py b/menu.py index 313e908f2..6aaad4288 100644 --- a/menu.py +++ b/menu.py @@ -165,7 +165,7 @@ def menu(): # 排班表设置标签 for i in range(1, 6): set_area = sg.Column([[sg.Text('干员:'), - sg.InputCombo(['Free'] + agent_list, size=20, key='agent' + str(i)), + sg.Combo(['Free'] + agent_list, size=20, key='agent' + str(i), change_submits=True), sg.Text('组:'), sg.InputText('', size=15, key='group' + str(i)), sg.Text('替换:'), @@ -299,10 +299,10 @@ def menu(): run_script(event[:event.rindex('-')], drag_task) continue drag_task.clear() # 拖拽事件连续不间断,若未触发事件,则初始化 - if event.startswith('conf_'): + if event.startswith('conf_'): # conf开头,为字符串输入的配置 key = event[5:] conf[key] = window[event].get().strip() - elif event.startswith('int_'): + elif event.startswith('int_'): # int开头,为数值型输入的配置 key = event[4:] try: conf[key] = int(window[event].get().strip()) @@ -324,15 +324,17 @@ def menu(): elif event.startswith('btn_'): # 设施按钮 btn = event init_btn(event) + elif event.endswith('-agent_change'): #干员填写 + input_agent = window[event[:event.rindex('-')]].get().strip() + window[event[:event.rindex('-')]].update(value=input_agent,values=list(filter(lambda s:input_agent in s,['Free'] + agent_list))) + elif event.startswith('agent'): + input_agent = window[event].get().strip() + window[event].update(value=input_agent,values=list(filter(lambda s:input_agent in s,['Free'] + agent_list))) elif event == 'savePlan': # 保存设施信息 save_btn(btn) elif event == 'clearPlan': # 清空当前设施信息 clear_btn(btn) elif event == 'on': - # if adb.get() == '': - # println('adb未设置!') - # continue - on_btn.update(visible=False) off_btn.update(visible=True) clear() @@ -359,6 +361,9 @@ def bind_scirpt(): window[event].bind("", "-motion-script") window[event].bind("", "-ButtonRelease-script") window[event].bind("", "-Enter-script") + for i in range(5): + event = f'agent{str(i + 1)}' + window[event].bind("", "-agent_change") def run_script(event, drag_task): From 7ed3f096e59d0928b5bbd68838524ae17d1f3f90 Mon Sep 17 00:00:00 2001 From: Ksnow <1048879349@qq.com> Date: Thu, 20 Apr 2023 23:00:06 +0800 Subject: [PATCH 14/49] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E5=B9=B2=E5=91=98?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- menu.spec | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 menu.spec diff --git a/menu.spec b/menu.spec new file mode 100644 index 000000000..cc6ef6e06 --- /dev/null +++ b/menu.spec @@ -0,0 +1,60 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['menu.py'], + pathex=[], + binaries=[], + datas=[('arknights_mower/fonts', 'arknights_mower/__init__/fonts'), + ('arknights_mower/models', 'arknights_mower/__init__/models'), + ('arknights_mower/templates', 'arknights_mower/__init__/templates'), + ('arknights_mower/resources', 'arknights_mower/__init__/resources'), + ('arknights_mower/data', 'arknights_mower/__init__/data'), + ('arknights_mower/ocr', 'arknights_mower/__init__/ocr'), + ('arknights_mower/vendor', 'arknights_mower/__init__/vendor'), + ('arknights_mower/solvers', 'arknights_mower/__init__/solvers'), + ('venv/Lib/site-packages/onnxruntime/capi/onnxruntime_providers_shared.dll', 'onnxruntime/capi/'), + ('venv/Lib/site-packages/paddleocr', 'paddleocr'), + ('venv/Lib/site-packages/paddle/libs/mkldnn.dll', '.'), + ('venv/Lib/site-packages/paddle/libs/mklml.dll', '.'), + ('venv/Lib/site-packages/shapely/DLLs/geos.dll', '.'), + ('venv/Lib/site-packages/paddle/fluid/libpaddle.lib', '.'), + ('venv/Lib/site-packages/paddle/fluid/libpaddle.pyd', '.'), + ('venv/Lib/site-packages/shapely/DLLs/geos_c.dll', '.')], + hiddenimports=['imghdr','imgaug','scipy.io','lmdb'], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='mower', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False , + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon='logo.ico' +) From 725f56125e6cd22c3415812e8bcd76be03af6e26 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Thu, 20 Apr 2023 11:01:27 -0700 Subject: [PATCH 15/49] =?UTF-8?q?add:=20=E4=BC=8A=E5=86=85=E4=B8=9D?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- diy.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/diy.py b/diy.py index 82f958495..4a871232d 100644 --- a/diy.py +++ b/diy.py @@ -186,19 +186,20 @@ "爱丽丝":{"ArrangeOrder":[ 2, "false" ]}, "桃金娘":{"ArrangeOrder":[ 2, "false" ]}, "帕拉斯": {"RestingPriority": "low"}, - "红云": {"RestingPriority": "low","ArrangeOrder":[2,"true"]}, - "承曦格雷伊": {"ArrangeOrder":[2,"true"]}, - "乌有":{"ArrangeOrder":[2,"true"],"RestingPriority": "low"}, - "图耶":{"ArrangeOrder":[2,"true"]}, - "鸿雪": {"ArrangeOrder":[2,"true"]}, - "孑":{"ArrangeOrder":[2,"true"]}, - "清道夫":{"ArrangeOrder":[2,"true"]}, - "临光":{"ArrangeOrder":[2,"true"]}, - "杜宾":{"ArrangeOrder":[2,"true"]}, - "焰尾":{"RestInFull": True}, - "重岳":{"ArrangeOrder":[2,"true"]}, - "坚雷":{"ArrangeOrder":[2,"true"]}, - "年":{"RestingPriority": "low"} + "红云": {"RestingPriority": "low", "ArrangeOrder": [2, "true"]}, + "承曦格雷伊": {"ArrangeOrder": [2, "true"],"RestInFull": True}, + "乌有": {"ArrangeOrder": [2, "true"], "RestingPriority": "low"}, + "图耶": {"ArrangeOrder": [2, "true"]}, + "鸿雪": {"ArrangeOrder": [2, "true"]}, + "孑": {"ArrangeOrder": [2, "true"]}, + "清道夫": {"ArrangeOrder": [2, "true"]}, + "临光": {"ArrangeOrder": [2, "true"]}, + "杜宾": {"ArrangeOrder": [2, "true"]}, + "焰尾": {"RestInFull": True}, + "重岳": {"ArrangeOrder": [2, "true"]}, + "坚雷": {"ArrangeOrder": [2, "true"]}, + "年": {"RestingPriority": "low"}, + "伊内丝": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"], "RestInFull": True}, } From c03103099d0dfb07c7dc081f131ee072d0e5fb99 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Thu, 20 Apr 2023 11:46:14 -0700 Subject: [PATCH 16/49] =?UTF-8?q?fix:=20=E7=A8=80=E9=9F=B3=E5=AE=89?= =?UTF-8?q?=E6=8E=92=E5=9C=A8=E9=9D=9E1=E5=8F=B7=E7=94=A8=E5=B0=BD?= =?UTF-8?q?=E5=BF=83=E6=83=85=E4=B8=8D=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index cac8c5ff7..c211641c9 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -561,6 +561,9 @@ def plan_solver(self): break continue if op.group != '': + if op.group in self.op_data.exhaust_group: + # 忽略掉用尽心情的分组 + continue # 如果在group里则同时上下班 group_resting = self.op_data.groups[op.group] _replacement, _plan, high_free, low_free = self.get_resting_plan( @@ -601,6 +604,10 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) if not success: break x = self.op_data.operators[agent] + if self.op_data.get_dorm_by_name(x.name)[0] is not None: + # 如果干员已经被安排了 + success = False + break _rep = next((obj for obj in x.replacement if (not ( self.op_data.operators[obj].current_room != '' and not self.op_data.operators[ obj].current_room.startswith('dormitory'))) and obj not in ['但书', @@ -1129,13 +1136,13 @@ def drone(self, room: str, not_customize=False, not_return=False): self.tap((self.recog.w * 0.75, self.recog.h * 0.8)) while self.get_infra_scene() == Scene.CONNECTING: self.sleep(3) + self.recog.update() + self.recog.save_screencap('run_order') if self.drone_room is not None: break if not_customize: drone_count = self.digit_reader.get_drone(self.recog.gray) logger.info(f'当前无人机数量为:{drone_count}') - self.recog.update() - self.recog.save_screencap('run_order') # 200 为识别错误 if drone_count < self.drone_count_limit or drone_count == 201: logger.info(f"无人机数量小于{self.drone_count_limit}->停止") From 36c961d5b46cbcda9f4a6d6f376d92c9ad9f508e Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Fri, 21 Apr 2023 22:49:54 -0700 Subject: [PATCH 17/49] =?UTF-8?q?add:=20=E9=81=97=E5=A4=B1=E7=9A=84?= =?UTF-8?q?=E7=BA=BF=E7=B4=A2=E5=BC=80=E5=90=AF=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index c211641c9..cd7a076a4 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -910,7 +910,8 @@ def clue(self) -> None: self.recog.update() logger.info(f"放置线索{i}") self.place_clue(last_ori) - + # 返回线索主界面 + self.tap((self.recog.w * 0.05, self.recog.h * 0.95), interval=3, rebuild=False) # 线索交流开启 if clue_unlock is not None and get_all_clue: self.tap(clue_unlock) From d5d10bdf5ab7574909033546d1f0c5243bfb687b Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 24 Apr 2023 00:14:54 -0700 Subject: [PATCH 18/49] =?UTF-8?q?feat:=20=E8=B6=B4=E4=BD=93=E7=BB=93?= =?UTF-8?q?=E6=9D=9F=E8=B4=AD=E7=89=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 6 +- arknights_mower/solvers/base_schedule.py | 139 +++++++++++++++-------- diy.py | 116 ++++++++++--------- 3 files changed, 154 insertions(+), 107 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index fcaceb3d7..f8abfa72e 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -27,18 +27,16 @@ def main(c, p, child_conn): agent_base_config['令']['UpperLimit'] = 11 assist = '夕' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] if assist in agent_base_config.keys(): - agent_base_config[assist]['UpperLimit'] = 11 agent_base_config[assist]['LowerLimit'] = 13 else: - agent_base_config[assist] = {'UpperLimit': 11,'LowerLimit':13} + agent_base_config[assist] = {'LowerLimit':13} elif conf['ling_xi'] == 2: agent_base_config['夕']['UpperLimit'] = 11 assist = '令' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] if assist in agent_base_config.keys(): - agent_base_config[assist]['UpperLimit'] = 11 agent_base_config[assist]['LowerLimit'] = 13 else: - agent_base_config[assist] = {'UpperLimit': 11,'LowerLimit':13} + agent_base_config[assist] = {'LowerLimit':13} for key in list(filter(None, conf['rest_in_full'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestInFull'] = True diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index cd7a076a4..ee9f51ab0 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -55,6 +55,8 @@ def __init__(self, device: Device = None, recog: Recognizer = None) -> None: self.max_resting_count = 4 self.party_time = None self.drone_time = None + self.reload_time = None + self.reload_room = None self.run_order_delay=10 self.enable_party = True self.digit_reader = DigitReader() @@ -323,6 +325,8 @@ def infra_main(self): # 如果任务名称包含干员名,则为动态生成的 elif 'type' in self.task.keys() and self.task['type'].split(',')[0] in agent_list: self.overtake_room() + elif 'type' in self.task.keys() and self.task['type'] == 'impart': + self.skip(False) del self.tasks[0] except Exception as e: logger.exception(e) @@ -351,6 +355,9 @@ def infra_main(self): self.drone_time = datetime.now() if self.party_time is None and self.enable_party: self.clue() + if self.reload_room is not None: + if self.reload_time is None or self.reload_time < datetime.now()- timedelta(hours=24): + self.reload() if notification is None: self.sleep(1) notification = detector.infra_notification(self.recog.img) @@ -925,6 +932,10 @@ def clue(self) -> None: else: self.back(interval=2) logger.info('返回基建主界面') + if self.party_time is not None: + if (next((e for e in self.tasks if e['time'] == self.party_time and e['type']=="maa_Mall"), None)) is None: + self.tasks.append({'time': self.party_time - timedelta(milliseconds=1), 'plan': {},'type': 'impart'}) + self.tasks.append({'time': self.party_time, 'plan': {}, 'type': 'maa_Mall'}) self.back(interval=2) def place_clue(self,last_ori): @@ -1225,7 +1236,7 @@ def detail_filter(self, turn_on, type="not_in_dorm"): logger.info(f'开始 {("打开" if turn_on else "关闭")} {type} 筛选') self.tap((self.recog.w * 0.95, self.recog.h * 0.05), interval=1) if type == "not_in_dorm": - not_in_dorm = self.find('arrange_non_check_in', score=0.85) + not_in_dorm = self.find('arrange_non_check_in', score=0.9) if turn_on ^ (not_in_dorm is None): self.tap((self.recog.w * 0.3, self.recog.h * 0.5), interval=0.5) # 确认 @@ -1434,7 +1445,7 @@ def get_agent_from_room(self, room, read_time_index=None): data['agent'] = _name data['mood'] = _mood if i in read_time_index: - if _mood in [24] or (_mood == 0 and not room.startswith('dorm')): + if _mood ==24 : data['time'] = datetime.now() else: upperLimit = 21600 @@ -1569,10 +1580,27 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): logger.info('返回基建主界面') def skip(self,skip_all=True): - self.todo_task = True self.planned = True if skip_all: self.todo_task = True + def reload(self): + error = False + for room in self.reload_room: + try: + self.enter_room(room) + except Exception as e: + logger.error(e) + error = True + self.recog.update() + back_count = 0 + while self.get_infra_scene() != Scene.INFRA_MAIN: + self.back() + self.recog.update() + back_count += 1 + if back_count > 3: + raise e + if not error: + self.reload_time = datetime.now() @Asst.CallBackType def log_maa(msg, details, arg): @@ -1587,6 +1615,7 @@ def inialize_maa(self): # 例如 asst = Asst(callback=my_callback) Asst.load(path=self.maa_config['maa_path']) self.MAA = Asst(callback=self.log_maa) + self.stages = [] # self.MAA.set_instance_option(2, 'maatouch') # 请自行配置 adb 环境变量,或修改为 adb 可执行程序的路径 # logger.info(self.device.client.device_id) @@ -1596,10 +1625,52 @@ def inialize_maa(self): logger.info("MAA 连接失败") raise Exception("MAA 连接失败") - def maa_plan_solver(self): - + def append_maa_task(self, type): + if type in ['StartUp','Visit','Award']: + self.MAA.append_task(type) + elif type == 'Fight': + _plan = self.maa_config['weekly_plan'][get_server_weekday()] + logger.info(f"现在服务器是{_plan['weekday']}") + for stage in _plan["stage"]: + logger.info(f"添加关卡:{stage}") + self.MAA.append_task('Fight', { + # 空值表示上一次 + # 'stage': '', + 'stage': stage, + 'medicine': _plan["medicine"], + 'stone': 0, + 'times': 999, + 'report_to_penguin': True, + 'client_type': '', + 'penguin_id': '', + 'DrGrandet': False, + 'server': 'CN' + }) + self.stages.append(stage) + elif type =='Recruit': + self.MAA.append_task('Recruit', { + 'select': [4], + 'confirm': [3, 4], + 'times': 4, + 'refresh': True, + "recruitment_time": { + "3": 460, + "4": 540 + } + }) + elif type == 'Mall': + credit_fight = False + if len(self.stages) > 0 and self.stages[- 1] != '': + credit_fight = True + self.MAA.append_task('Mall', { + 'shopping': True, + 'buy_first': ['龙门币', '赤金'], + 'blacklist': ['家具', '碳', '加急'], + 'credit_fight':credit_fight + }) + def maa_plan_solver(self,tasks ='All',one_time = False): try: - if self.maa_config['last_execution'] is not None and datetime.now() - timedelta( + if not one_time and self.maa_config['last_execution'] is not None and datetime.now() - timedelta( seconds=self.maa_config['maa_execution_gap'] * 3600) < self.maa_config['last_execution']: logger.info("间隔未超过设定时间,不启动maa") else: @@ -1607,44 +1678,10 @@ def maa_plan_solver(self): self.back_to_index() # 任务及参数请参考 docs/集成文档.md self.inialize_maa() - self.MAA.append_task('StartUp') - _plan = self.maa_config['weekly_plan'][get_server_weekday()] - logger.info(f"现在服务器是{_plan['weekday']}") - fights = [] - for stage in _plan["stage"]: - logger.info(f"添加关卡:{stage}") - self.MAA.append_task('Fight', { - # 空值表示上一次 - # 'stage': '', - 'stage': stage, - 'medicine': _plan["medicine"], - 'stone': 0, - 'times': 999, - 'report_to_penguin': True, - 'client_type': '', - 'penguin_id': '', - 'DrGrandet': False, - 'server': 'CN' - }) - fights.append(stage) - self.MAA.append_task('Recruit', { - 'select': [4], - 'confirm': [3, 4], - 'times': 4, - 'refresh': True, - "recruitment_time": { - "3": 460, - "4": 540 - } - }) - self.MAA.append_task('Visit') - self.MAA.append_task('Mall', { - 'shopping': True, - 'buy_first': ['龙门币', '赤金'], - 'blacklist': ['家具', '碳', '加急'], - 'credit_fight': fights[len(fights) - 1] != '' - }) - self.MAA.append_task('Award') + if tasks == 'All': + tasks = ['StartUp','Fight','Recruit','Visit','Mall','Award'] + for maa_task in tasks: + self.append_maa_task(maa_task) # asst.append_task('Copilot', { # 'stage_name': '千层蛋糕', # 'filename': './GA-EX8-raid.json', @@ -1652,11 +1689,18 @@ def maa_plan_solver(self): # }) self.MAA.start() + stop_time = None + if one_time: + stop_time = datetime.now()+timedelta(minutes=5) logger.info(f"MAA 启动") hard_stop = False while self.MAA.running(): + # 单次任务默认5分钟 + if one_time and stop_time < datetime.now(): + self.MAA.stop() + hard_stop = True # 5分钟之前就停止 - if (self.tasks[0]["time"] - datetime.now()).total_seconds() < 300: + elif not one_time and (self.tasks[0]["time"] - datetime.now()).total_seconds() < 300: self.MAA.stop() hard_stop = True else: @@ -1666,7 +1710,7 @@ def maa_plan_solver(self): logger.info(f"由于maa任务并未完成,等待3分钟重启软件") time.sleep(180) self.device.exit(self.package_name) - else: + elif not one_time: logger.info(f"记录MAA 本次执行时间") self.maa_config['last_execution'] = datetime.now() logger.info(self.maa_config['last_execution']) @@ -1705,7 +1749,8 @@ def maa_plan_solver(self): time.sleep(0) self.device.exit(self.package_name) # 生息演算逻辑 结束 - remaining_time = (self.tasks[0]["time"] - datetime.now()).total_seconds() + remaining_time = 0 if one_time and len(self.tasks) == 1 else ( + self.tasks[1 if one_time else 0]["time"] - datetime.now()).total_seconds() subject = f"开始休息 {'%.2f' % (remaining_time / 60)} 分钟,到{self.tasks[0]['time'].strftime('%H:%M:%S')}" context = f"下一次任务:{self.tasks[0]['plan']}" logger.info(context) diff --git a/diy.py b/diy.py index 4a871232d..a01a3ff0c 100644 --- a/diy.py +++ b/diy.py @@ -60,12 +60,13 @@ # 无人机执行间隔时间 (小时) drone_execution_gap = 4 +reload_room = [] + # 全自动基建排班计划: # 这里定义了一套全自动基建的排班计划 plan_1 # agent 为常驻高效组的干员名 # group 为干员编队,你希望任何编队的人一起上下班则给他们编一样的名字 - # 编队最大数不支持超过4个干员 否则可能会在计算自动排班的时候报错 # replacement 为替换组干员备选 # 暖机干员的自动换班 # 目前只支持一个暖机干员休息 @@ -85,13 +86,13 @@ "default": "plan_1", "plan_1": { # 中枢 - 'central': [{'agent': '焰尾', 'group': '红松骑士', 'replacement': ["凯尔希","诗怀雅"]}, - {'agent': '琴柳', 'group': '', 'replacement': ["凯尔希","阿米娅"]}, - {'agent': '重岳', 'group': '夕', 'replacement': ["玛恩纳", "清道夫", "凯尔希", "阿米娅", '坚雷']}, - {'agent': '夕', 'group': '夕', 'replacement': ["玛恩纳", "清道夫", "凯尔希", "阿米娅", '坚雷']}, - {'agent': '令', 'group': '夕', 'replacement': ["玛恩纳", "清道夫", "凯尔希", "阿米娅", '坚雷']}, + 'central': [{'agent': '焰尾', 'group': '红松骑士', 'replacement': [ "阿米娅","凯尔希",]}, + {'agent': '琴柳', 'group': '夕', 'replacement': [ "阿米娅","凯尔希","玛恩纳"]}, + {'agent': '重岳', 'group': '', 'replacement': ["玛恩纳", "清道夫", "凯尔希", "阿米娅", '坚雷']}, + {'agent': '夕', 'group': '夕', 'replacement': ["阿米娅","凯尔希","玛恩纳", "清道夫", "阿米娅", '坚雷']}, + {'agent': '令', 'group': '', 'replacement': ["玛恩纳", "清道夫", "凯尔希", "阿米娅", '坚雷']}, ], - 'contact': [{'agent': '絮雨', 'group': '絮雨', 'replacement': []}], + 'contact': [{'agent': '桑葚', 'group': '', 'replacement': ['艾雅法拉']}], # 宿舍 'dormitory_1': [{'agent': '流明', 'group': '', 'replacement': []}, {'agent': '闪灵', 'group': '', 'replacement': []}, @@ -113,23 +114,23 @@ ], 'dormitory_4': [{'agent': '波登可', 'group': '', 'replacement': []}, {'agent': '夜莺', 'group': '', 'replacement': []}, - {'agent': '菲亚梅塔', 'group': '', 'replacement': ['迷迭香', '黑键', '絮雨','至简']}, + {'agent': '菲亚梅塔', 'group': '', 'replacement': ['重岳', '令', '乌有']}, {'agent': 'Free', 'group': '', 'replacement': []}, {'agent': 'Free', 'group': '', 'replacement': []}], - 'factory':[{'agent': '年', 'replacement': ['九色鹿','芳汀'], 'group': '夕'}], + 'factory': [{'agent': '年', 'replacement': ['九色鹿', '芳汀'], 'group': '夕'}], # 会客室 - 'meeting': [{'agent': '陈', 'replacement': ['星极','远山'], 'group': ''}, - {'agent': '红', 'replacement': ['远山','星极'], 'group': ''} ], - 'room_1_1': [{'agent': '黑键', 'group': '', 'replacement': []}, - {'agent': '乌有', 'group': '夕', 'replacement': ['但书','图耶']}, - {'agent': '空弦', 'group': '夕', 'replacement': ['龙舌兰', '鸿雪']} + 'meeting': [{'agent': '伊内丝', 'replacement': ['陈', '红', '远山'], 'group': ''}, + {'agent': '见行者', 'replacement': ['陈', '红', '星极'], 'group': ''}], + 'room_1_1': [{'agent': '乌有', 'group': '', 'replacement': ['伺夜']}, + {'agent': '空弦', 'group': '图耶', 'replacement': ['龙舌兰', '鸿雪']}, + {'agent': '伺夜', 'group': '图耶', 'replacement': ['但书','图耶']}, # {'agent': '伺夜', 'group': '图耶', 'replacement': ['但书','能天使']}, - # {'agent': '空弦', 'group': '图耶', 'replacement': ['龙舌兰', '雪雉']} + # {'agent': '空弦', '鸿雪': '图耶', 'replacement': ['龙舌兰', '雪雉']} ], - 'room_1_2': [{'agent': '迷迭香', 'group': '', 'replacement': []}, - {'agent': '砾', 'group': '', 'Type': '', 'replacement': ['斑点','夜烟']}, - {'agent': '至简', 'group': '', 'replacement': []}], - 'room_1_3': [{'agent': '承曦格雷伊', 'group': '异客', 'replacement': ['炎狱炎熔','格雷伊']}], + 'room_1_2': [{'agent': '槐琥', 'group': '槐琥', 'replacement': ['贝娜']}, + {'agent': '砾', 'group': '槐琥', 'Type': '', 'replacement': ['泡泡']}, + {'agent': '至简', 'group': '槐琥', 'replacement': ['火神']}], + 'room_1_3': [{'agent': '承曦格雷伊', 'group': '异客', 'replacement': ['炎狱炎熔', '格雷伊']}], 'room_2_2': [{'agent': '温蒂', 'group': '异客', 'replacement': ['火神']}, # {'agent': '异客', 'group': '异客', 'Type': '', 'replacement': ['贝娜']}, {'agent': '异客', 'group': '异客', 'Type': '', 'replacement': ['贝娜']}, @@ -137,14 +138,14 @@ 'room_3_1': [{'agent': '稀音', 'group': '稀音', 'replacement': ['贝娜']}, {'agent': '帕拉斯', 'group': '稀音', 'Type': '', 'replacement': ['泡泡']}, {'agent': '红云', 'group': '稀音', 'replacement': ['火神']}], - 'room_2_3': [{'agent': '澄闪', 'group': '', 'replacement': ['炎狱炎熔', '格雷伊']}], + 'room_2_3': [{'agent': '澄闪', 'group': '澄闪', 'replacement': ['炎狱炎熔', '格雷伊']}], 'room_2_1': [{'agent': '食铁兽', 'group': '食铁兽', 'replacement': ['泡泡']}, {'agent': '断罪者', 'group': '食铁兽', 'replacement': ['火神']}, - {'agent': '槐琥', 'group': '食铁兽', 'replacement': ['贝娜']}], + {'agent': '截云', 'group': '夕', 'replacement': ['迷迭香']}], 'room_3_2': [{'agent': '灰毫', 'group': '红松骑士', 'replacement': ['贝娜']}, {'agent': '远牙', 'group': '红松骑士', 'Type': '', 'replacement': ['泡泡']}, {'agent': '野鬃', 'group': '红松骑士', 'replacement': ['火神']}], - 'room_3_3': [{'agent': '雷蛇', 'group': '', 'replacement': ['炎狱炎熔','格雷伊']}] + 'room_3_3': [{'agent': '雷蛇', 'group': '澄闪', 'replacement': ['炎狱炎熔', '格雷伊']}] } } @@ -155,39 +156,37 @@ # RestingPriority:休息优先级,低优先级不会使用单回技能。 agent_base_config = { - "Default":{"UpperLimit": 24,"LowerLimit": 0,"ExhaustRequire": False,"ArrangeOrder":[2,"false"],"RestInFull": False}, - # 卡贸易站 - "令":{"UpperLimit": 11,"LowerLimit": 13,"ArrangeOrder":[2,"true"]}, - "夕": {"UpperLimit": 11,"ArrangeOrder":[2,"true"]}, - # 卡制造站 - #"令": {"UpperLimit": 11, "LowerLimit": 13, "ArrangeOrder": [2, "true"]}, - #"夕": {"UpperLimit": 11, "ArrangeOrder": [2, "true"]}, - "稀音":{"ExhaustRequire": True,"ArrangeOrder":[2,"true"],"RestInFull": True}, - "巫恋":{"ArrangeOrder":[2,"true"]}, - "柏喙":{"ExhaustRequire": True,"ArrangeOrder":[2,"true"]}, - "龙舌兰":{"ArrangeOrder":[2,"true"]}, - "空弦":{"ArrangeOrder":[2,"true"],"RestingPriority": "low"}, - "伺夜":{"ArrangeOrder":[2,"true"]}, - "绮良":{"ArrangeOrder":[2,"true"]}, - "但书":{"ArrangeOrder":[2,"true"]}, - "泡泡":{"ArrangeOrder":[2,"true"]}, - "火神":{"ArrangeOrder":[2,"true"]}, - "黑键":{"ArrangeOrder":[2,"true"]}, - "波登可":{"ArrangeOrder":[ 2, "false" ]}, - "夜莺":{"ArrangeOrder":[ 2, "false" ]}, - "菲亚梅塔":{"ArrangeOrder":[ 2, "false" ]}, - "流明":{"ArrangeOrder":[ 2, "false" ]}, - "蜜莓":{"ArrangeOrder":[ 2, "false" ]}, - "闪灵":{"ArrangeOrder":[ 2, "false" ]}, - "杜林":{"ArrangeOrder":[ 2, "false" ]}, - "褐果":{"ArrangeOrder":[ 2, "false" ]}, - "车尔尼":{"ArrangeOrder":[ 2, "false" ]}, - "安比尔":{"ArrangeOrder":[ 2, "false" ]}, - "爱丽丝":{"ArrangeOrder":[ 2, "false" ]}, - "桃金娘":{"ArrangeOrder":[ 2, "false" ]}, + "Default": {"UpperLimit": 24, "LowerLimit": 0, "ExhaustRequire": False, "ArrangeOrder": [2, "false"], + "RestInFull": False}, + "琴柳": {"UpperLimit": 19, "LowerLimit": 13}, + "令": {"ArrangeOrder": [2, "true"]}, + "夕": {"UpperLimit": 6, "ArrangeOrder": [2, "true"]}, + "稀音": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"], "RestInFull": True}, + "巫恋": {"ArrangeOrder": [2, "true"]}, + "柏喙": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"]}, + "龙舌兰": {"ArrangeOrder": [2, "true"]}, + "空弦": {"ArrangeOrder": [2, "true"], "RestingPriority": "low"}, + "伺夜": {"ArrangeOrder": [2, "true"], "RestingPriority": "low"}, + "绮良": {"ArrangeOrder": [2, "true"]}, + "但书": {"ArrangeOrder": [2, "true"]}, + "泡泡": {"ArrangeOrder": [2, "true"]}, + "火神": {"ArrangeOrder": [2, "true"]}, + "黑键": {"ArrangeOrder": [2, "true"]}, + "波登可": {"ArrangeOrder": [2, "false"]}, + "夜莺": {"ArrangeOrder": [2, "false"]}, + "菲亚梅塔": {"ArrangeOrder": [2, "false"]}, + "流明": {"ArrangeOrder": [2, "false"]}, + "蜜莓": {"ArrangeOrder": [2, "false"]}, + "闪灵": {"ArrangeOrder": [2, "false"]}, + "杜林": {"ArrangeOrder": [2, "false"]}, + "褐果": {"ArrangeOrder": [2, "false"]}, + "车尔尼": {"ArrangeOrder": [2, "false"]}, + "安比尔": {"ArrangeOrder": [2, "false"]}, + "爱丽丝": {"ArrangeOrder": [2, "false"]}, + "桃金娘": {"ArrangeOrder": [2, "false"]}, "帕拉斯": {"RestingPriority": "low"}, "红云": {"RestingPriority": "low", "ArrangeOrder": [2, "true"]}, - "承曦格雷伊": {"ArrangeOrder": [2, "true"],"RestInFull": True}, + "承曦格雷伊": {"ArrangeOrder": [2, "true"], "RestInFull": True}, "乌有": {"ArrangeOrder": [2, "true"], "RestingPriority": "low"}, "图耶": {"ArrangeOrder": [2, "true"]}, "鸿雪": {"ArrangeOrder": [2, "true"]}, @@ -256,6 +255,7 @@ def inialize(tasks, scheduler=None): base_scheduler.drone_execution_gap = drone_execution_gap base_scheduler.agent_base_config = agent_base_config base_scheduler.run_order_delay = 10 # 跑单提前10分钟运行 + base_scheduler.reload_room = reload_room return base_scheduler else: scheduler.device = cli.device @@ -285,17 +285,21 @@ def simulate(): # 如果任务间隔时间超过9分钟则启动MAA if sleep_time > 540: base_scheduler.maa_plan_solver() - elif sleep_time > 0 : time.sleep(sleep_time) + elif sleep_time > 0: + time.sleep(sleep_time) + if 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': + base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) + del base_scheduler.tasks[0] base_scheduler.run() reconnect_tries = 0 except ConnectionError as e: - reconnect_tries +=1 + reconnect_tries += 1 if reconnect_tries < reconnect_max_tries: logger.warning(f'连接端口断开....正在重连....') connected = False while not connected: try: - base_scheduler = inialize([],base_scheduler) + base_scheduler = inialize([], base_scheduler) break except Exception as ce: logger.error(ce) From 7050e6b25f91e59e50c48ade567cba58a80100ec Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 24 Apr 2023 00:32:47 -0700 Subject: [PATCH 19/49] =?UTF-8?q?feat:=20=E6=90=93=E7=8E=89=E8=A1=A5?= =?UTF-8?q?=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index ee9f51ab0..2b8f7292e 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -1588,6 +1588,14 @@ def reload(self): for room in self.reload_room: try: self.enter_room(room) + self.tap((self.recog.w * 0.05, self.recog.h * 0.95), interval=0.5) + # 补货 + self.tap((self.recog.w * 0.75, self.recog.h * 0.3), interval=0.5) + self.tap((self.recog.w * 0.75, self.recog.h * 0.9), interval=0.5) + while self.get_infra_scene() == Scene.CONNECTING: + self.sleep(2) + self.back() + self.back() except Exception as e: logger.error(e) error = True From 25be7bc53422f87abd9618d21dca0b9f190e13a3 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 24 Apr 2023 00:46:40 -0700 Subject: [PATCH 20/49] =?UTF-8?q?UI=5Ffeat:=20=E6=90=93=E7=8E=89=E8=A1=A5?= =?UTF-8?q?=E8=B4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 5 +++++ menu.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index f8abfa72e..a8d99056e 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -106,6 +106,7 @@ def inialize(tasks, scheduler=None): base_scheduler.ADB_CONNECT = config.ADB_CONNECT[0] base_scheduler.error = False base_scheduler.drone_room = None if conf['drone_room'] == '' else conf['drone_room'] + base_scheduler.reload_room = list(filter(None, conf['reload_room'].replace(',', ',').split(','))) base_scheduler.drone_execution_gap = 4 base_scheduler.run_order_delay = conf['run_order_delay'] base_scheduler.agent_base_config = agent_base_config @@ -147,6 +148,10 @@ def simulate(): logger.info(subject) base_scheduler.send_email(context, subject) time.sleep(sleep_time) + if 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': + logger.info(f"开始执行 MAA {base_scheduler.tasks[0]['type'].split('_')[1]} 任务") + base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) + del base_scheduler.tasks[0] base_scheduler.run() reconnect_tries = 0 except ConnectionError as e: diff --git a/menu.py b/menu.py index 6aaad4288..80477e274 100644 --- a/menu.py +++ b/menu.py @@ -60,6 +60,7 @@ def load_conf(): conf['drone_count_limit'] = conf['drone_count_limit'] if 'drone_count_limit' in conf.keys() else 92 # 无人机阈值 conf['run_order_delay'] = conf['run_order_delay'] if 'run_order_delay' in conf.keys() else 10 # 跑单提前10分钟运行 conf['drone_room'] = conf['drone_room'] if 'drone_room' in conf.keys() else '' # 无人机使用房间 + conf['reload_room'] = conf['reload_room'] if 'reload_room' in conf.keys() else '' # 搓玉补货房间 conf['enable_party'] = conf['enable_party'] if 'enable_party' in conf.keys() else 1 # 是否启用收取线索 @@ -205,8 +206,11 @@ def menu(): run_order_delay = sg.InputText(conf['run_order_delay'], size=5, key='int_run_order_delay', enable_events=True) drone_room_title = sg.Text('无人机使用房间(room_X_X):', size=25, key='drone_room_title') + reload_room_title = sg.Text('搓玉补货房间(逗号分隔房间名):', size=25, key='reload_room_title') drone_room = sg.InputText(conf['drone_room'], size=15, key='conf_drone_room', enable_events=True) + reload_room = sg.InputText(conf['reload_room'], size=30, + key='conf_reload_room', enable_events=True) rest_in_full_title = sg.Text('需要回满心情的干员:', size=25) rest_in_full = sg.InputText(conf['rest_in_full'], size=60, key='conf_rest_in_full', enable_events=True) @@ -273,6 +277,7 @@ def menu(): [enable_party_title,enable_party_1,enable_party_0], [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title,run_order_delay], [drone_room_title, drone_room, sg.Text('', size=7), drone_count_limit_title,drone_count_limit], + [reload_room_title, reload_room], [rest_in_full_title, rest_in_full], [exhaust_require_title, exhaust_require], [resting_priority_title, resting_priority], From cbcf7c79af42e6210aaf1ce2e5b96d6ebb4ecb5c Mon Sep 17 00:00:00 2001 From: Luowen <1048879349@qq.com> Date: Tue, 25 Apr 2023 09:05:20 +0800 Subject: [PATCH 21/49] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E8=B6=8A=E7=95=8C=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 2 +- diy.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index a8d99056e..f2118cfc2 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -148,7 +148,7 @@ def simulate(): logger.info(subject) base_scheduler.send_email(context, subject) time.sleep(sleep_time) - if 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': + if len(base_scheduler.tasks) > 0 and 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': logger.info(f"开始执行 MAA {base_scheduler.tasks[0]['type'].split('_')[1]} 任务") base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) del base_scheduler.tasks[0] diff --git a/diy.py b/diy.py index a01a3ff0c..d647c9405 100644 --- a/diy.py +++ b/diy.py @@ -287,7 +287,7 @@ def simulate(): base_scheduler.maa_plan_solver() elif sleep_time > 0: time.sleep(sleep_time) - if 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': + if len(base_scheduler.tasks) > 0 and 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) del base_scheduler.tasks[0] base_scheduler.run() From 79073d461ed58b5ac73ea36ee577761ad638c7fa Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Tue, 25 Apr 2023 02:34:09 -0700 Subject: [PATCH 22/49] =?UTF-8?q?fix:=20=E5=AE=89=E6=8E=92=E5=90=8C?= =?UTF-8?q?=E7=BB=84=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 2b8f7292e..bb7457088 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -602,7 +602,7 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) else: _high += 1 # 排序 - agents.sort(key=lambda x: self.op_data.operators[x].mood) + agents.sort(key=lambda x: self.op_data.operators[x].mood- self.op_data.operators[x].lower_limit, reverse=False) # 进行位置数量的初步判定 # 对于252可能需要进行额外判定,由于 low_free 性质等同于 high_free success = True From a74af6a09f059e2cd3e50e06fff58157888239f7 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Thu, 27 Apr 2023 17:56:09 -0700 Subject: [PATCH 23/49] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E5=BF=83=E6=83=85?= =?UTF-8?q?=E8=A1=B0=E5=BC=B1=E6=95=88=E7=8E=87=E8=AE=A1=E7=AE=97+?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=8B=90=E8=AE=BE=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 12 +++--- arknights_mower/solvers/base_schedule.py | 38 ++++++++++++++-- arknights_mower/utils/operators.py | 55 +++++++++++++++--------- diy.py | 8 ++-- 4 files changed, 80 insertions(+), 33 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index f2118cfc2..4789f19c5 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -24,19 +24,19 @@ def main(c, p, child_conn): 'package_type'] == 1 else 'com.hypergryph.arknights.bilibili' # 服务器 init_fhlr(child_conn) if conf['ling_xi'] == 1: - agent_base_config['令']['UpperLimit'] = 11 + agent_base_config['令']['UpperLimit'] = 12 assist = '夕' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] if assist in agent_base_config.keys(): - agent_base_config[assist]['LowerLimit'] = 13 + agent_base_config[assist]['LowerLimit'] = 12 else: - agent_base_config[assist] = {'LowerLimit':13} + agent_base_config[assist] = {'LowerLimit':12} elif conf['ling_xi'] == 2: - agent_base_config['夕']['UpperLimit'] = 11 + agent_base_config['夕']['UpperLimit'] = 12 assist = '令' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] if assist in agent_base_config.keys(): - agent_base_config[assist]['LowerLimit'] = 13 + agent_base_config[assist]['LowerLimit'] = 12 else: - agent_base_config[assist] = {'LowerLimit':13} + agent_base_config[assist] = {'LowerLimit':12} for key in list(filter(None, conf['rest_in_full'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestInFull'] = True diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index bb7457088..3f82fa82f 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -1387,6 +1387,37 @@ def swipe_left(self, right_swipe, w, h): self.swipe_only((w // 2, h // 2), (w // 2, 0), interval=0.5) return 0 + def read_accurate_mood(self,img, cord): + try: + img = img[cord[1]:cord[3], cord[0]:cord[2]] + # Convert the image to grayscale + gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + + blurred_image = cv2.GaussianBlur(gray_image, (5, 5), 0) + + # Threshold the image to isolate the progress bar region + contours, hierarchy = cv2.findContours(blurred_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + # Calculate the bounding box of the progress bar + x, y, w, h = cv2.boundingRect(contours[0]) + + # Crop the progress bar region + progress_bar = img[y:y + h, x:x + w] + + # Convert the progress bar to grayscale + gray_pb = cv2.cvtColor(progress_bar, cv2.COLOR_BGR2GRAY) + + # Threshold the progress bar to isolate the gray fill + ret, thresh_pb = cv2.threshold(gray_pb, 137, 255, cv2.THRESH_BINARY) + + # Calculate the ratio of colored pixels to the total number of pixels in the progress bar region + total_pixels = w * h + colored_pixels = cv2.countNonZero(thresh_pb) + return colored_pixels / total_pixels * 24 + + except Exception: + return 24 + def get_agent_from_room(self, room, read_time_index=None): if read_time_index is None: read_time_index = [] @@ -1405,8 +1436,8 @@ def get_agent_from_room(self, room, read_time_index=None): ((1460, 560), (1700, 610)), ((1460, 775), (1700, 820))] time_p = [((1650, 270, 1780, 305)), ((1650, 480, 1780, 515)), ((1650, 690, 1780, 725)), ((1650, 665, 1780, 700)), ((1650, 875, 1780, 910))] - mood_p = [((1685, 213, 1780, 256)), ((1685, 422, 1780, 465)), ((1685, 632, 1780, 675)), - ((1685, 612, 1780, 655)), ((1685, 822, 1780, 865))] + mood_p = [((1470, 219, 1780, 221)), ((1470, 428, 1780, 430)), ((1470, 637, 1780, 639)), + ((1470, 615, 1780, 617)), ((1470, 823, 1780, 825))] result = [] swiped = False for i in range(0, length): @@ -1432,11 +1463,12 @@ def get_agent_from_room(self, room, read_time_index=None): self.op_data.add(Operator(_name, "")) update_time=False if self.op_data.operators[_name].need_to_refresh(): - _mood = self.read_screen(self.recog.img, cord=mood_p[i], change_color=True) + _mood = self.read_accurate_mood(self.recog.img, cord=mood_p[i]) update_time = True else: _mood = self.op_data.operators[_name].mood high_no_time = self.op_data.update_detail(_name, _mood, room, i,update_time) + data['depletion_rate'] = self.op_data.operators[_name].depletion_rate if high_no_time is not None: logger.debug(f"检测到高效组休息时间数据不存在:{room},{high_no_time}") read_time_index.append(high_no_time) diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 3db7f20f1..589adfb4f 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -11,7 +11,7 @@ class Operators(object): dorm = [] max_resting_count = 4 - def __init__(self, config,max_resting_count): + def __init__(self, config, max_resting_count): self.config = config self.operators = {} self.groups = {} @@ -20,13 +20,16 @@ def __init__(self, config,max_resting_count): self.dorm = [] self.max_resting_count = max_resting_count - def update_detail(self,name, mood, current_room, current_index,update_time = False): + def update_detail(self, name, mood, current_room, current_index, update_time=False): agent = self.operators[name] if update_time: + if agent.time_stamp is not None and agent.mood > mood: + agent.depletion_rate = 0 - (agent.mood - mood) * 3600 / ( + (datetime.now() - agent.time_stamp).total_seconds()) agent.time_stamp = datetime.now() # 如果移出宿舍,则清除对应宿舍数据 且重新记录高效组心情 if agent.current_room.startswith('dorm') and not current_room.startswith('dorm') and agent.is_high(): - self.refresh_dorm_time(agent.current_room,agent.current_index,{'agent':''}) + self.refresh_dorm_time(agent.current_room, agent.current_index, {'agent': ''}) agent.time_stamp = None if self.get_dorm_by_name(name)[0] is not None and not current_room.startswith('dorm') and agent.is_high(): _dorm = self.get_dorm_by_name(name)[1] @@ -41,7 +44,7 @@ def update_detail(self,name, mood, current_room, current_index,update_time = Fal if dorm.position[0] == current_room and dorm.position[1] == current_index and dorm.time is None: return current_index - def refresh_dorm_time(self,room,index, agent): + def refresh_dorm_time(self, room, index, agent): for idx, dorm in enumerate(self.dorm): # Filter out resting priority low # if idx >= self.max_resting_count: @@ -51,30 +54,38 @@ def refresh_dorm_time(self,room,index, agent): _name = agent['agent'] if _name in self.operators.keys() and self.operators[_name].is_high(): dorm.name = _name - dorm.time = agent['time'] + _agent = self.operators[_name] + # 如果干员有心情上限,则按比例修改休息时间 + if _agent.mood != 24: + sec_remaining = (_agent.upper_limit - _agent.mood) * ( + (agent['time'] - _agent.time_stamp).total_seconds()) / (24 - _agent.mood) + dorm.time = _agent.time_stamp + timedelta(seconds=sec_remaining) + else: + dorm.time = agent['time'] else: dorm.name = '' dorm.time = None break - def get_refresh_index(self,room,plan): + def get_refresh_index(self, room, plan): ret = [] for idx, dorm in enumerate(self.dorm): # Filter out resting priority low if idx >= self.max_resting_count: break if dorm.position[0] == room: - for i,_name in enumerate(plan): - if _name in self.operators.keys() and self.operators[_name].is_high() and self.operators[_name].resting_priority=='high' and not self.operators[_name].room.startswith('dorm'): + for i, _name in enumerate(plan): + if _name in self.operators.keys() and self.operators[_name].is_high() and self.operators[ + _name].resting_priority == 'high' and not self.operators[_name].room.startswith('dorm'): ret.append(i) break return ret - def get_dorm_by_name(self,name): + def get_dorm_by_name(self, name): for idx, dorm in enumerate(self.dorm): if dorm.name == name: return idx, dorm - return None,None + return None, None def add(self, operator): if operator.name not in agent_list: @@ -108,7 +119,7 @@ def available_free(self, free_type='high', count=4): if free_type == 'high': idx = 0 for dorm in self.dorm: - if dorm.name =='' or (dorm.name in self.operators.keys() and not self.operators[dorm.name].is_high()): + if dorm.name == '' or (dorm.name in self.operators.keys() and not self.operators[dorm.name].is_high()): ret += 1 if idx == count - 1: break @@ -118,7 +129,7 @@ def available_free(self, free_type='high', count=4): idx = -1 while idx < 0: dorm = self.dorm[idx] - if dorm.name =='' or (dorm.name in self.operators.keys() and not self.operators[dorm.name].is_high()): + if dorm.name == '' or (dorm.name in self.operators.keys() and not self.operators[dorm.name].is_high()): ret += 1 if idx == count - len(self.dorm): break @@ -126,15 +137,16 @@ def available_free(self, free_type='high', count=4): idx -= 1 return ret - def assign_dorm(self,name): - is_high = self.operators[name].resting_priority=='high' + def assign_dorm(self, name): + is_high = self.operators[name].resting_priority == 'high' if is_high: - _room = next(obj for obj in self.dorm if obj.name not in self.operators.keys() or not self.operators[obj.name].is_high()) + _room = next(obj for obj in self.dorm if + obj.name not in self.operators.keys() or not self.operators[obj.name].is_high()) else: _room = None idx = -1 while idx < 0: - if self.dorm[idx].name=='': + if self.dorm[idx].name == '': _room = self.dorm[idx] break else: @@ -147,8 +159,8 @@ def print(self): op = [] dorm = [] for k, v in self.operators.items(): - op.append("'"+k+"': "+ str(vars(v))) - ret += "'operators': {" + ','.join(op)+"}," + op.append("'" + k + "': " + str(vars(v))) + ret += "'operators': {" + ','.join(op) + "}," for v in self.dorm: dorm.append(str(vars(v))) ret += "'dorms': [" + ','.join(dorm) + "]}" @@ -165,6 +177,7 @@ def __init__(self, position, name='', time=None): class Operator(object): time_stamp = None + depletion_rate = 0 def __init__(self, name, room, index=-1, group='', replacement=[], resting_priority='low', current_room='', exhaust_require=False, @@ -185,15 +198,17 @@ def __init__(self, name, room, index=-1, group='', replacement=[], resting_prior self.mood = mood self.current_index = current_index self.lower_limit = lower_limit + self.depletion_rate = 0 def is_high(self): - return self.operator_type =='high' + return self.operator_type == 'high' def need_to_refresh(self, h=2): # 是否需要读取心情 if self.operator_type == 'high': if self.time_stamp is None or ( - self.time_stamp is not None and self.time_stamp + timedelta(hours=h) < datetime.now()): + self.time_stamp is not None and self.time_stamp + timedelta(hours=h) < datetime.now()) or ( + self.current_room.startswith("dorm") and not self.room.startswith("dorm")): return True return False diff --git a/diy.py b/diy.py index d647c9405..70585d4ed 100644 --- a/diy.py +++ b/diy.py @@ -158,9 +158,8 @@ agent_base_config = { "Default": {"UpperLimit": 24, "LowerLimit": 0, "ExhaustRequire": False, "ArrangeOrder": [2, "false"], "RestInFull": False}, - "琴柳": {"UpperLimit": 19, "LowerLimit": 13}, - "令": {"ArrangeOrder": [2, "true"]}, - "夕": {"UpperLimit": 6, "ArrangeOrder": [2, "true"]}, + "令": {"LowerLimit": 12,"ArrangeOrder": [2, "true"]}, + "夕": {"UpperLimit": 12, "ArrangeOrder": [2, "true"]}, "稀音": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"], "RestInFull": True}, "巫恋": {"ArrangeOrder": [2, "true"]}, "柏喙": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"]}, @@ -199,6 +198,7 @@ "坚雷": {"ArrangeOrder": [2, "true"]}, "年": {"RestingPriority": "low"}, "伊内丝": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"], "RestInFull": True}, + "铅踝":{"LowerLimit": 8,"UpperLimit": 12}, } @@ -216,7 +216,7 @@ def savelog(): ''' config.LOGFILE_PATH = './log' config.SCREENSHOT_PATH = './screenshot' - config.SCREENSHOT_MAXNUM = 1000 + config.SCREENSHOT_MAXNUM = 30 config.ADB_DEVICE = maa_config['maa_adb'] config.ADB_CONNECT = maa_config['maa_adb'] config.MAX_RETRYTIME = 10 From a1b03c7a688e3170694c7d5ce4fdab4ef56ec290 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Thu, 27 Apr 2023 19:52:55 -0700 Subject: [PATCH 24/49] =?UTF-8?q?update:=20=E7=94=A8=E5=B0=BD=E5=BF=83?= =?UTF-8?q?=E6=83=85=E7=BB=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 17 ++++++++--------- arknights_mower/utils/operators.py | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 3f82fa82f..100e0bf15 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -505,7 +505,7 @@ def plan_solver(self): # 根据剩余心情排序 self.total_agent = list( v for k, v in self.op_data.operators.items() if v.is_high() and not v.room.startswith('dorm')) - self.total_agent.sort(key=lambda x: x.mood - x.lower_limit, reverse=False) + self.total_agent.sort(key=lambda x: x.mood, reverse=False) # 目前有换班的计划后面改 logger.debug(f'当前基地数据--> {self.total_agent}') fia_plan, fia_room = self.check_fia() @@ -525,6 +525,8 @@ def plan_solver(self): next(obj for obj in self.total_agent if obj.name in fia_plan).name, "菲亚梅塔"]}}) try: + # 重新排序 + self.total_agent.sort(key=lambda x: x.mood - x.lower_limit, reverse=False) # 自动生成任务 self.plan_metadata() # 剩余高效组位置 @@ -546,7 +548,7 @@ def plan_solver(self): if op.mood > int((op.upper_limit - op.lower_limit) * self.resting_treshhold + op.lower_limit): continue if op.name in self.op_data.exhaust_agent: - if op.mood <= 0: + if op.mood <= 2: if next((e for e in self.tasks if 'type' in e.keys() and op.name in e['type']), None) is None: self.enter_room(op.current_room) @@ -554,18 +556,15 @@ def plan_solver(self): _time = datetime.now() if result[op.current_index]['time'] is not None: _time = result[op.current_index]['time'] + elif op.mood != 0.0: + _time = datetime.now() + timedelta( + hours=op.mood / op.depletion_rate) - timedelta(minutes=10) self.back() # plan 是空的是因为得动态生成 exhaust_type = op.name if op.group != '': exhaust_type = ','.join(self.op_data.groups[op.group]) - if _time0: - continue - elif _time >= datetime.now() or (_time mood: - agent.depletion_rate = 0 - (agent.mood - mood) * 3600 / ( + agent.depletion_rate = (agent.mood - mood) * 3600 / ( (datetime.now() - agent.time_stamp).total_seconds()) agent.time_stamp = datetime.now() # 如果移出宿舍,则清除对应宿舍数据 且重新记录高效组心情 From 03a6009b19ea78cd32cb2ba57ec7c70293257f61 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Thu, 27 Apr 2023 22:32:29 -0700 Subject: [PATCH 25/49] =?UTF-8?q?add:=E4=B8=8D=E8=B7=91=E5=8D=953=E5=B0=8F?= =?UTF-8?q?=E6=97=B6=E5=88=B7=E6=96=B0=E5=9F=BA=E5=9C=B0=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E9=93=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 1 + arknights_mower/solvers/base_schedule.py | 5 +++-- diy.py | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 4789f19c5..c20447467 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -152,6 +152,7 @@ def simulate(): logger.info(f"开始执行 MAA {base_scheduler.tasks[0]['type'].split('_')[1]} 任务") base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) del base_scheduler.tasks[0] + continue base_scheduler.run() reconnect_tries = 0 except ConnectionError as e: diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 100e0bf15..40f0b0c7f 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -203,13 +203,11 @@ def overtake_room(self): return def handle_error(self, force=False): - # 如果有任何报错,则生成一个空 if self.scene() == Scene.UNKNOWN: self.device.exit(self.package_name) if self.error or force: # 如果没有任何时间小于当前时间的任务才生成空任务 if (next((e for e in self.tasks if e['time'] < datetime.now()), None)) is None: - room = next(iter(self.currentPlan.keys())) logger.debug("由于出现错误情况,生成一次空任务来执行纠错") self.tasks.append({'time': datetime.now(), 'plan': {}}) # 如果没有任何时间小于当前时间的任务-10分钟 则清空任务 @@ -217,6 +215,9 @@ def handle_error(self, force=False): logger.info("检测到执行超过10分钟的任务,清空全部任务") self.tasks = [] self.op_data = None + if (next((e for e in self.tasks if e['time'] < datetime.now()+timedelta(hours=3)), None)) is None: + logger.debug("2小时内没有其他任务,生成一个空任务") + self.tasks.append({'time': datetime.now()+timedelta(hours=3), 'plan': {}}) return True def plan_metadata(self): diff --git a/diy.py b/diy.py index 70585d4ed..9139559fd 100644 --- a/diy.py +++ b/diy.py @@ -290,6 +290,7 @@ def simulate(): if len(base_scheduler.tasks) > 0 and 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) del base_scheduler.tasks[0] + continue base_scheduler.run() reconnect_tries = 0 except ConnectionError as e: From bb60705cee0226f11eafbb6f29047fb8a3df77fb Mon Sep 17 00:00:00 2001 From: Luowen <1048879349@qq.com> Date: Fri, 28 Apr 2023 17:53:29 +0800 Subject: [PATCH 26/49] =?UTF-8?q?fix:=E5=B0=86=E9=9C=80=E8=A6=81=E7=9A=84?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E6=B7=BB=E5=8A=A0=E5=88=B0requirements?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 4dee94da6..e556977ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,6 @@ pandas==1.5.2 pyyaml==6.0 PySimpleGUI~=4.60.4 pytz~=2022.6 +ruamel.yaml==0.15.46 paddleocr==2.6.1.3 +paddlepaddle==2.4.2 From fc21210715731bac4fe5dde2d7b9bc32416a6e9d Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sat, 29 Apr 2023 18:55:25 -0700 Subject: [PATCH 27/49] =?UTF-8?q?add:diy=E5=85=B3=E9=97=AD=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=9F=BA=E5=9C=B0=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 73 ++++++++++++++---------- arknights_mower/utils/operators.py | 20 +++++-- diy.py | 35 ++++++++++-- 3 files changed, 88 insertions(+), 40 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 40f0b0c7f..5ff866ff0 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -60,12 +60,12 @@ def __init__(self, device: Device = None, recog: Recognizer = None) -> None: self.run_order_delay=10 self.enable_party = True self.digit_reader = DigitReader() + self.error = False def run(self) -> None: """ :param clue_collect: bool, 是否收取线索 """ - self.currentPlan = self.global_plan[self.global_plan["default"]] self.error = False self.handle_error(True) if len(self.tasks) > 0: @@ -77,7 +77,7 @@ def run(self) -> None: self.party_time = None self.todo_task = False self.planned = False - if self.op_data is None: + if self.op_data is None or self.op_data.operators is None: self.initialize_operators() return super().run() @@ -194,7 +194,7 @@ def overtake_room(self): plan = {} for room in rooms: if room not in plan.keys(): - plan[room] = [data["agent"] for data in self.currentPlan[room]] + plan[room] = [data["agent"] for data in self.current_plan[room]] if len(plan.keys()) > 0: self.tasks.append({'time': datetime.now(), 'plan': plan}) # 执行完提前换班任务再次执行本任务 @@ -214,10 +214,9 @@ def handle_error(self, force=False): if (next((e for e in self.tasks if e['time'] < datetime.now() - timedelta(seconds=600)), None)) is not None: logger.info("检测到执行超过10分钟的任务,清空全部任务") self.tasks = [] - self.op_data = None - if (next((e for e in self.tasks if e['time'] < datetime.now()+timedelta(hours=3)), None)) is None: - logger.debug("2小时内没有其他任务,生成一个空任务") - self.tasks.append({'time': datetime.now()+timedelta(hours=3), 'plan': {}}) + elif (next((e for e in self.tasks if e['time'] < datetime.now()+timedelta(hours=2.5)), None)) is None: + logger.debug("2.5小时内没有其他任务,生成一个空任务") + self.tasks.append({'time': datetime.now()+timedelta(hours=2.5), 'plan': {}}) return True def plan_metadata(self): @@ -237,6 +236,7 @@ def plan_metadata(self): short_rest= True low_priority = [] for idx, dorm in enumerate(self.op_data.dorm): + logger.debug(f'开始计算{dorm}') # Filter out resting priority low if idx >= self.max_resting_count: break @@ -271,13 +271,14 @@ def plan_metadata(self): planned_index.append(_idx) __room = self.op_data.operators[x].room if __room not in __plan.keys(): - __plan[__room] = ['Current'] * len(self.currentPlan[__room]) + __plan[__room] = ['Current'] * len(self.current_plan[__room]) __plan[__room][self.op_data.operators[x].index] = x if __time < datetime.now(): __time = datetime.now() self.tasks.append({"type": ','.join(__type), 'plan': __plan, 'time': __time}) # 如果非 rest in full, 则同组取时间最小值 else: if dorm.time is not None and dorm.time < _time: + logger.debug(f"更新任务时间{dorm.time}") _time = dorm.time __room = self.op_data.operators[_name].room __rest_agent = [] @@ -285,12 +286,13 @@ def plan_metadata(self): __rest_agent.append(_name) else: __rest_agent.extend(self.op_data.groups[self.op_data.operators[_name].group]) + logger.debug(f"小组分组为{__rest_agent}") for x in __rest_agent: if x in low_priority: continue __room = self.op_data.operators[x].room if __room not in _plan.keys(): - _plan[__room] = ['Current'] * len(self.currentPlan[__room]) + _plan[__room] = ['Current'] * len(self.current_plan[__room]) _plan[__room][self.op_data.operators[x].index] = x _dorm_idx, __dorm = self.op_data.get_dorm_by_name(x) if __dorm is not None: @@ -298,6 +300,7 @@ def plan_metadata(self): planned_index.append(_dorm_idx) if __dorm.time is not None and __dorm.time < _time and self.op_data.operators[ x].resting_priority == 'high': + logger.debug(f"更新任务时间{dorm.time}") _time = __dorm.time if x not in low_priority: low_priority.append(x) @@ -394,19 +397,19 @@ def agent_get_mood(self, skip_dorm=False, force=False): continue self.back() logger.debug(self.op_data.print()) - for room in self.currentPlan.keys(): - for idx, item in enumerate(self.currentPlan[room]): + for room in self.current_plan.keys(): + for idx, item in enumerate(self.current_plan[room]): _name = next((k for k, v in self.op_data.operators.items() if v.current_room == room and v.current_index == idx), None) if room not in self.current_base.keys(): - self.current_base[room] = [''] * len(self.currentPlan[room]) + self.current_base[room] = [''] * len(self.current_plan[room]) if _name is None or _name == '': self.current_base[room][idx] = {"agent": "", "mood": -1} else: self.current_base[room][idx] = {"mood": self.op_data.operators[_name].mood, "agent": _name} current_base = copy.deepcopy(self.current_base) - plan = self.currentPlan + plan = self.current_plan fix_plan = {} for key in current_base: if key == 'train': continue @@ -426,7 +429,7 @@ def agent_get_mood(self, skip_dorm=False, force=False): continue if not (_name == plan[key][idx]['agent'] or ( (_name in plan[key][idx]["replacement"]) and len(plan[key][idx]["replacement"]) > 0) or not - self.op_data.operators[_name].need_to_refresh(2.5)): + self.op_data.operators[_name].need_to_refresh(h=2.5)): if not need_fix: fix_plan[key] = ['Current'] * len(plan[key]) need_fix = True @@ -450,18 +453,18 @@ def agent_get_mood(self, skip_dorm=False, force=False): for a in agents: __agent = self.op_data.operators[a] if __agent.room not in fix_plan.keys(): - fix_plan[__agent.room] = ['Current'] * len(self.currentPlan[__agent.room]) + fix_plan[__agent.room] = ['Current'] * len(self.current_plan[__agent.room]) fix_plan[__agent.room][__agent.index] = a if _agent.room not in fix_plan.keys(): - fix_plan[_agent.room] = ['Current'] * len(self.currentPlan[_agent.room]) + fix_plan[_agent.room] = ['Current'] * len(self.current_plan[_agent.room]) fix_plan[_agent.room][_agent.index] = key # 如果是错位: if (_agent.current_index != -1 and _agent.current_index != _agent.index) or (_agent.current_room !=""and _agent.room != _agent.current_room): moved_room = _agent.current_room moved_index = _agent.current_index if moved_room not in fix_plan.keys(): - fix_plan[moved_room] = ['Current'] * len(self.currentPlan[moved_room]) - fix_plan[moved_room][moved_index] = self.currentPlan[moved_room][moved_index]["agent"] + fix_plan[moved_room] = ['Current'] * len(self.current_plan[moved_room]) + fix_plan[moved_room][moved_index] = self.current_plan[moved_room][moved_index]["agent"] if len(fix_plan.keys()) > 0: # 不能在房间里安排同一个人 如果有重复则换成Free # 还要修复确保同一组在同时上班 @@ -484,7 +487,7 @@ def agent_get_mood(self, skip_dorm=False, force=False): return "self_correction" def plan_solver(self): - plan = self.currentPlan + plan = self.current_plan # 如果下个 普通任务 <10 分钟则跳过 plan if ( next((e for e in self.tasks if e['time'] < datetime.now() + timedelta(seconds=600)), @@ -623,7 +626,7 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) if _rep is not None: __replacement.append(_rep) if x.room not in __plan.keys(): - __plan[x.room] = ['Current'] * len(self.currentPlan[x.room]) + __plan[x.room] = ['Current'] * len(self.current_plan[x.room]) __plan[x.room][x.index] = _rep else: success = False @@ -648,7 +651,7 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) return exist_replacement, plan, high_free - _high, low_free - _low def initialize_operators(self): - plan = self.currentPlan + plan = self.current_plan self.op_data = Operators(self.agent_base_config, self.max_resting_count) for room in plan.keys(): for idx, data in enumerate(plan[room]): @@ -681,7 +684,7 @@ def initialize_operators(self): def check_in_and_out(self): res = {} - for x, y in self.currentPlan.items(): + for x, y in self.current_plan.items(): if not x.startswith('room'): continue if any(('但书' in obj['replacement'] or '龙舌兰' in obj['replacement']) for obj in y): res[x] = y @@ -922,8 +925,13 @@ def clue(self) -> None: # 线索交流开启 if clue_unlock is not None and get_all_clue: self.tap(clue_unlock) - self.party_time = datetime.now() + timedelta(days=1) - logger.info("为期一天的impart开始") + self.party_time = self.double_read_time((1765, 422, 1920, 515)) + if self.party_time < datetime.now(): + logger.info(f"检测到impart开启失败!") + self.party_time = None + self.error = True + else: + logger.info("为期一天的impart开始") elif clue_unlock is None: # 记录趴体时间 self.back(interval=2) @@ -1429,7 +1437,7 @@ def get_agent_from_room(self, room, read_time_index=None): raise Exception('未成功进入房间') self.tap((self.recog.w * 0.05, self.recog.h * 0.4), interval=0.5) error_count += 1 - length = len(self.currentPlan[room]) + length = len(self.current_plan[room]) if length > 3: self.swipe((self.recog.w * 0.8, self.recog.h * 0.8), (0, self.recog.h * 0.4), interval=1, rebuild=True) name_p = [((1460, 155), (1700, 210)), ((1460, 370), (1700, 420)), ((1460, 585), (1700, 630)), @@ -1462,7 +1470,7 @@ def get_agent_from_room(self, room, read_time_index=None): if _name not in self.op_data.operators.keys() and _name in agent_list: self.op_data.add(Operator(_name, "")) update_time=False - if self.op_data.operators[_name].need_to_refresh(): + if self.op_data.operators[_name].need_to_refresh(r=room): _mood = self.read_accurate_mood(self.recog.img, cord=mood_p[i]) update_time = True else: @@ -1537,7 +1545,7 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): else: # 如果空房间或者名字错误,则使用default干员 plan[room][current_idx] = \ - self.currentPlan[room][current_idx]["agent"] + self.current_plan[room][current_idx]["agent"] while self.find('arrange_order_options') is None: if error_count > 3: raise Exception('未成功进入干员选择界面') @@ -1592,7 +1600,7 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): in_and_out_plan = [data["agent"] for data in self.current_base[room]] # 防止由于意外导致的死循环 if '但书' in in_and_out_plan or '龙舌兰' in in_and_out_plan: - in_and_out_plan = [data["agent"] for data in self.currentPlan[room]] + in_and_out_plan = [data["agent"] for data in self.current_plan[room]] replace_plan[room] = in_and_out_plan self.back(interval=0.5) self.back(interval=0.5) @@ -1602,7 +1610,7 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): replace_agent = fia_data[1] fia_change_room = self.op_data.operators[replace_agent].room fia_room_plan = [data["agent"] for data in self.current_base[fia_data[0]]] - fia_change_room_plan = ['Current'] * len(self.currentPlan[fia_change_room]) + fia_change_room_plan = ['Current'] * len(self.current_plan[fia_change_room]) fia_change_room_plan[self.op_data.operators[replace_agent].index] = replace_agent self.tasks.append( {'time': self.tasks[0]['time'], @@ -1796,7 +1804,12 @@ def maa_plan_solver(self,tasks ='All',one_time = False): logger.info(context) logger.info(subject) self.send_email(context, subject) - time.sleep(remaining_time) + if one_time: + if len(self.tasks)>0: + del self.tasks[0] + self.handle_error(True) + if remaining_time>0: + time.sleep(remaining_time) self.MAA = None except Exception as e: logger.error(e) diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 37eb73d7d..931459ea6 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -20,6 +20,9 @@ def __init__(self, config, max_resting_count): self.dorm = [] self.max_resting_count = max_resting_count + def __repr__(self): + return f'Operators(operators={self.operators})' + def update_detail(self, name, mood, current_room, current_index, update_time=False): agent = self.operators[name] if update_time: @@ -174,6 +177,8 @@ def __init__(self, position, name='', time=None): self.name = name self.time = time + def __repr__(self): + return f"Dormitory(position={self.position},name='{self.name}',time='{self.time}')" class Operator(object): time_stamp = None @@ -181,12 +186,11 @@ class Operator(object): def __init__(self, name, room, index=-1, group='', replacement=[], resting_priority='low', current_room='', exhaust_require=False, - mood=24, upper_limit=24, rest_in_full=False, current_index=-1, lower_limit=0, operator_type="low"): + mood=24, upper_limit=24, rest_in_full=False, current_index=-1, lower_limit=0, operator_type="low", + depletion_rate=0, time_stamp=None): self.name = name self.room = room self.operator_type = operator_type - # if room.startswith('dormitory'): - # self.operator_type = "low" self.index = index self.group = group self.replacement = replacement @@ -198,17 +202,18 @@ def __init__(self, name, room, index=-1, group='', replacement=[], resting_prior self.mood = mood self.current_index = current_index self.lower_limit = lower_limit - self.depletion_rate = 0 + self.depletion_rate = depletion_rate + self.time_stamp = time_stamp def is_high(self): return self.operator_type == 'high' - def need_to_refresh(self, h=2): + def need_to_refresh(self, h=2, r=""): # 是否需要读取心情 if self.operator_type == 'high': if self.time_stamp is None or ( self.time_stamp is not None and self.time_stamp + timedelta(hours=h) < datetime.now()) or ( - self.current_room.startswith("dorm") and not self.room.startswith("dorm")): + r.startswith("dorm") and not self.room.startswith("dorm")): return True return False @@ -221,3 +226,6 @@ def not_valid(self): return False return self.need_to_refresh(2.5) or self.current_room != self.room or self.index != self.current_index return False + + def __repr__(self): + return f"Operator(name='{self.name}', room='{self.room}', index={self.index}, group='{self.group}', replacement={self.replacement}, resting_priority='{self.resting_priority}', current_room='{self.current_room}',exhaust_require={self.exhaust_require},mood={self.mood}, upper_limit={self.upper_limit}, rest_in_full={self.rest_in_full}, current_index={self.current_index}, lower_limit={self.lower_limit}, operator_type='{self.operator_type}',depletion_rate={self.depletion_rate},time_stamp='{self.time_stamp}')" \ No newline at end of file diff --git a/diy.py b/diy.py index 9139559fd..be883b360 100644 --- a/diy.py +++ b/diy.py @@ -1,12 +1,15 @@ import time from datetime import datetime +import atexit +import json +import os from arknights_mower.solvers.base_schedule import BaseSchedulerSolver from arknights_mower.strategy import Solver from arknights_mower.utils.device import Device from arknights_mower.utils.log import logger, init_fhlr from arknights_mower.utils import config - +from arknights_mower.utils.operators import Operators, Operator email_config= { # 发信账户 @@ -62,6 +65,9 @@ reload_room = [] +# 基地数据json文件保存名 +state_file_name = 'state.json' + # 全自动基建排班计划: # 这里定义了一套全自动基建的排班计划 plan_1 # agent 为常驻高效组的干员名 @@ -236,12 +242,12 @@ def inialize(tasks, scheduler=None): base_scheduler.global_plan = plan base_scheduler.current_base = {} base_scheduler.resting = [] + base_scheduler.current_plan = base_scheduler.global_plan[base_scheduler.global_plan["default"]] # 同时休息最大人数 base_scheduler.max_resting_count = 4 base_scheduler.tasks = tasks # 读取心情开关,有菲亚梅塔或者希望全自动换班得设置为 true base_scheduler.read_mood = True - base_scheduler.scan_time = {} base_scheduler.last_room = '' base_scheduler.free_blacklist = free_blacklist base_scheduler.resting_treshhold = resting_treshhold @@ -263,17 +269,38 @@ def inialize(tasks, scheduler=None): scheduler.handle_error(True) return scheduler +def save_state(): + with open(state_file_name, 'w') as f: + if base_scheduler is not None and base_scheduler.op_data is not None: + json.dump(vars(base_scheduler.op_data), f, default=str) + +def load_state(): + if not os.path.exists(state_file_name): + return None + + with open(state_file_name, 'r') as f: + state = json.load(f) + operators = {k: eval(v) for k, v in state['operators'].items()} + for k,v in operators.items(): + if not v.time_stamp=='None': + v.time_stamp = datetime.strptime(v.time_stamp, '%Y-%m-%d %H:%M:%S.%f') + else: + v.time_stamp = None + return operators + def simulate(): ''' 具体调用方法可见各个函数的参数说明 ''' - global ope_list + global ope_list,base_scheduler # 第一次执行任务 # tasks = [{"plan": {'room_1_1': ['能天使','但书','龙舌兰']}, "time": datetime.now()}] tasks =[] reconnect_max_tries = 10 reconnect_tries = 0 base_scheduler = inialize(tasks) + base_scheduler.initialize_operators() + base_scheduler.op_data.operators = load_state() while True: try: @@ -289,7 +316,6 @@ def simulate(): time.sleep(sleep_time) if len(base_scheduler.tasks) > 0 and 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) - del base_scheduler.tasks[0] continue base_scheduler.run() reconnect_tries = 0 @@ -319,5 +345,6 @@ def simulate(): # debuglog() +atexit.register(save_state) savelog() simulate() From 347ebaaa44459b84aeed09d73307dc1ac7e6158d Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 1 May 2023 21:59:03 -0700 Subject: [PATCH 28/49] =?UTF-8?q?add:agent=20data=20&=20=E7=AD=BE=E5=88=B0?= =?UTF-8?q?=E5=AF=BC=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/data/agent.json | 6 +++++- arknights_mower/data/scene.json | 4 ++++ arknights_mower/resources/check_in.png | Bin 0 -> 8502 bytes arknights_mower/utils/recognize.py | 2 ++ arknights_mower/utils/solver.py | 2 ++ 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 arknights_mower/resources/check_in.png diff --git a/arknights_mower/data/agent.json b/arknights_mower/data/agent.json index d322f2e6e..0da8c9479 100644 --- a/arknights_mower/data/agent.json +++ b/arknights_mower/data/agent.json @@ -274,5 +274,9 @@ "洋灰", "休谟斯", "摩根", - "U-Official" + "U-Official", + "缪尔赛思", + "霍尔海雅", + "淬羽赫默", + "玫拉" ] diff --git a/arknights_mower/data/scene.json b/arknights_mower/data/scene.json index 9dd47a732..a665d3704 100644 --- a/arknights_mower/data/scene.json +++ b/arknights_mower/data/scene.json @@ -95,6 +95,10 @@ "label": "CLOSE_MINE", "comment": "产业合作洽谈会" }, + "113": { + "label": "CHECK_IN", + "comment": "4周年签到" + }, "201": { "label": "INFRA_MAIN", "comment": "基建全局视角" diff --git a/arknights_mower/resources/check_in.png b/arknights_mower/resources/check_in.png new file mode 100644 index 0000000000000000000000000000000000000000..063c8e7019b01fc7fa0bd77f4769f7e5e555fdde GIT binary patch literal 8502 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 int: self.scene = Scene.NAVIGATION_BAR elif self.find('close_mine') is not None: self.scene = Scene.CLOSE_MINE + elif self.find('check_in') is not None: + self.scene = Scene.CHECK_IN elif self.find('materiel_ico') is not None: self.scene = Scene.MATERIEL elif self.find('read_mail') is not None: diff --git a/arknights_mower/utils/solver.py b/arknights_mower/utils/solver.py index 2ad143306..bbfb12fcd 100644 --- a/arknights_mower/utils/solver.py +++ b/arknights_mower/utils/solver.py @@ -263,6 +263,8 @@ def back_to_index(self): self.tap_element('nav_index') elif self.scene() == Scene.CLOSE_MINE: self.tap_element('close_mine') + elif self.scene() == Scene.CHECK_IN: + self.tap_element('check_in') elif self.scene() == Scene.ANNOUNCEMENT: self.tap(detector.announcement_close(self.recog.img)) elif self.scene() == Scene.MATERIEL: From b6a225b4ab324b4acfc0067e797f251bf0bd0a99 Mon Sep 17 00:00:00 2001 From: Ksnow <1048879349@qq.com> Date: Wed, 3 May 2023 03:33:22 +0800 Subject: [PATCH 29/49] =?UTF-8?q?feat:=E6=96=B0=E5=A2=9E=E5=BF=83=E6=83=85?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E8=AE=B0=E5=BD=95=20feat:=E5=B0=86=E9=83=A8?= =?UTF-8?q?=E5=88=86=E9=AB=98=E7=BA=A7=E8=AE=BE=E7=BD=AE=E7=A7=BB=E8=87=B3?= =?UTF-8?q?=E6=8E=92=E7=8F=AD=E8=A1=A8=20feat:=E4=BC=98=E5=8C=96=E6=8E=92?= =?UTF-8?q?=E7=8F=AD=E8=A1=A8=E5=92=8C=E9=85=8D=E7=BD=AE=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 89 +++++--- arknights_mower/solvers/base_schedule.py | 7 +- arknights_mower/templates/conf.yml | 44 ++++ arknights_mower/templates/plan.json | 12 ++ arknights_mower/utils/conf.py | 58 ++++++ arknights_mower/utils/log.py | 2 +- arknights_mower/utils/pipe.py | 15 ++ menu.py | 250 ++++++++++------------- 8 files changed, 309 insertions(+), 168 deletions(-) create mode 100644 arknights_mower/templates/conf.yml create mode 100644 arknights_mower/templates/plan.json create mode 100644 arknights_mower/utils/conf.py create mode 100644 arknights_mower/utils/pipe.py diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index c20447467..8a285829b 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -1,53 +1,65 @@ +import atexit +import os import time from datetime import datetime +from arknights_mower.utils.log import logger +import json + +from arknights_mower.utils.pipe import Pipe conf = {} plan = {} +operators = {} # 执行自动排班 -def main(c, p, child_conn): +def main(c, p, o={}, child_conn=None): __init_params__() - from arknights_mower.utils.log import logger, init_fhlr + from arknights_mower.utils.log import init_fhlr from arknights_mower.utils import config global plan global conf + global operators conf = c plan = p + operators = o config.LOGFILE_PATH = './log' config.SCREENSHOT_PATH = './screenshot' - config.SCREENSHOT_MAXNUM = 1000 + config.SCREENSHOT_MAXNUM = 50 config.ADB_DEVICE = [conf['adb']] config.ADB_CONNECT = [conf['adb']] config.ADB_CONNECT = [conf['adb']] config.APPNAME = 'com.hypergryph.arknights' if conf[ 'package_type'] == 1 else 'com.hypergryph.arknights.bilibili' # 服务器 init_fhlr(child_conn) - if conf['ling_xi'] == 1: + Pipe.conn = child_conn + if plan['conf']['ling_xi'] == 1: agent_base_config['令']['UpperLimit'] = 12 - assist = '夕' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] - if assist in agent_base_config.keys(): - agent_base_config[assist]['LowerLimit'] = 12 - else: - agent_base_config[assist] = {'LowerLimit':12} - elif conf['ling_xi'] == 2: + agent_base_config['夕']['LowerLimit'] = 12 + # assist = '夕' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] + # if assist in agent_base_config.keys(): + # agent_base_config[assist]['LowerLimit'] = 12 + # else: + # agent_base_config[assist] = {'LowerLimit':12} + elif plan['conf']['ling_xi'] == 2: agent_base_config['夕']['UpperLimit'] = 12 - assist = '令' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] - if assist in agent_base_config.keys(): - agent_base_config[assist]['LowerLimit'] = 12 - else: - agent_base_config[assist] = {'LowerLimit':12} - for key in list(filter(None, conf['rest_in_full'].replace(',', ',').split(','))): + agent_base_config['令']['LowerLimit'] = 12 + # assist = '令' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] + # if assist in agent_base_config.keys(): + # agent_base_config[assist]['LowerLimit'] = 12 + # else: + # agent_base_config[assist] = {'LowerLimit':12} + for key in list(filter(None, plan['conf']['rest_in_full'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestInFull'] = True else: agent_base_config[key] = {'RestInFull': True} - for key in list(filter(None, conf['exhaust_require'].replace(',', ',').split(','))): + for key in list(filter(None, plan['conf']['exhaust_require'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['ExhaustRequire'] = True else: agent_base_config[key] = {'ExhaustRequire': True} - for key in list(filter(None, conf['resting_priority'].replace(',', ',').split(','))): + for key in list(filter(None, plan['conf']['resting_priority'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestingPriority'] = 'low' else: @@ -58,7 +70,6 @@ def main(c, p, child_conn): def inialize(tasks, scheduler=None): - from arknights_mower.utils.log import logger from arknights_mower.solvers.base_schedule import BaseSchedulerSolver from arknights_mower.strategy import Solver from arknights_mower.utils.device import Device @@ -69,13 +80,16 @@ def inialize(tasks, scheduler=None): base_scheduler = BaseSchedulerSolver(cli.device, cli.recog) base_scheduler.operators = {} plan1 = {} - for key in plan: - plan1[key] = plan[key]['plans'] + for key in plan[plan['default']]: + plan1[key] = plan[plan['default']][key]['plans'] + plan[plan['default']] = plan1 + logger.debug(plan) base_scheduler.package_name = config.APPNAME # 服务器 - base_scheduler.global_plan = {'default': "plan_1", "plan_1": plan1} + base_scheduler.global_plan = plan + base_scheduler.current_plan = plan1 base_scheduler.current_base = {} base_scheduler.resting = [] - base_scheduler.max_resting_count = conf['max_resting_count'] + base_scheduler.max_resting_count = plan['conf']['max_resting_count'] base_scheduler.drone_count_limit = conf['drone_count_limit'] base_scheduler.tasks = tasks base_scheduler.enable_party = conf['enable_party'] == 1 # 是否使用线索 @@ -119,14 +133,17 @@ def inialize(tasks, scheduler=None): def simulate(): - from arknights_mower.utils.log import logger ''' 具体调用方法可见各个函数的参数说明 ''' tasks = [] reconnect_max_tries = 10 reconnect_tries = 0 + global base_scheduler base_scheduler = inialize(tasks) + base_scheduler.initialize_operators() + if operators != {}: + base_scheduler.op_data.operators = operators while True: try: if len(base_scheduler.tasks) > 0: @@ -175,6 +192,30 @@ def simulate(): logger.exception(f"程序出错--->{E}") +def save_state(op_data,file='state.json'): + if not os.path.exists('tmp'): + os.makedirs('tmp') + with open('tmp/' + file, 'w') as f: + if op_data is not None : + json.dump(vars(op_data), f, default=str) + + +def load_state(file='state.json'): + + if not os.path.exists('tmp/' + file): + return None + with open('tmp/' + file, 'r') as f: + state = json.load(f) + operators = {k: eval(v) for k, v in state['operators'].items()} + for k,v in operators.items(): + if not v.time_stamp == 'None': + v.time_stamp = datetime.strptime(v.time_stamp, '%Y-%m-%d %H:%M:%S.%f') + else: + v.time_stamp = None + logger.info("基建配置已加载!") + return operators + + agent_base_config = {} maa_config = {} diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 5ff866ff0..e1fcd1305 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -15,6 +15,7 @@ from ..utils import typealias as tp from ..utils.device import Device from ..utils.log import logger +from ..utils.pipe import push_operators from ..utils.recognize import RecognizeError, Recognizer, Scene from ..utils.solver import BaseSolver from ..utils.datetime import get_server_weekday @@ -1426,6 +1427,8 @@ def read_accurate_mood(self,img, cord): except Exception: return 24 + + @push_operators def get_agent_from_room(self, room, read_time_index=None): if read_time_index is None: read_time_index = [] @@ -1712,8 +1715,8 @@ def append_maa_task(self, type): credit_fight = True self.MAA.append_task('Mall', { 'shopping': True, - 'buy_first': ['龙门币', '赤金'], - 'blacklist': ['家具', '碳', '加急'], + 'buy_first': ['招聘许可'], + 'blacklist': ['家具', '碳', '加急许可'], 'credit_fight':credit_fight }) def maa_plan_solver(self,tasks ='All',one_time = False): diff --git a/arknights_mower/templates/conf.yml b/arknights_mower/templates/conf.yml new file mode 100644 index 000000000..9f7ccb79d --- /dev/null +++ b/arknights_mower/templates/conf.yml @@ -0,0 +1,44 @@ + +adb: 127.0.0.1:62001 +drone_count_limit: 92 +drone_room: '' +enable_party: 1 +exhaust_require: '' +free_blacklist: '' +ling_xi: 1 +maa_adb_path: D:\Program Files\Nox\bin\adb.exe +maa_enable: 0 +maa_path: D:\MAA-v4.13.0-win-x64 +maa_weekly_plan: + - medicine: 0 + stage: [''] + weekday: 周一 + - medicine: 0 + stage: [''] + weekday: 周二 + - medicine: 0 + stage: [''] + weekday: 周三 + - medicine: 0 + stage: [''] + weekday: 周四 + - medicine: 0 + stage: [''] + weekday: 周五 + - medicine: 0 + stage: [''] + weekday: 周六 + - medicine: 0 + stage: [''] + weekday: 周日 +mail_enable: 0 +account: '' +pass_code: '' +max_resting_count: 8 +package_type: 1 +planFile: ./plan.json +reload_room: '' +rest_in_full: '' +resting_priority: '' +run_mode: 1 +run_order_delay: 10 diff --git a/arknights_mower/templates/plan.json b/arknights_mower/templates/plan.json new file mode 100644 index 000000000..a40b23116 --- /dev/null +++ b/arknights_mower/templates/plan.json @@ -0,0 +1,12 @@ +{ + "default": "plan1", + "plan1": {}, + "conf": { + "ling_xi": 1, + "max_resting_count": 4, + "exhaust_require": "", + "rest_in_full": "", + "resting_priority": "" + } + +} diff --git a/arknights_mower/utils/conf.py b/arknights_mower/utils/conf.py new file mode 100644 index 000000000..cdebcf593 --- /dev/null +++ b/arknights_mower/utils/conf.py @@ -0,0 +1,58 @@ +import os +import json +from pathlib import Path +from ruamel import yaml +from .. import __rootdir__ + + +def __get_temp_conf(): + with Path(f'{__rootdir__}/templates/conf.yml').open('r', encoding='utf8') as f: + return yaml.load(f,Loader=yaml.Loader) + + +def save_conf(conf, path="./conf.yml"): + with Path(path).open('w', encoding='utf8') as f: + yaml.dump(conf, f, allow_unicode=True) + + +def load_conf(path="./conf.yml"): + temp_conf = __get_temp_conf() + if not os.path.isfile(path): + open(path, 'w') # 创建空配置文件 + save_conf(temp_conf, path) + return temp_conf + else: + with Path(path).open('r', encoding='utf8') as c: + conf = yaml.load(c, Loader=yaml.Loader) + if conf is None: + conf = {} + temp_conf.update(conf) + return temp_conf + + +def __get_temp_plan(): + with open(f'{__rootdir__}/templates/plan.json', 'r') as f: + return json.loads(f.read()) + + +def load_plan(path="./plan.json"): + temp_plan = __get_temp_plan() + if not os.path.isfile(path): + with open(path, 'w') as f: + json.dump(temp_plan, f) # 创建空json文件 + return temp_plan + with open(path, 'r', encoding='utf8') as fp: + plan = json.loads(fp.read()) + if 'conf' not in plan.keys(): # 兼容旧版本 + temp_plan['plan1'] = plan + return temp_plan + # 获取新版本的 + tmp = temp_plan['conf'] + tmp.update(plan['conf']) + plan['conf'] = tmp + return plan + + +def write_plan(plan, path="./plan.json"): + with open(path, 'w', encoding='utf8') as c: + json.dump(plan, c, ensure_ascii=False) diff --git a/arknights_mower/utils/log.py b/arknights_mower/utils/log.py index 20e627044..b6c892ff0 100644 --- a/arknights_mower/utils/log.py +++ b/arknights_mower/utils/log.py @@ -46,7 +46,7 @@ def __init__(self, pipe): def emit(self, record): record = f'{record.message}' - self.pipe.send(record) + self.pipe.send({'type':'log','data':record}) chlr = logging.StreamHandler(stream=sys.stdout) diff --git a/arknights_mower/utils/pipe.py b/arknights_mower/utils/pipe.py new file mode 100644 index 000000000..48853bcc9 --- /dev/null +++ b/arknights_mower/utils/pipe.py @@ -0,0 +1,15 @@ +def push_operators(func): + def func_dec(s,*args): + r=func(s,*args) + if Pipe is not None and Pipe.conn is not None: + print('发送数据') + print(s.op_data.operators) + Pipe.conn.send({'type':'operators','data':s.op_data.operators}) + return r + return func_dec + + +class Pipe: + conn = None + + diff --git a/menu.py b/menu.py index 80477e274..9fc98fbcd 100644 --- a/menu.py +++ b/menu.py @@ -1,116 +1,64 @@ -import importlib import json -import sys from multiprocessing import Pipe, Process, freeze_support import time import PySimpleGUI as sg import os from ruamel.yaml import YAML + +from arknights_mower.utils.conf import load_conf, save_conf, load_plan, write_plan from arknights_mower.utils.log import logger from arknights_mower.data import agent_list from arknights_mower.__main__ import main yaml = YAML() -confUrl = './conf.yml'; +# confUrl = './conf.yml' conf = {} plan = {} +current_plan = {} +operators = {} global window buffer = '' line = 0 half_line_index = 0 -# 读取写入配置文件 -def load_conf(): - global conf - global confUrl - if not os.path.isfile(confUrl): - open(confUrl, 'w') # 创建空配置文件 - else: - with open(confUrl, 'r', encoding='utf8') as c: - conf = yaml.load(c) - if conf is None: - conf = {} - conf['package_type'] = conf['package_type'] if 'package_type' in conf.keys() else 1 - conf['adb'] = conf['adb'] if 'adb' in conf.keys() else '' - conf['planFile'] = conf['planFile'] if 'planFile' in conf.keys() else './plan.json' # 默认排班表地址 - conf['free_blacklist'] = conf['free_blacklist'] if 'free_blacklist' in conf.keys() else '' - conf['run_mode'] = conf['run_mode'] if 'run_mode' in conf.keys() else 1 - conf['ling_xi'] = conf['ling_xi'] if 'ling_xi' in conf.keys() else 1 - conf['rest_in_full'] = conf['rest_in_full'] if 'rest_in_full' in conf.keys() else '' # 需回满心情的干员 - conf['exhaust_require'] = conf['exhaust_require'] if 'exhaust_require' in conf.keys() else '' # 需用尽心情的干员 - conf['resting_priority'] = conf['resting_priority'] if 'resting_priority' in conf.keys() else '' # 宿舍低优先级干员 - conf['ling_xi_assist'] = conf['ling_xi_assist'] if 'ling_xi_assist' in conf.keys() else '' # 协助令夕心情调配的干员 - conf['mail_enable'] = conf['mail_enable'] if 'mail_enable' in conf.keys() else 0 - conf['account'] = conf['account'] if 'account' in conf.keys() else '' - conf['pass_code'] = conf['pass_code'] if 'pass_code' in conf.keys() else '' - conf['maa_enable'] = conf['maa_enable'] if 'maa_enable' in conf.keys() else 0 - conf['maa_path'] = conf['maa_path'] if 'maa_path' in conf.keys() else '' - conf['maa_adb_path'] = conf['maa_adb_path'] if 'maa_adb_path' in conf.keys() else '' - conf['maa_weekly_plan'] = conf['maa_weekly_plan'] if 'maa_weekly_plan' in conf.keys() else [ - {"weekday": "周一", "stage": ['AP-5'], "medicine": 0}, - {"weekday": "周二", "stage": ['CE-6'], "medicine": 0}, - {"weekday": "周三", "stage": ['1-7'], "medicine": 0}, - {"weekday": "周四", "stage": ['AP-5'], "medicine": 0}, - {"weekday": "周五", "stage": ['1-7'], "medicine": 0}, - {"weekday": "周六", "stage": ['AP-5'], "medicine": 0}, - {"weekday": "周日", "stage": ['AP-5'], "medicine": 0} - ] - conf['max_resting_count'] = conf['max_resting_count'] if 'max_resting_count' in conf.keys() else 4 # 最大组人数 - conf['drone_count_limit'] = conf['drone_count_limit'] if 'drone_count_limit' in conf.keys() else 92 # 无人机阈值 - conf['run_order_delay'] = conf['run_order_delay'] if 'run_order_delay' in conf.keys() else 10 # 跑单提前10分钟运行 - conf['drone_room'] = conf['drone_room'] if 'drone_room' in conf.keys() else '' # 无人机使用房间 - conf['reload_room'] = conf['reload_room'] if 'reload_room' in conf.keys() else '' # 搓玉补货房间 - conf['enable_party'] = conf['enable_party'] if 'enable_party' in conf.keys() else 1 # 是否启用收取线索 - - -def write_conf(): - global conf - global confUrl - with open(confUrl, 'w', encoding='utf8') as c: - yaml.default_flow_style = False - yaml.dump(conf, c) - - -# 读取排班表 -def load_plan(url): +def build_plan(url): global plan - if not os.path.isfile(url): - with open(url, 'w') as f: - json.dump(plan, f) # 创建空json文件 - return + global current_plan try: - with open(url, 'r', encoding='utf8') as fp: - plan = json.loads(fp.read()) + plan = load_plan(url) + current_plan = plan[plan['default']] conf['planFile'] = url for i in range(1, 4): for j in range(1, 4): window[f'btn_room_{str(i)}_{str(j)}'].update('待建造', button_color=('white', '#4f4945')) - for key in plan: - if type(plan[key]).__name__ == 'list': # 兼容旧版格式 - plan[key] = {'plans': plan[key], 'name': ''} - elif plan[key]['name'] == '贸易站': + for key in current_plan: + if type(current_plan[key]).__name__ == 'list': # 兼容旧版格式 + current_plan[key] = {'plans': current_plan[key], 'name': ''} + elif current_plan[key]['name'] == '贸易站': window['btn_' + key].update('贸易站', button_color=('#4f4945', '#33ccff')) - elif plan[key]['name'] == '制造站': + elif current_plan[key]['name'] == '制造站': window['btn_' + key].update('制造站', button_color=('#4f4945', '#ffcc00')) - elif plan[key]['name'] == '发电站': + elif current_plan[key]['name'] == '发电站': window['btn_' + key].update('发电站', button_color=('#4f4945', '#ccff66')) + window['plan_radio_ling_xi_' + str(plan['conf']['ling_xi'])].update(True) + window['plan_int_max_resting_count'].update(plan['conf']['max_resting_count']) + window['plan_conf_exhaust_require'].update(plan['conf']['exhaust_require']) + window['plan_conf_rest_in_full'].update(plan['conf']['rest_in_full']) + window['plan_conf_resting_priority'].update(plan['conf']['resting_priority']) except Exception as e: logger.error(e) println('json格式错误!') -# 写入排班表 -def write_plan(): - with open(conf['planFile'], 'w', encoding='utf8') as c: - json.dump(plan, c, ensure_ascii=False) - - # 主页面 def menu(): global window global buffer - load_conf() + global conf + global plan + conf = load_conf() + plan = load_plan(conf['planFile']) sg.theme('LightBlue2') # --------主页 package_type_title = sg.Text('服务器:', size=10) @@ -173,7 +121,8 @@ def menu(): sg.InputText('', size=30, key='replacement' + str(i)) ]], key='setArea' + str(i), visible=False) setting_layout.append([set_area]) - setting_layout.append([sg.Button('保存', key='savePlan', visible=False),sg.Button('清空', key='clearPlan', visible=False)]) + setting_layout.append( + [sg.Button('保存', key='savePlan', visible=False), sg.Button('清空', key='clearPlan', visible=False)]) setting_area = sg.Column(setting_layout, element_justification="center", vertical_alignment="bottom", expand_x=True) @@ -185,20 +134,20 @@ def menu(): run_mode_2 = sg.Radio('仅跑单模式', 'run_mode', default=conf['run_mode'] == 2, key='radio_run_mode_2', enable_events=True) ling_xi_title = sg.Text('令夕模式(令夕上班时起作用):', size=25) - ling_xi_1 = sg.Radio('感知信息', 'ling_xi', default=conf['ling_xi'] == 1, - key='radio_ling_xi_1', enable_events=True) - ling_xi_2 = sg.Radio('人间烟火', 'ling_xi', default=conf['ling_xi'] == 2, - key='radio_ling_xi_2', enable_events=True) - ling_xi_3 = sg.Radio('均衡模式', 'ling_xi', default=conf['ling_xi'] == 3, - key='radio_ling_xi_3', enable_events=True) + ling_xi_1 = sg.Radio('感知信息', 'ling_xi', default=plan['conf']['ling_xi'] == 1, + key='plan_radio_ling_xi_1', enable_events=True) + ling_xi_2 = sg.Radio('人间烟火', 'ling_xi', default=plan['conf']['ling_xi'] == 2, + key='plan_radio_ling_xi_2', enable_events=True) + ling_xi_3 = sg.Radio('均衡模式', 'ling_xi', default=plan['conf']['ling_xi'] == 3, + key='plan_radio_ling_xi_3', enable_events=True) enable_party_title = sg.Text('线索收集:', size=25) enable_party_1 = sg.Radio('启用', 'enable_party', default=conf['enable_party'] == 1, - key='radio_enable_party_1', enable_events=True) + key='radio_enable_party_1', enable_events=True) enable_party_0 = sg.Radio('禁用', 'enable_party', default=conf['enable_party'] == 0, - key='radio_enable_party_0', enable_events=True) + key='radio_enable_party_0', enable_events=True) max_resting_count_title = sg.Text('最大组人数:', size=25, key='max_resting_count_title') - max_resting_count = sg.InputText(conf['max_resting_count'], size=5, - key='int_max_resting_count', enable_events=True) + max_resting_count = sg.InputText(plan['conf']['max_resting_count'], size=5, + key='plan_int_max_resting_count', enable_events=True) drone_count_limit_title = sg.Text('无人机使用阈值:', size=25, key='drone_count_limit_title') drone_count_limit = sg.InputText(conf['drone_count_limit'], size=5, key='int_drone_count_limit', enable_events=True) @@ -210,22 +159,21 @@ def menu(): drone_room = sg.InputText(conf['drone_room'], size=15, key='conf_drone_room', enable_events=True) reload_room = sg.InputText(conf['reload_room'], size=30, - key='conf_reload_room', enable_events=True) + key='conf_reload_room', enable_events=True) rest_in_full_title = sg.Text('需要回满心情的干员:', size=25) - rest_in_full = sg.InputText(conf['rest_in_full'], size=60, - key='conf_rest_in_full', enable_events=True) + rest_in_full = sg.InputText(plan['conf']['rest_in_full'], size=60, + key='plan_conf_rest_in_full', enable_events=True) exhaust_require_title = sg.Text('需用尽心情的干员:', size=25) - exhaust_require = sg.InputText(conf['exhaust_require'], size=60, - key='conf_exhaust_require', enable_events=True) + exhaust_require = sg.InputText(plan['conf']['exhaust_require'], size=60, + key='plan_conf_exhaust_require', enable_events=True) resting_priority_title = sg.Text('宿舍低优先级干员:', size=25) - resting_priority = sg.InputText(conf['resting_priority'], size=60, - key='conf_resting_priority', enable_events=True) - ling_xi_assist_title = sg.Text('协助令夕心情调配的干员:', size=25) - ling_xi_assist = sg.InputText(conf['ling_xi_assist'], size=60, - key='conf_ling_xi_assist', enable_events=True) - + resting_priority = sg.InputText(plan['conf']['resting_priority'], size=60, + key='plan_conf_resting_priority', enable_events=True) + # ling_xi_assist_title = sg.Text('协助令夕心情调配的干员:', size=25) + # ling_xi_assist = sg.InputText(conf['ling_xi_assist'], size=60, + # key='conf_ling_xi_assist', enable_events=True) # --------外部调用设置页面 # mail @@ -274,14 +222,16 @@ def menu(): plan_tab = sg.Tab(' 排班表 ', [[left_area, central_area, right_area], [setting_area]], element_justification="center") setting_tab = sg.Tab(' 高级设置 ', [[run_mode_title, run_mode_1, run_mode_2], [ling_xi_title, ling_xi_1, ling_xi_2, ling_xi_3], - [enable_party_title,enable_party_1,enable_party_0], - [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title,run_order_delay], - [drone_room_title, drone_room, sg.Text('', size=7), drone_count_limit_title,drone_count_limit], + [enable_party_title, enable_party_1, enable_party_0], + [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title, + run_order_delay], + [drone_room_title, drone_room, sg.Text('', size=7), drone_count_limit_title, + drone_count_limit], [reload_room_title, reload_room], [rest_in_full_title, rest_in_full], [exhaust_require_title, exhaust_require], [resting_priority_title, resting_priority], - [ling_xi_assist_title, ling_xi_assist] + # [ling_xi_assist_title, ling_xi_assist] 去除协助令夕心情调配项 ], pad=((10, 10), (10, 10))) other_tab = sg.Tab(' 外部调用 ', @@ -291,8 +241,7 @@ def menu(): selected_background_color='#d4dae8', background_color='#aab6d3', tab_background_color='#aab6d3')]], font='微软雅黑', finalize=True, resizable=False) - - load_plan(conf['planFile']) + build_plan(conf['planFile']) btn = None bind_scirpt() # 为基建布局左边的站点排序绑定事件 drag_task = DragTask() @@ -304,10 +253,23 @@ def menu(): run_script(event[:event.rindex('-')], drag_task) continue drag_task.clear() # 拖拽事件连续不间断,若未触发事件,则初始化 - if event.startswith('conf_'): # conf开头,为字符串输入的配置 + + if event.startswith('plan_conf_'): # plan_conf开头,为字符串输入的排班表配置 + key = event[10:] + plan['conf'][key] = window[event].get().strip() + elif event.startswith('plan_int_'): # plan_int开头,为数值型输入的配置 + key = event[9:] + try: + plan['conf'][key] = int(window[event].get().strip()) + except ValueError: + println(f'[{window[key + "_title"].get()}]需为数字') + elif event.startswith('plan_radio_'): + v_index = event.rindex('_') + plan['conf'][event[11:v_index]] = int(event[v_index + 1:]) + elif event.startswith('conf_'): # conf开头,为字符串输入的配置 key = event[5:] conf[key] = window[event].get().strip() - elif event.startswith('int_'): # int开头,为数值型输入的配置 + elif event.startswith('int_'): # int开头,为数值型输入的配置 key = event[4:] try: conf[key] = int(window[event].get().strip()) @@ -317,8 +279,8 @@ def menu(): v_index = event.rindex('_') conf[event[6:v_index]] = int(event[v_index + 1:]) elif event == 'planFile' and plan_file.get() != conf['planFile']: # 排班表 - write_plan() - load_plan(plan_file.get()) + write_plan(plan, conf['planFile']) + build_plan(plan_file.get()) plan_file.update(conf['planFile']) elif event.startswith('maa_weekly_plan_stage_'): # 关卡名 v_index = event.rindex('_') @@ -329,24 +291,26 @@ def menu(): elif event.startswith('btn_'): # 设施按钮 btn = event init_btn(event) - elif event.endswith('-agent_change'): #干员填写 + elif event.endswith('-agent_change'): # 干员填写 input_agent = window[event[:event.rindex('-')]].get().strip() - window[event[:event.rindex('-')]].update(value=input_agent,values=list(filter(lambda s:input_agent in s,['Free'] + agent_list))) + window[event[:event.rindex('-')]].update(value=input_agent, values=list( + filter(lambda s: input_agent in s, ['Free'] + agent_list))) elif event.startswith('agent'): input_agent = window[event].get().strip() - window[event].update(value=input_agent,values=list(filter(lambda s:input_agent in s,['Free'] + agent_list))) + window[event].update(value=input_agent, + values=list(filter(lambda s: input_agent in s, ['Free'] + agent_list))) elif event == 'savePlan': # 保存设施信息 save_btn(btn) - elif event == 'clearPlan': # 清空当前设施信息 + elif event == 'clearPlan': # 清空当前设施信息 clear_btn(btn) elif event == 'on': on_btn.update(visible=False) off_btn.update(visible=True) clear() parent_conn, child_conn = Pipe() - main_thread = Process(target=main, args=(conf, plan, child_conn), daemon=True) + main_thread = Process(target=main, args=(conf, plan,operators, child_conn), daemon=True) main_thread.start() - window.perform_long_operation(lambda: log(parent_conn), 'log') + window.perform_long_operation(lambda: recv(parent_conn),'recv') elif event == 'off': println('停止运行') child_conn.close() @@ -355,8 +319,8 @@ def menu(): off_btn.update(visible=False) window.close() - write_conf() - write_plan() + save_conf(conf) + write_plan(plan, conf['planFile']) def bind_scirpt(): @@ -378,38 +342,38 @@ def run_script(event, drag_task): drag_task.btn = event[:event.rindex('-')] # 记录初始按钮 drag_task.step = 1 # 初始化键位,并推进任务步骤 elif event.endswith('-ButtonRelease'): # 松开按钮事件,标志着拖拽结束 - if drag_task.step == 1 : + if drag_task.step == 1: drag_task.step = 2 # 推进任务步骤 elif event.endswith('-Enter'): # 进入元素事件,拖拽结束鼠标若在其他元素,会进入此事件 if drag_task.step == 2: drag_task.new_btn = event[:event.rindex('-')] # 记录需交换的按钮 - swtich_plan(drag_task) + switch_plan(drag_task) drag_task.clear() else: drag_task.clear() -def swtich_plan(drag_task): +def switch_plan(drag_task): key1 = drag_task.btn[4:] key2 = drag_task.new_btn[4:] - value1 = plan[key1] if key1 in plan else None; - value2 = plan[key2] if key2 in plan else None; + value1 = current_plan[key1] if key1 in current_plan else None; + value2 = current_plan[key2] if key2 in current_plan else None; if value1 is not None: - plan[key2] = value1 - elif key2 in plan: - plan.pop(key2) + current_plan[key2] = value1 + elif key2 in current_plan: + current_plan.pop(key2) if value2 is not None: - plan[key1] = value2 - elif key1 in plan: - plan.pop(key1) - write_plan() - load_plan(conf['planFile']) + current_plan[key1] = value2 + elif key1 in current_plan: + current_plan.pop(key1) + write_plan(plan, conf['planFile']) + build_plan(conf['planFile']) def init_btn(event): room_key = event[4:] - station_name = plan[room_key]['name'] if room_key in plan.keys() else '' - plans = plan[room_key]['plans'] if room_key in plan.keys() else [] + station_name = current_plan[room_key]['name'] if room_key in current_plan.keys() else '' + plans = current_plan[room_key]['plans'] if room_key in current_plan.keys() else [] if room_key.startswith('room'): window['station_type_col'].update(visible=True) window['station_type'].update(station_name) @@ -448,25 +412,29 @@ def save_btn(btn): plan1['plans'].append({'agent': agent, 'group': group, 'replacement': replacement}) elif btn.startswith('btn_dormitory'): # 宿舍 plan1['plans'].append({'agent': 'Free', 'group': '', 'replacement': []}) - plan[btn[4:]] = plan1 - write_plan() - load_plan(conf['planFile']) + current_plan[btn[4:]] = plan1 + write_plan(plan, conf['planFile']) + build_plan(conf['planFile']) def clear_btn(btn): - if btn[4:] in plan: - plan.pop(btn[4:]) + if btn[4:] in current_plan: + current_plan.pop(btn[4:]) init_btn(btn) - write_plan() - load_plan(conf['planFile']) + write_plan(plan, conf['planFile']) + build_plan(conf['planFile']) -# 输出日志 -def log(pipe): +# 接收推送 +def recv(pipe): try: while True: msg = pipe.recv() - println(msg) + if msg['type'] == 'log': + println(msg['data']) + elif msg['type'] == 'operators': + global operators + operators = msg['data'] except EOFError: pipe.close() From 17e21f09ec13eb0a5bde66525833dda54eb7d413 Mon Sep 17 00:00:00 2001 From: Zhao Zuohong Date: Thu, 4 May 2023 09:48:04 +0800 Subject: [PATCH 30/49] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=89=93=E5=8C=85dev?= =?UTF-8?q?=5Fshawn=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pyinstaller-win-shawn.yml | 31 +++++++++++++++++++++ requirements.txt | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pyinstaller-win-shawn.yml diff --git a/.github/workflows/pyinstaller-win-shawn.yml b/.github/workflows/pyinstaller-win-shawn.yml new file mode 100644 index 000000000..e991e5fe2 --- /dev/null +++ b/.github/workflows/pyinstaller-win-shawn.yml @@ -0,0 +1,31 @@ +name: dev_shawn分支自动打包 + +on: + push: + branches: + - dev_shawn + +jobs: + build-win-amd64: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 amd64 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + architecture: x64 + - name: Install dependencies + shell: cmd + run: | + python -m venv venv + venv\Scripts\python -m pip install -r requirements.txt + venv\Scripts\python -m pip install pyinstaller + - name: Make package + shell: cmd + run: | + venv\Scripts\pyinstaller .\menu.spec + - uses: actions/upload-artifact@v3 + with: + name: mower + path: dist\mower.exe diff --git a/requirements.txt b/requirements.txt index e556977ca..82c74001e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,6 @@ pandas==1.5.2 pyyaml==6.0 PySimpleGUI~=4.60.4 pytz~=2022.6 -ruamel.yaml==0.15.46 +ruamel.yaml==0.17.22 paddleocr==2.6.1.3 paddlepaddle==2.4.2 From 1963a4122631f289e6a3f866744b355afc222af2 Mon Sep 17 00:00:00 2001 From: lethefrost <47198693+lethefrost@users.noreply.github.com> Date: Thu, 4 May 2023 00:11:16 -0400 Subject: [PATCH 31/49] =?UTF-8?q?fix:=20macOS=E9=94=99=E8=AF=AF=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20(#181)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/ocr/decode.py | 8 ++++---- arknights_mower/solvers/base_schedule.py | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arknights_mower/ocr/decode.py b/arknights_mower/ocr/decode.py index 1352ad753..bd289edd2 100644 --- a/arknights_mower/ocr/decode.py +++ b/arknights_mower/ocr/decode.py @@ -111,10 +111,10 @@ def get_mini_boxes(self, contour): def box_score_fast(self, bitmap, _box): h, w = bitmap.shape[:2] box = _box.copy() - xmin = np.clip(np.floor(box[:, 0].min()).astype(np.int), 0, w - 1) - xmax = np.clip(np.ceil(box[:, 0].max()).astype(np.int), 0, w - 1) - ymin = np.clip(np.floor(box[:, 1].min()).astype(np.int), 0, h - 1) - ymax = np.clip(np.ceil(box[:, 1].max()).astype(np.int), 0, h - 1) + xmin = np.clip(np.floor(box[:, 0].min()).astype(np.int32), 0, w - 1) + xmax = np.clip(np.ceil(box[:, 0].max()).astype(np.int32), 0, w - 1) + ymin = np.clip(np.floor(box[:, 1].min()).astype(np.int32), 0, h - 1) + ymax = np.clip(np.ceil(box[:, 1].max()).astype(np.int32), 0, h - 1) mask = np.zeros((ymax - ymin + 1, xmax - xmin + 1), dtype=np.uint8) box[:, 0] = box[:, 0] - xmin diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index e1fcd1305..0c880a05d 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -1,6 +1,7 @@ from __future__ import annotations import copy import time +import sys from enum import Enum from datetime import datetime, timedelta import numpy as np @@ -729,7 +730,11 @@ def double_read_time(self, cord, upperLimit=None,use_digit_reader = False): def initialize_paddle(self): global ocr if ocr is None: - ocr = PaddleOCR(enable_mkldnn=True, use_angle_cls=False) + # mac 平台不支持 mkldnn 加速,关闭以修复 mac 运行时错误 + if sys.platform == 'darwin': + ocr = PaddleOCR(enable_mkldnn=False, use_angle_cls=False) + else: + ocr = PaddleOCR(enable_mkldnn=True, use_angle_cls=False) def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False): if cord is not None: @@ -1234,11 +1239,8 @@ def scan_agant(self, agent: list[str], error_count=0, max_agent_count=-1): raise e def get_order(self, name): - if (name in self.agent_base_config.keys()): - if "ArrangeOrder" in self.agent_base_config[name].keys(): - return True, self.agent_base_config[name]["ArrangeOrder"] - else: - return False, self.agent_base_config["Default"]["ArrangeOrder"] + if name in self.agent_base_config and "ArrangeOrder" in self.agent_base_config[name]: + return True, self.agent_base_config[name]["ArrangeOrder"] return False, self.agent_base_config["Default"]["ArrangeOrder"] def detail_filter(self, turn_on, type="not_in_dorm"): From d1526f8a9613923bd12599427d0f783d255dd169 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Wed, 3 May 2023 23:05:32 -0700 Subject: [PATCH 32/49] =?UTF-8?q?fix:=20=E6=8F=92=E6=8B=94=E5=AE=8C?= =?UTF-8?q?=E7=9C=8B=E7=BA=BF=E7=B4=A2&=E5=8F=AA=E9=87=8D=E8=BD=BD?= =?UTF-8?q?=E5=BF=83=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 22 +++++++++++----------- diy.py | 9 +++++++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 0c880a05d..150176c42 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -351,19 +351,19 @@ def infra_main(self): # 重新扫描 self.error = True logger.exception({e}) + if self.party_time is None and self.enable_party: + self.clue() + if self.drone_room is not None and (self.drone_time is None or self.drone_time < datetime.now() - timedelta( + hours=self.drone_execution_gap)): + self.drone(self.drone_room) + logger.info(f"记录本次无人机使用时间为:{datetime.now()}") + self.drone_time = datetime.now() + if self.reload_room is not None and ( + self.reload_time is None or self.reload_time < datetime.now() - timedelta(hours=24)): + self.reload() self.planned = True elif not self.todo_task: notification = detector.infra_notification(self.recog.img) - if self.drone_room is not None: - if self.drone_time is None or self.drone_time < datetime.now()- timedelta(hours=self.drone_execution_gap): - self.drone(self.drone_room) - logger.info(f"记录本次无人机使用时间为:{datetime.now()}") - self.drone_time = datetime.now() - if self.party_time is None and self.enable_party: - self.clue() - if self.reload_room is not None: - if self.reload_time is None or self.reload_time < datetime.now()- timedelta(hours=24): - self.reload() if notification is None: self.sleep(1) notification = detector.infra_notification(self.recog.img) @@ -561,7 +561,7 @@ def plan_solver(self): result = self.get_agent_from_room(op.current_room, [op.current_index]) _time = datetime.now() if result[op.current_index]['time'] is not None: - _time = result[op.current_index]['time'] + _time = result[op.current_index]['time'] - timedelta(minutes=10) elif op.mood != 0.0: _time = datetime.now() + timedelta( hours=op.mood / op.depletion_rate) - timedelta(minutes=10) diff --git a/diy.py b/diy.py index be883b360..969cb34cc 100644 --- a/diy.py +++ b/diy.py @@ -300,8 +300,13 @@ def simulate(): reconnect_tries = 0 base_scheduler = inialize(tasks) base_scheduler.initialize_operators() - base_scheduler.op_data.operators = load_state() - + _loaded_operators = load_state() + if _loaded_operators is not None: + for k,v in _loaded_operators.items(): + if k in base_scheduler.op_data.operators: + # 只复制心情数据 + base_scheduler.op_data.operators[k].mood = v.mood + base_scheduler.op_data.operators[k].time_stamp = v.time_stamp while True: try: if len(base_scheduler.tasks) > 0: From a2fe834ad5f6f1a272634ab319d4d82d5d4f5e8a Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Wed, 3 May 2023 23:35:39 -0700 Subject: [PATCH 33/49] =?UTF-8?q?update:=E5=BF=83=E6=83=85=E8=BD=BD?= =?UTF-8?q?=E5=85=A5=E9=80=BB=E8=BE=91+=E9=87=8D=E7=BD=AE=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 8a285829b..0438f1031 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -232,7 +232,7 @@ def __init_params__(): "巫恋": {"ArrangeOrder": [2, "true"]}, "柏喙": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"]}, "龙舌兰": {"ArrangeOrder": [2, "true"]}, - "空弦": {"ArrangeOrder": [2, "true"], "RestingPriority": "low"}, + "空弦": {"ArrangeOrder": [2, "true"]}, "伺夜": {"ArrangeOrder": [2, "true"]}, "绮良": {"ArrangeOrder": [2, "true"]}, "但书": {"ArrangeOrder": [2, "true"]}, @@ -251,10 +251,9 @@ def __init_params__(): "安比尔": {"ArrangeOrder": [2, "false"]}, "爱丽丝": {"ArrangeOrder": [2, "false"]}, "桃金娘": {"ArrangeOrder": [2, "false"]}, - "帕拉斯": {"RestingPriority": "low"}, - "红云": {"RestingPriority": "low", "ArrangeOrder": [2, "true"]}, + "红云": {"ArrangeOrder": [2, "true"]}, "承曦格雷伊": {"ArrangeOrder": [2, "true"]}, - "乌有": {"ArrangeOrder": [2, "true"], "RestingPriority": "low"}, + "乌有": {"ArrangeOrder": [2, "true"]}, "图耶": {"ArrangeOrder": [2, "true"]}, "鸿雪": {"ArrangeOrder": [2, "true"]}, "孑": {"ArrangeOrder": [2, "true"]}, @@ -264,7 +263,8 @@ def __init_params__(): "焰尾": {"RestInFull": True}, "重岳": {"ArrangeOrder": [2, "true"]}, "坚雷": {"ArrangeOrder": [2, "true"]}, - "年": {"RestingPriority": "low"} + "年": {"RestingPriority": "low"}, + "伊内丝": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"], "RestInFull": True}, } maa_config = { # maa 运行的时间间隔,以小时计 From df7e9606c07173ebca8ded88d830061e6ec022dc Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Wed, 3 May 2023 23:35:57 -0700 Subject: [PATCH 34/49] =?UTF-8?q?update:=E5=BF=83=E6=83=85=E8=BD=BD?= =?UTF-8?q?=E5=85=A5=E9=80=BB=E8=BE=91+=E9=87=8D=E7=BD=AE=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 0438f1031..ed24a2589 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -36,19 +36,9 @@ def main(c, p, o={}, child_conn=None): if plan['conf']['ling_xi'] == 1: agent_base_config['令']['UpperLimit'] = 12 agent_base_config['夕']['LowerLimit'] = 12 - # assist = '夕' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] - # if assist in agent_base_config.keys(): - # agent_base_config[assist]['LowerLimit'] = 12 - # else: - # agent_base_config[assist] = {'LowerLimit':12} elif plan['conf']['ling_xi'] == 2: agent_base_config['夕']['UpperLimit'] = 12 agent_base_config['令']['LowerLimit'] = 12 - # assist = '令' if conf['ling_xi_assist'] == '' else conf['ling_xi_assist'] - # if assist in agent_base_config.keys(): - # agent_base_config[assist]['LowerLimit'] = 12 - # else: - # agent_base_config[assist] = {'LowerLimit':12} for key in list(filter(None, plan['conf']['rest_in_full'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestInFull'] = True @@ -143,7 +133,11 @@ def simulate(): base_scheduler = inialize(tasks) base_scheduler.initialize_operators() if operators != {}: - base_scheduler.op_data.operators = operators + for k, v in operators.items(): + if k in base_scheduler.op_data.operators: + # 只复制心情数据 + base_scheduler.op_data.operators[k].mood = v.mood + base_scheduler.op_data.operators[k].time_stamp = v.time_stamp while True: try: if len(base_scheduler.tasks) > 0: From 29d3522cadafc379c657e6a9c08e31926e17280d Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Fri, 5 May 2023 16:23:48 -0700 Subject: [PATCH 35/49] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E7=8B=82=E8=AF=8D=E6=9D=A1-->0=E5=BF=83=E6=83=85?= =?UTF-8?q?=E5=B0=8F=E8=BD=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 61 +++++++++++++++--------- arknights_mower/utils/operators.py | 17 +++++++ diy.py | 23 +++++++-- 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 150176c42..193171770 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -19,7 +19,7 @@ from ..utils.pipe import push_operators from ..utils.recognize import RecognizeError, Recognizer, Scene from ..utils.solver import BaseSolver -from ..utils.datetime import get_server_weekday +from ..utils.datetime import get_server_weekday, the_same_time from paddleocr import PaddleOCR import cv2 @@ -78,6 +78,7 @@ def run(self) -> None: if self.party_time is not None and self.party_time {self.total_agent}') fia_plan, fia_room = self.check_fia() @@ -532,7 +535,7 @@ def plan_solver(self): "菲亚梅塔"]}}) try: # 重新排序 - self.total_agent.sort(key=lambda x: x.mood - x.lower_limit, reverse=False) + self.total_agent.sort(key=lambda x: x.current_mood() - x.lower_limit, reverse=False) # 自动生成任务 self.plan_metadata() # 剩余高效组位置 @@ -547,14 +550,16 @@ def plan_solver(self): break if fia_room is not None and op.name in self.op_data.operators['菲亚梅塔'].replacement: continue + if op.name in self.op_data.workaholic_agent: + continue # 忽略掉正在休息的 if op.current_room.startswith("dorm") or op.current_room in ['factory']: continue # 忽略掉心情值没低于上限的的 - if op.mood > int((op.upper_limit - op.lower_limit) * self.resting_treshhold + op.lower_limit): + if op.current_mood() > int((op.upper_limit - op.lower_limit) * self.resting_treshhold + op.lower_limit): continue if op.name in self.op_data.exhaust_agent: - if op.mood <= 2: + if op.current_mood() <= 2: if next((e for e in self.tasks if 'type' in e.keys() and op.name in e['type']), None) is None: self.enter_room(op.current_room) @@ -562,9 +567,9 @@ def plan_solver(self): _time = datetime.now() if result[op.current_index]['time'] is not None: _time = result[op.current_index]['time'] - timedelta(minutes=10) - elif op.mood != 0.0: + elif op.current_mood() != 0.0: _time = datetime.now() + timedelta( - hours=op.mood / op.depletion_rate) - timedelta(minutes=10) + hours=op.current_mood() / op.depletion_rate) - timedelta(minutes=10) self.back() # plan 是空的是因为得动态生成 exhaust_type = op.name @@ -602,12 +607,13 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) __replacement = [] __plan = {} for x in agents: + if self.op_data.operators[x].workaholic : continue if self.op_data.operators[x].resting_priority == 'low': _low += 1 else: _high += 1 # 排序 - agents.sort(key=lambda x: self.op_data.operators[x].mood- self.op_data.operators[x].lower_limit, reverse=False) + agents.sort(key=lambda x: self.op_data.operators[x].current_mood()- self.op_data.operators[x].lower_limit, reverse=False) # 进行位置数量的初步判定 # 对于252可能需要进行额外判定,由于 low_free 性质等同于 high_free success = True @@ -636,6 +642,8 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) # 记录替换组 exist_replacement.extend(__replacement) for x in agents: + if self.op_data.operators[x].workaholic: + continue _dorm = self.op_data.assign_dorm(x) if _dorm.position[0] not in plan.keys(): plan[_dorm.position[0]] = ['Current'] * 5 @@ -947,7 +955,7 @@ def clue(self) -> None: self.back(interval=2) logger.info('返回基建主界面') if self.party_time is not None: - if (next((e for e in self.tasks if e['time'] == self.party_time and e['type']=="maa_Mall"), None)) is None: + if (next((e for e in self.tasks if the_same_time(e['time'],self.party_time) and e['type']=="maa_Mall"), None)) is None: self.tasks.append({'time': self.party_time - timedelta(milliseconds=1), 'plan': {},'type': 'impart'}) self.tasks.append({'time': self.party_time, 'plan': {}, 'type': 'maa_Mall'}) self.back(interval=2) @@ -1479,7 +1487,7 @@ def get_agent_from_room(self, room, read_time_index=None): _mood = self.read_accurate_mood(self.recog.img, cord=mood_p[i]) update_time = True else: - _mood = self.op_data.operators[_name].mood + _mood = self.op_data.operators[_name].current_mood() high_no_time = self.op_data.update_detail(_name, _mood, room, i,update_time) data['depletion_rate'] = self.op_data.operators[_name].depletion_rate if high_no_time is not None: @@ -1610,7 +1618,7 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): self.back(interval=0.5) self.back(interval=0.5) self.tasks.append({'time': self.tasks[0]['time'], 'plan': replace_plan}) - self.skip(False) + self.skip(['planned','todo_task']) if fia_data is not None: replace_agent = fia_data[1] fia_change_room = self.op_data.operators[replace_agent].room @@ -1624,10 +1632,16 @@ def agent_arrange(self, plan: tp.BasePlan, metadata=None): self.skip() logger.info('返回基建主界面') - def skip(self,skip_all=True): - self.planned = True - if skip_all: + def skip(self, task_names ='All'): + if task_names == 'All': + task_names = ['planned', 'collect_notification', 'todo_task'] + if 'planned' in task_names: + self.planned = True + if 'todo_task': self.todo_task = True + if 'collect_notification': + self.collect_notification = True + def reload(self): error = False for room in self.reload_room: @@ -1697,7 +1711,8 @@ def append_maa_task(self, type): 'client_type': '', 'penguin_id': '', 'DrGrandet': False, - 'server': 'CN' + 'server': 'CN', + 'expiring_medicine':9999 }) self.stages.append(stage) elif type =='Recruit': diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 931459ea6..6bd4951b5 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -19,6 +19,7 @@ def __init__(self, config, max_resting_count): self.exhaust_group = [] self.dorm = [] self.max_resting_count = max_resting_count + self.workaholic_agent = [] def __repr__(self): return f'Operators(operators={self.operators})' @@ -103,6 +104,8 @@ def add(self, operator): operator.lower_limit = self.config[operator.name]['LowerLimit'] if operator.name in self.config.keys() and 'UpperLimit' in self.config[operator.name].keys(): operator.upper_limit = self.config[operator.name]['UpperLimit'] + if operator.name in self.config.keys() and 'Workaholic' in self.config[operator.name].keys(): + operator.workaholic = self.config[operator.name]['Workaholic'] self.operators[operator.name] = operator # 需要用尽心情干员逻辑 if (operator.exhaust_require or operator.group in self.exhaust_group) \ @@ -116,6 +119,8 @@ def add(self, operator): self.groups[operator.group] = [operator.name] else: self.groups[operator.group].append(operator.name) + if operator.workaholic and operator.name not in self.workaholic_agent: + self.workaholic_agent.append(operator.workaholic) def available_free(self, free_type='high', count=4): ret = 0 @@ -183,6 +188,7 @@ def __repr__(self): class Operator(object): time_stamp = None depletion_rate = 0 + workaholic = False def __init__(self, name, room, index=-1, group='', replacement=[], resting_priority='low', current_room='', exhaust_require=False, @@ -218,6 +224,8 @@ def need_to_refresh(self, h=2, r=""): return False def not_valid(self): + if self.workaholic: + return True if self.operator_type == 'high': if not self.room.startswith("dorm") and self.current_room.startswith("dorm"): if self.mood == -1 or self.mood == 24: @@ -227,5 +235,14 @@ def not_valid(self): return self.need_to_refresh(2.5) or self.current_room != self.room or self.index != self.current_index return False + def current_mood(self): + predict = self.mood + if self.time_stamp is not None: + predict = self.mood - self.depletion_rate * (datetime.now() - self.time_stamp).total_seconds() / 3600 + if 0 <= predict <= 24: + return predict + else: + return self.mood + def __repr__(self): return f"Operator(name='{self.name}', room='{self.room}', index={self.index}, group='{self.group}', replacement={self.replacement}, resting_priority='{self.resting_priority}', current_room='{self.current_room}',exhaust_require={self.exhaust_require},mood={self.mood}, upper_limit={self.upper_limit}, rest_in_full={self.rest_in_full}, current_index={self.current_index}, lower_limit={self.lower_limit}, operator_type='{self.operator_type}',depletion_rate={self.depletion_rate},time_stamp='{self.time_stamp}')" \ No newline at end of file diff --git a/diy.py b/diy.py index 969cb34cc..b3be8f006 100644 --- a/diy.py +++ b/diy.py @@ -9,7 +9,8 @@ from arknights_mower.utils.device import Device from arknights_mower.utils.log import logger, init_fhlr from arknights_mower.utils import config -from arknights_mower.utils.operators import Operators, Operator +# 下面不能删除 +from arknights_mower.utils.operators import Operators, Operator,Dormitory email_config= { # 发信账户 @@ -163,7 +164,7 @@ agent_base_config = { "Default": {"UpperLimit": 24, "LowerLimit": 0, "ExhaustRequire": False, "ArrangeOrder": [2, "false"], - "RestInFull": False}, + "RestInFull": False,"Workaholic":False}, "令": {"LowerLimit": 12,"ArrangeOrder": [2, "true"]}, "夕": {"UpperLimit": 12, "ArrangeOrder": [2, "true"]}, "稀音": {"ExhaustRequire": True, "ArrangeOrder": [2, "true"], "RestInFull": True}, @@ -276,17 +277,24 @@ def save_state(): def load_state(): if not os.path.exists(state_file_name): - return None + return None,None with open(state_file_name, 'r') as f: state = json.load(f) operators = {k: eval(v) for k, v in state['operators'].items()} + dorm = [eval(k) for k in state['dorm']] for k,v in operators.items(): if not v.time_stamp=='None': v.time_stamp = datetime.strptime(v.time_stamp, '%Y-%m-%d %H:%M:%S.%f') else: v.time_stamp = None - return operators + for v in dorm: + if not v.time=='None': + v.time = datetime.strptime(v.time, '%Y-%m-%d %H:%M:%S.%f') + else: + v.time = None + return operators,dorm + def simulate(): ''' @@ -300,13 +308,18 @@ def simulate(): reconnect_tries = 0 base_scheduler = inialize(tasks) base_scheduler.initialize_operators() - _loaded_operators = load_state() + _loaded_operators,_loaded_dorms = load_state() if _loaded_operators is not None: for k,v in _loaded_operators.items(): if k in base_scheduler.op_data.operators: # 只复制心情数据 base_scheduler.op_data.operators[k].mood = v.mood base_scheduler.op_data.operators[k].time_stamp = v.time_stamp + base_scheduler.op_data.operators[k].depletion_rate = v.depletion_rate + base_scheduler.op_data.operators[k].current_room = v.current_room + base_scheduler.op_data.operators[k].current_index = v.current_index + if _loaded_dorms is not None: + base_scheduler.op_data.dorm = _loaded_dorms while True: try: if len(base_scheduler.tasks) > 0: From e342afea2e05c551ba4a1dbe1f71c3f565789459 Mon Sep 17 00:00:00 2001 From: Zhao Zuohong Date: Sat, 6 May 2023 09:45:39 +0800 Subject: [PATCH 36/49] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=89=93=E5=8C=85=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pyinstaller-win-shawn.yml | 4 + menu.spec | 1 + packaging/image.py | 420 ++++++++++++++++++++ 3 files changed, 425 insertions(+) create mode 100644 packaging/image.py diff --git a/.github/workflows/pyinstaller-win-shawn.yml b/.github/workflows/pyinstaller-win-shawn.yml index e991e5fe2..0da64445e 100644 --- a/.github/workflows/pyinstaller-win-shawn.yml +++ b/.github/workflows/pyinstaller-win-shawn.yml @@ -21,6 +21,10 @@ jobs: python -m venv venv venv\Scripts\python -m pip install -r requirements.txt venv\Scripts\python -m pip install pyinstaller + - name: Patch Paddle + shell: cmd + run: | + copy .\packaging\image.py .\venv\Lib\site-packages\paddle\dataset\image.py /y - name: Make package shell: cmd run: | diff --git a/menu.spec b/menu.spec index cc6ef6e06..6059ab80a 100644 --- a/menu.spec +++ b/menu.spec @@ -21,6 +21,7 @@ a = Analysis( ('venv/Lib/site-packages/paddle/libs/mkldnn.dll', '.'), ('venv/Lib/site-packages/paddle/libs/mklml.dll', '.'), ('venv/Lib/site-packages/shapely/DLLs/geos.dll', '.'), + ('venv/Lib/site-packages/paddle/fluid/proto/framework_pb2.py', '.'), ('venv/Lib/site-packages/paddle/fluid/libpaddle.lib', '.'), ('venv/Lib/site-packages/paddle/fluid/libpaddle.pyd', '.'), ('venv/Lib/site-packages/shapely/DLLs/geos_c.dll', '.')], diff --git a/packaging/image.py b/packaging/image.py new file mode 100644 index 000000000..3cd2e6054 --- /dev/null +++ b/packaging/image.py @@ -0,0 +1,420 @@ +# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +This file contains some common interfaces for image preprocess. +Many users are confused about the image layout. We introduce +the image layout as follows. + +- CHW Layout + + - The abbreviations: C=channel, H=Height, W=Width + - The default layout of image opened by cv2 or PIL is HWC. + PaddlePaddle only supports the CHW layout. And CHW is simply + a transpose of HWC. It must transpose the input image. + +- Color format: RGB or BGR + + OpenCV use BGR color format. PIL use RGB color format. Both + formats can be used for training. Noted that, the format should + be keep consistent between the training and inference period. +""" + +from __future__ import print_function + +import six +import numpy as np +# FIXME(minqiyang): this is an ugly fix for the numpy bug reported here +# https://github.com/numpy/numpy/issues/12497 +# if six.PY3: +# import subprocess +# import sys +# import os +# interpreter = sys.executable +# # Note(zhouwei): if use Python/C 'PyRun_SimpleString', 'sys.executable' +# # will be the C++ execubable on Windows +# if sys.platform == 'win32' and 'python.exe' not in interpreter: +# interpreter = sys.exec_prefix + os.sep + 'python.exe' +# import_cv2_proc = subprocess.Popen([interpreter, "-c", "import cv2"], +# stdout=subprocess.PIPE, +# stderr=subprocess.PIPE) +# out, err = import_cv2_proc.communicate() +# retcode = import_cv2_proc.poll() +# if retcode != 0: +# cv2 = None +# else: +# try: +# import cv2 +# except ImportError: +# cv2 = None +# else: +try: + import cv2 +except ImportError: + cv2 = None +import os +import tarfile +import six.moves.cPickle as pickle + +__all__ = [] + + +def _check_cv2(): + if cv2 is None: + import sys + sys.stderr.write( + '''Warning with paddle image module: opencv-python should be imported, + or paddle image module could NOT work; please install opencv-python first.''' + ) + return False + else: + return True + + +def batch_images_from_tar(data_file, + dataset_name, + img2label, + num_per_batch=1024): + """ + Read images from tar file and batch them into batch file. + + :param data_file: path of image tar file + :type data_file: string + :param dataset_name: 'train','test' or 'valid' + :type dataset_name: string + :param img2label: a dic with image file name as key + and image's label as value + :type img2label: dic + :param num_per_batch: image number per batch file + :type num_per_batch: int + :return: path of list file containing paths of batch file + :rtype: string + """ + batch_dir = data_file + "_batch" + out_path = "%s/%s_%s" % (batch_dir, dataset_name, os.getpid()) + meta_file = "%s/%s_%s.txt" % (batch_dir, dataset_name, os.getpid()) + + if os.path.exists(out_path): + return meta_file + else: + os.makedirs(out_path) + + tf = tarfile.open(data_file) + mems = tf.getmembers() + data = [] + labels = [] + file_id = 0 + for mem in mems: + if mem.name in img2label: + data.append(tf.extractfile(mem).read()) + labels.append(img2label[mem.name]) + if len(data) == num_per_batch: + output = {} + output['label'] = labels + output['data'] = data + pickle.dump(output, + open('%s/batch_%d' % (out_path, file_id), 'wb'), + protocol=2) + file_id += 1 + data = [] + labels = [] + if len(data) > 0: + output = {} + output['label'] = labels + output['data'] = data + pickle.dump(output, + open('%s/batch_%d' % (out_path, file_id), 'wb'), + protocol=2) + + with open(meta_file, 'a') as meta: + for file in os.listdir(out_path): + meta.write(os.path.abspath("%s/%s" % (out_path, file)) + "\n") + return meta_file + + +def load_image_bytes(bytes, is_color=True): + """ + Load an color or gray image from bytes array. + + Example usage: + + .. code-block:: python + + with open('cat.jpg') as f: + im = load_image_bytes(f.read()) + + :param bytes: the input image bytes array. + :type bytes: str + :param is_color: If set is_color True, it will load and + return a color image. Otherwise, it will + load and return a gray image. + :type is_color: bool + """ + assert _check_cv2() is True + + flag = 1 if is_color else 0 + file_bytes = np.asarray(bytearray(bytes), dtype=np.uint8) + img = cv2.imdecode(file_bytes, flag) + return img + + +def load_image(file, is_color=True): + """ + Load an color or gray image from the file path. + + Example usage: + + .. code-block:: python + + im = load_image('cat.jpg') + + :param file: the input image path. + :type file: string + :param is_color: If set is_color True, it will load and + return a color image. Otherwise, it will + load and return a gray image. + :type is_color: bool + """ + assert _check_cv2() is True + + # cv2.IMAGE_COLOR for OpenCV3 + # cv2.CV_LOAD_IMAGE_COLOR for older OpenCV Version + # cv2.IMAGE_GRAYSCALE for OpenCV3 + # cv2.CV_LOAD_IMAGE_GRAYSCALE for older OpenCV Version + # Here, use constant 1 and 0 + # 1: COLOR, 0: GRAYSCALE + flag = 1 if is_color else 0 + im = cv2.imread(file, flag) + return im + + +def resize_short(im, size): + """ + Resize an image so that the length of shorter edge is size. + + Example usage: + + .. code-block:: python + + im = load_image('cat.jpg') + im = resize_short(im, 256) + + :param im: the input image with HWC layout. + :type im: ndarray + :param size: the shorter edge size of image after resizing. + :type size: int + """ + assert _check_cv2() is True + + h, w = im.shape[:2] + h_new, w_new = size, size + if h > w: + h_new = size * h // w + else: + w_new = size * w // h + im = cv2.resize(im, (w_new, h_new), interpolation=cv2.INTER_CUBIC) + return im + + +def to_chw(im, order=(2, 0, 1)): + """ + Transpose the input image order. The image layout is HWC format + opened by cv2 or PIL. Transpose the input image to CHW layout + according the order (2,0,1). + + Example usage: + + .. code-block:: python + + im = load_image('cat.jpg') + im = resize_short(im, 256) + im = to_chw(im) + + :param im: the input image with HWC layout. + :type im: ndarray + :param order: the transposed order. + :type order: tuple|list + """ + assert len(im.shape) == len(order) + im = im.transpose(order) + return im + + +def center_crop(im, size, is_color=True): + """ + Crop the center of image with size. + + Example usage: + + .. code-block:: python + + im = center_crop(im, 224) + + :param im: the input image with HWC layout. + :type im: ndarray + :param size: the cropping size. + :type size: int + :param is_color: whether the image is color or not. + :type is_color: bool + """ + h, w = im.shape[:2] + h_start = (h - size) // 2 + w_start = (w - size) // 2 + h_end, w_end = h_start + size, w_start + size + if is_color: + im = im[h_start:h_end, w_start:w_end, :] + else: + im = im[h_start:h_end, w_start:w_end] + return im + + +def random_crop(im, size, is_color=True): + """ + Randomly crop input image with size. + + Example usage: + + .. code-block:: python + + im = random_crop(im, 224) + + :param im: the input image with HWC layout. + :type im: ndarray + :param size: the cropping size. + :type size: int + :param is_color: whether the image is color or not. + :type is_color: bool + """ + h, w = im.shape[:2] + h_start = np.random.randint(0, h - size + 1) + w_start = np.random.randint(0, w - size + 1) + h_end, w_end = h_start + size, w_start + size + if is_color: + im = im[h_start:h_end, w_start:w_end, :] + else: + im = im[h_start:h_end, w_start:w_end] + return im + + +def left_right_flip(im, is_color=True): + """ + Flip an image along the horizontal direction. + Return the flipped image. + + Example usage: + + .. code-block:: python + + im = left_right_flip(im) + + :param im: input image with HWC layout or HW layout for gray image + :type im: ndarray + :param is_color: whether input image is color or not + :type is_color: bool + """ + if len(im.shape) == 3 and is_color: + return im[:, ::-1, :] + else: + return im[:, ::-1] + + +def simple_transform(im, + resize_size, + crop_size, + is_train, + is_color=True, + mean=None): + """ + Simply data argumentation for training. These operations include + resizing, croping and flipping. + + Example usage: + + .. code-block:: python + + im = simple_transform(im, 256, 224, True) + + :param im: The input image with HWC layout. + :type im: ndarray + :param resize_size: The shorter edge length of the resized image. + :type resize_size: int + :param crop_size: The cropping size. + :type crop_size: int + :param is_train: Whether it is training or not. + :type is_train: bool + :param is_color: whether the image is color or not. + :type is_color: bool + :param mean: the mean values, which can be element-wise mean values or + mean values per channel. + :type mean: numpy array | list + """ + im = resize_short(im, resize_size) + if is_train: + im = random_crop(im, crop_size, is_color=is_color) + if np.random.randint(2) == 0: + im = left_right_flip(im, is_color) + else: + im = center_crop(im, crop_size, is_color=is_color) + if len(im.shape) == 3: + im = to_chw(im) + + im = im.astype('float32') + if mean is not None: + mean = np.array(mean, dtype=np.float32) + # mean value, may be one value per channel + if mean.ndim == 1 and is_color: + mean = mean[:, np.newaxis, np.newaxis] + elif mean.ndim == 1: + mean = mean + else: + # elementwise mean + assert len(mean.shape) == len(im) + im -= mean + + return im + + +def load_and_transform(filename, + resize_size, + crop_size, + is_train, + is_color=True, + mean=None): + """ + Load image from the input file `filename` and transform image for + data argumentation. Please refer to the `simple_transform` interface + for the transform operations. + + Example usage: + + .. code-block:: python + + im = load_and_transform('cat.jpg', 256, 224, True) + + :param filename: The file name of input image. + :type filename: string + :param resize_size: The shorter edge length of the resized image. + :type resize_size: int + :param crop_size: The cropping size. + :type crop_size: int + :param is_train: Whether it is training or not. + :type is_train: bool + :param is_color: whether the image is color or not. + :type is_color: bool + :param mean: the mean values, which can be element-wise mean values or + mean values per channel. + :type mean: numpy array | list + """ + im = load_image(filename, is_color) + im = simple_transform(im, resize_size, crop_size, is_train, is_color, mean) + return im From 6dfec123299770fcd2ba09ac58459ce7d909b19d Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sat, 6 May 2023 10:21:55 -0700 Subject: [PATCH 37/49] =?UTF-8?q?fix=EF=BC=9Aovertake=20=E6=96=B9=E7=A8=8B?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 25 +++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 193171770..401def1e5 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -190,7 +190,7 @@ def overtake_room(self): _rooms.append(__room) # 跳过需要休息满 if not is_exhaust_require: - rooms.extend(__room) + rooms.extend(_rooms) remove_idx.append(idx) for idx in remove_idx: del self.tasks[idx] @@ -214,8 +214,8 @@ def handle_error(self, force=False): logger.debug("由于出现错误情况,生成一次空任务来执行纠错") self.tasks.append({'time': datetime.now(), 'plan': {}}) # 如果没有任何时间小于当前时间的任务-10分钟 则清空任务 - if (next((e for e in self.tasks if e['time'] < datetime.now() - timedelta(seconds=600)), None)) is not None: - logger.info("检测到执行超过10分钟的任务,清空全部任务") + if (next((e for e in self.tasks if e['time'] < datetime.now() - timedelta(seconds=900)), None)) is not None: + logger.info("检测到执行超过15分钟的任务,清空全部任务") self.tasks = [] elif (next((e for e in self.tasks if e['time'] < datetime.now()+timedelta(hours=2.5)), None)) is None: logger.debug("2.5小时内没有其他任务,生成一个空任务") @@ -277,7 +277,11 @@ def plan_metadata(self): __plan[__room] = ['Current'] * len(self.current_plan[__room]) __plan[__room][self.op_data.operators[x].index] = x if __time < datetime.now(): __time = datetime.now() - self.tasks.append({"type": ','.join(__type), 'plan': __plan, 'time': __time}) + if _time != datetime.max: + self.tasks.append({"type": ','.join(__type), 'plan': __plan, 'time': __time}) + else: + logger.debug("检测到时间数据不存在") + self.error= True # 如果非 rest in full, 则同组取时间最小值 else: if dorm.time is not None and dorm.time < _time: @@ -309,11 +313,14 @@ def plan_metadata(self): low_priority.append(x) # 生成单个任务 if len(_plan.items()) > 0: - _time -= timedelta(minutes=8) - if _time < datetime.now(): _time = datetime.now() - self.tasks.append({"type": ','.join(_type), 'plan': _plan, - 'time': _time if not short_rest else (datetime.now() + timedelta(hours=0.5))}) - + if _time != datetime.max: + _time -= timedelta(minutes=8) + if _time < datetime.now(): _time = datetime.now() + self.tasks.append({"type": ','.join(_type), 'plan': _plan, + 'time': _time if not short_rest else (datetime.now() + timedelta(hours=0.5))}) + else: + logger.debug("检测到时间数据不存在") + self.error = True def infra_main(self): """ 位于基建首页 """ From dffce3b5da54dc46de51939afbcc5cbf3830a3a4 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sat, 6 May 2023 21:44:01 -0700 Subject: [PATCH 38/49] fix bug --- arknights_mower/solvers/base_schedule.py | 26 ++++++++++++++++++++---- arknights_mower/utils/operators.py | 6 ++++++ diy.py | 14 +++---------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 401def1e5..ab45149e7 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -277,11 +277,11 @@ def plan_metadata(self): __plan[__room] = ['Current'] * len(self.current_plan[__room]) __plan[__room][self.op_data.operators[x].index] = x if __time < datetime.now(): __time = datetime.now() - if _time != datetime.max: + if __time != datetime.max: self.tasks.append({"type": ','.join(__type), 'plan': __plan, 'time': __time}) else: - logger.debug("检测到时间数据不存在") - self.error= True + self.op_data.reset_dorm_time() + self.error = True # 如果非 rest in full, 则同组取时间最小值 else: if dorm.time is not None and dorm.time < _time: @@ -320,6 +320,7 @@ def plan_metadata(self): 'time': _time if not short_rest else (datetime.now() + timedelta(hours=0.5))}) else: logger.debug("检测到时间数据不存在") + self.op_data.reset_dorm_time() self.error = True def infra_main(self): @@ -846,7 +847,24 @@ def todo_list(self) -> None: self.todo_task = True def share_clue(self): - pass + global x1, x2, x3, x4, y0, y1, y2 + x1, x2, x3, x4 = 0, 0, 0, 0 + y0, y1, y2 = 0, 0, 0 + + logger.info('基建:赠送线索') + + # 进入会客室 + self.enter_room('meeting') + + # 关闭掉房间总览 + error_count = 0 + while self.find('clue_func') is None: + if error_count > 5: + raise Exception('未成功进入线索详情界面') + self.tap((self.recog.w * 0.1, self.recog.h * 0.9), interval=3) + error_count += 1 + # 识别右侧按钮 + (x0, y0), (x1, y1) = self.find('clue_func', strict=True) def clue(self) -> None: # 一些识别时会用到的参数 diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 6bd4951b5..414fe8556 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -24,6 +24,12 @@ def __init__(self, config, max_resting_count): def __repr__(self): return f'Operators(operators={self.operators})' + def reset_dorm_time(self): + for name in self.operators.keys(): + agent = self.operators[name] + if agent.room.startswith("dorm"): + agent.time_stamp = None + def update_detail(self, name, mood, current_room, current_index, update_time=False): agent = self.operators[name] if update_time: diff --git a/diy.py b/diy.py index b3be8f006..6e3ed42cd 100644 --- a/diy.py +++ b/diy.py @@ -282,18 +282,12 @@ def load_state(): with open(state_file_name, 'r') as f: state = json.load(f) operators = {k: eval(v) for k, v in state['operators'].items()} - dorm = [eval(k) for k in state['dorm']] for k,v in operators.items(): if not v.time_stamp=='None': v.time_stamp = datetime.strptime(v.time_stamp, '%Y-%m-%d %H:%M:%S.%f') else: v.time_stamp = None - for v in dorm: - if not v.time=='None': - v.time = datetime.strptime(v.time, '%Y-%m-%d %H:%M:%S.%f') - else: - v.time = None - return operators,dorm + return operators def simulate(): @@ -308,18 +302,16 @@ def simulate(): reconnect_tries = 0 base_scheduler = inialize(tasks) base_scheduler.initialize_operators() - _loaded_operators,_loaded_dorms = load_state() + _loaded_operators = load_state() if _loaded_operators is not None: for k,v in _loaded_operators.items(): - if k in base_scheduler.op_data.operators: + if k in base_scheduler.op_data.operators and not base_scheduler.op_data.operators[k].room.startswith("dorm"): # 只复制心情数据 base_scheduler.op_data.operators[k].mood = v.mood base_scheduler.op_data.operators[k].time_stamp = v.time_stamp base_scheduler.op_data.operators[k].depletion_rate = v.depletion_rate base_scheduler.op_data.operators[k].current_room = v.current_room base_scheduler.op_data.operators[k].current_index = v.current_index - if _loaded_dorms is not None: - base_scheduler.op_data.dorm = _loaded_dorms while True: try: if len(base_scheduler.tasks) > 0: From 654d0a136990925132438071d5ed550d3bcb5a1a Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sat, 6 May 2023 22:15:20 -0700 Subject: [PATCH 39/49] =?UTF-8?q?update:=E6=A1=8C=E9=9D=A2=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index ed24a2589..4e21bdec9 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -133,11 +133,14 @@ def simulate(): base_scheduler = inialize(tasks) base_scheduler.initialize_operators() if operators != {}: - for k, v in operators.items(): - if k in base_scheduler.op_data.operators: + for k,v in operators.items(): + if k in base_scheduler.op_data.operators and not base_scheduler.op_data.operators[k].room.startswith("dorm"): # 只复制心情数据 base_scheduler.op_data.operators[k].mood = v.mood base_scheduler.op_data.operators[k].time_stamp = v.time_stamp + base_scheduler.op_data.operators[k].depletion_rate = v.depletion_rate + base_scheduler.op_data.operators[k].current_room = v.current_room + base_scheduler.op_data.operators[k].current_index = v.current_index while True: try: if len(base_scheduler.tasks) > 0: From bdb30b04677812d4b35d7bf7c9fbf071bd47c037 Mon Sep 17 00:00:00 2001 From: Zhao Zuohong Date: Mon, 8 May 2023 16:31:03 +0800 Subject: [PATCH 40/49] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=A3=9E=E6=A1=A8?= =?UTF-8?q?=E7=9A=84=E8=BF=9B=E5=BA=A6=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pyinstaller-win-shawn.yml | 1 + packaging/network.py | 82 +++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 packaging/network.py diff --git a/.github/workflows/pyinstaller-win-shawn.yml b/.github/workflows/pyinstaller-win-shawn.yml index 0da64445e..ae333f724 100644 --- a/.github/workflows/pyinstaller-win-shawn.yml +++ b/.github/workflows/pyinstaller-win-shawn.yml @@ -25,6 +25,7 @@ jobs: shell: cmd run: | copy .\packaging\image.py .\venv\Lib\site-packages\paddle\dataset\image.py /y + copy .\packaging\network.py .\venv\Lib\site-packages\paddleocr\ppocr\utils\network.py /y - name: Make package shell: cmd run: | diff --git a/packaging/network.py b/packaging/network.py new file mode 100644 index 000000000..9c62622e0 --- /dev/null +++ b/packaging/network.py @@ -0,0 +1,82 @@ +# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys +import tarfile +import requests +# from tqdm import tqdm + +from ppocr.utils.logging import get_logger + + +def download_with_progressbar(url, save_path): + logger = get_logger() + response = requests.get(url, stream=True) + if response.status_code == 200: + total_size_in_bytes = int(response.headers.get('content-length', 1)) + block_size = 1024 # 1 Kibibyte + # progress_bar = tqdm( + # total=total_size_in_bytes, unit='iB', unit_scale=True) + with open(save_path, 'wb') as file: + for data in response.iter_content(block_size): + # progress_bar.update(len(data)) + file.write(data) + # progress_bar.close() + else: + logger.error("Something went wrong while downloading models") + sys.exit(0) + + +def maybe_download(model_storage_directory, url): + # using custom model + tar_file_name_list = ['.pdiparams', '.pdiparams.info', '.pdmodel'] + if not os.path.exists( + os.path.join(model_storage_directory, 'inference.pdiparams') + ) or not os.path.exists( + os.path.join(model_storage_directory, 'inference.pdmodel')): + assert url.endswith('.tar'), 'Only supports tar compressed package' + tmp_path = os.path.join(model_storage_directory, url.split('/')[-1]) + print('download {} to {}'.format(url, tmp_path)) + os.makedirs(model_storage_directory, exist_ok=True) + download_with_progressbar(url, tmp_path) + with tarfile.open(tmp_path, 'r') as tarObj: + for member in tarObj.getmembers(): + filename = None + for tar_file_name in tar_file_name_list: + if member.name.endswith(tar_file_name): + filename = 'inference' + tar_file_name + if filename is None: + continue + file = tarObj.extractfile(member) + with open( + os.path.join(model_storage_directory, filename), + 'wb') as f: + f.write(file.read()) + os.remove(tmp_path) + + +def is_link(s): + return s is not None and s.startswith('http') + + +def confirm_model_dir_url(model_dir, default_model_dir, default_url): + url = default_url + if model_dir is None or is_link(model_dir): + if is_link(model_dir): + url = model_dir + file_name = url.split('/')[-1][:-4] + model_dir = default_model_dir + model_dir = os.path.join(model_dir, file_name) + return model_dir, url From 02d9b2a16c613723f788324d9ce8f2fbe003acfd Mon Sep 17 00:00:00 2001 From: Ksnow <1048879349@qq.com> Date: Tue, 9 May 2023 00:57:54 +0800 Subject: [PATCH 41/49] =?UTF-8?q?fix=EF=BC=9A=E5=A2=9E=E5=8A=A0[=E5=90=AF?= =?UTF-8?q?=E5=8A=A8mower=E6=97=B6=E8=87=AA=E5=8A=A8=E5=BC=80=E5=A7=8B?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/templates/conf.yml | 1 + menu.py | 31 +++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/arknights_mower/templates/conf.yml b/arknights_mower/templates/conf.yml index 9f7ccb79d..0e59ca828 100644 --- a/arknights_mower/templates/conf.yml +++ b/arknights_mower/templates/conf.yml @@ -42,3 +42,4 @@ rest_in_full: '' resting_priority: '' run_mode: 1 run_order_delay: 10 +start_automatically: false diff --git a/menu.py b/menu.py index 9fc98fbcd..2b6ad472d 100644 --- a/menu.py +++ b/menu.py @@ -128,6 +128,8 @@ def menu(): expand_x=True) # --------高级设置页面 + start_automatically = sg.Checkbox('启动mower时自动开始任务', default=conf['start_automatically'], + key='conf_start_automatically', enable_events=True) run_mode_title = sg.Text('运行模式:', size=25) run_mode_1 = sg.Radio('换班模式', 'run_mode', default=conf['run_mode'] == 1, key='radio_run_mode_1', enable_events=True) @@ -221,7 +223,8 @@ def menu(): plan_tab = sg.Tab(' 排班表 ', [[left_area, central_area, right_area], [setting_area]], element_justification="center") setting_tab = sg.Tab(' 高级设置 ', - [[run_mode_title, run_mode_1, run_mode_2], [ling_xi_title, ling_xi_1, ling_xi_2, ling_xi_3], + [ + [run_mode_title, run_mode_1, run_mode_2], [ling_xi_title, ling_xi_1, ling_xi_2, ling_xi_3], [enable_party_title, enable_party_1, enable_party_0], [max_resting_count_title, max_resting_count, sg.Text('', size=16), run_order_delay_title, run_order_delay], @@ -232,6 +235,7 @@ def menu(): [exhaust_require_title, exhaust_require], [resting_priority_title, resting_priority], # [ling_xi_assist_title, ling_xi_assist] 去除协助令夕心情调配项 + [start_automatically], ], pad=((10, 10), (10, 10))) other_tab = sg.Tab(' 外部调用 ', @@ -245,6 +249,8 @@ def menu(): btn = None bind_scirpt() # 为基建布局左边的站点排序绑定事件 drag_task = DragTask() + if conf['start_automatically']: + start() while True: event, value = window.Read() if event == sg.WIN_CLOSED: @@ -268,7 +274,8 @@ def menu(): plan['conf'][event[11:v_index]] = int(event[v_index + 1:]) elif event.startswith('conf_'): # conf开头,为字符串输入的配置 key = event[5:] - conf[key] = window[event].get().strip() + value = window[event].get() + conf[key] = value.strip() if isinstance(value, str) else value elif event.startswith('int_'): # int开头,为数值型输入的配置 key = event[4:] try: @@ -304,13 +311,7 @@ def menu(): elif event == 'clearPlan': # 清空当前设施信息 clear_btn(btn) elif event == 'on': - on_btn.update(visible=False) - off_btn.update(visible=True) - clear() - parent_conn, child_conn = Pipe() - main_thread = Process(target=main, args=(conf, plan,operators, child_conn), daemon=True) - main_thread.start() - window.perform_long_operation(lambda: recv(parent_conn),'recv') + start() elif event == 'off': println('停止运行') child_conn.close() @@ -323,6 +324,18 @@ def menu(): write_plan(plan, conf['planFile']) +def start(): + global main_thread, child_conn + window['on'].update(visible=False) + window['off'].update(visible=True) + clear() + parent_conn, child_conn = Pipe() + main_thread = Process(target=main, args=(conf, plan, operators, child_conn), daemon=True) + main_thread.start() + window.perform_long_operation(lambda: recv(parent_conn), 'recv') + + + def bind_scirpt(): for i in range(3): for j in range(3): From 6edf226880a9bf691e2bcd06e68e6f615ae1e193 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 8 May 2023 23:07:06 -0700 Subject: [PATCH 42/49] =?UTF-8?q?update:=20SIFT=20=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/data/agent.json | 3 ++- arknights_mower/solvers/base_schedule.py | 7 +++---- arknights_mower/utils/character_recognize.py | 17 +++++++++++------ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/arknights_mower/data/agent.json b/arknights_mower/data/agent.json index 0da8c9479..0f9b0041a 100644 --- a/arknights_mower/data/agent.json +++ b/arknights_mower/data/agent.json @@ -278,5 +278,6 @@ "缪尔赛思", "霍尔海雅", "淬羽赫默", - "玫拉" + "玫拉", + "铎铃" ] diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index ab45149e7..35f816e6c 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -752,14 +752,13 @@ def initialize_paddle(self): else: ocr = PaddleOCR(enable_mkldnn=True, use_angle_cls=False) - def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False): + def read_screen(self, img, type="mood", limit=24, cord=None): if cord is not None: img = img[cord[1]:cord[3], cord[0]:cord[2]] if 'mood' in type or type == "time": # 心情图片太小,复制8次提高准确率 for x in range(0, 4): img = cv2.vconcat([img, img]) - if change_color: img[img == 137] = 255 try: self.initialize_paddle() rets = ocr.ocr(img, cls=True) @@ -778,7 +777,7 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) return -1 elif 'name' in type: logger.debug("使用老版识别") - return character_recognize.agent_name(img, self.recog.h * 1.1) + return character_recognize.agent_name(img, self.recog.h) else: return "" x = [i[0] for i in line_conf] @@ -793,7 +792,7 @@ def read_screen(self, img, type="mood", limit=24, cord=None, change_color=False) __str = __str.replace(".", ":") elif 'name' in type and __str not in agent_list: logger.debug("使用老版识别") - __str = character_recognize.agent_name(img, self.recog.h * 1.1) + __str = character_recognize.agent_name(img, self.recog.h) logger.debug(__str) return __str except Exception as e: diff --git a/arknights_mower/utils/character_recognize.py b/arknights_mower/utils/character_recognize.py index 09f3da2e4..688cb53b7 100644 --- a/arknights_mower/utils/character_recognize.py +++ b/arknights_mower/utils/character_recognize.py @@ -63,15 +63,20 @@ def agent_sift_init(): origin_kp, origin_des = SIFT.detectAndCompute(origin, None) -def sift_recog(query, resolution, draw=False,reverse = False): +def sift_recog(query, resolution, draw=False,bigfont = False): """ 使用 SIFT 提取特征点识别干员名称 """ agent_sift_init() + # 大号字体修改参数 + if bigfont: + SIFT = cv2.SIFT_create( + contrastThreshold=0.1, + edgeThreshold=20 + ) + else: + SIFT = cv2.SIFT_create() query = cv2.cvtColor(np.array(query), cv2.COLOR_RGB2GRAY) - if reverse : - # 干员总览界面图像色度反转 - query = 255 -query # the height & width of query image height, width = query.shape @@ -217,7 +222,7 @@ def agent(img, draw=False): saveimg(img, 'failure_agent') raise RecognizeError(e) -def agent_name(__img, height,reverse = False, draw: bool = False): +def agent_name(__img, height, draw: bool = False): query = cv2.cvtColor(np.array(__img), cv2.COLOR_RGB2GRAY) h, w= query.shape dim = (w*4, h*4) @@ -231,7 +236,7 @@ def agent_name(__img, height,reverse = False, draw: bool = False): elif len(ocr) > 0 and ocr[0][1] in ocr_error.keys(): name = ocr_error[ocr[0][1]] else: - res = sift_recog(__img, height, draw, reverse) + res = sift_recog(__img, height, draw,bigfont=True) if (res is not None) and res in agent_list: name = res else: From d6db72eac447f2f45d2b5b0d63d0cac92a4fad4f Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sun, 14 May 2023 01:39:22 -0700 Subject: [PATCH 43/49] =?UTF-8?q?#159=20=E8=B5=A0=E9=80=81=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=BA=BF=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 49 ++++++++++++++++-------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 35f816e6c..087a956d8 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -60,6 +60,7 @@ def __init__(self, device: Device = None, recog: Recognizer = None) -> None: self.reload_time = None self.reload_room = None self.run_order_delay=10 + self.clue_count_limit = 9 self.enable_party = True self.digit_reader = DigitReader() self.error = False @@ -80,6 +81,7 @@ def run(self) -> None: self.todo_task = False self.collect_notification = False self.planned = False + self.clue_count = 0 if self.op_data is None or self.op_data.operators is None: self.initialize_operators() return super().run() @@ -365,6 +367,8 @@ def infra_main(self): elif not self.todo_task: if self.party_time is None and self.enable_party: self.clue() + if self.clue_count>self.clue_count_limit and self.enable_party: + self.share_clue() if self.drone_room is not None and (self.drone_time is None or self.drone_time < datetime.now() - timedelta( hours=self.drone_execution_gap)): self.drone(self.drone_room) @@ -851,7 +855,6 @@ def share_clue(self): y0, y1, y2 = 0, 0, 0 logger.info('基建:赠送线索') - # 进入会客室 self.enter_room('meeting') @@ -865,6 +868,31 @@ def share_clue(self): # 识别右侧按钮 (x0, y0), (x1, y1) = self.find('clue_func', strict=True) + self.tap(((x0 + x1) // 2, (y0 + y1 * 3) // 4), interval=3, rebuild=True) + while self.get_infra_scene() == Scene.CONNECTING: + self.sleep(2) + self.recog_bar() + self.recog_view(only_y2=False) + for i in range(1, 8): + # 切换阵营 + self.tap(self.switch_camp(i)) + # 获得和线索视图有关的数据 + self.recog_view() + ori_results = self.ori_clue() + if len(ori_results) >1: + last_ori = ori_results[0] + self.tap(((last_ori[0][0] + last_ori[2][0]) / 2, (last_ori[0][1] + last_ori[2][1]) / 2), interval=1) + self.tap((self.recog.w * 0.93, self.recog.h * 0.15), interval=3) + logger.info(f'赠送线索 {i} -->给一位随机的幸运儿') + break + else: + continue + while self.get_infra_scene() == Scene.CONNECTING: + self.sleep(2) + self.tap((self.recog.w * 0.95, self.recog.h * 0.05), interval=3) + self.back() + self.back() + def clue(self) -> None: # 一些识别时会用到的参数 global x1, x2, x3, x4, y0, y1, y2 @@ -900,26 +928,12 @@ def clue(self) -> None: logger.info('领取会客室线索') self.tap(((x0 + x1) // 2, (y0 * 5 - y1) // 4), interval=3) obtain = self.find('clue_obtain') - clue_inventory_full = False - if self.find('clue_full') is not None: - clue_inventory_full = True if obtain is not None and self.get_color(self.get_pos(obtain, 0.25, 0.5))[0] < 20: self.tap(obtain, interval=2) if self.find('clue_full') is not None: self.back() else: self.back() - if not clue_inventory_full: - pass - # self.back() - # self.tap((x1, y1), interval=0.5) - # self.recog_bar() - # # 获得和线索视图相关的数据 - # self.recog_view(only_y2=False) - # for i in range(1, 8): - # # 切换阵营 - # self.tap(self.switch_camp(i)) - logger.info('放置线索') clue_unlock = self.find('clue_unlock') if clue_unlock is not None: @@ -1469,6 +1483,11 @@ def get_agent_from_room(self, room, read_time_index=None): error_count = 0 if room == 'meeting': time.sleep(3) + self.recog.update() + clue_res = self.read_screen(self.recog.img,limit=10,cord= (645,977,755,1018)) + if clue_res!=-1: + self.clue_count =clue_res + logger.info(f'当前拥有线索数量为{self.clue_count}') while self.find('room_detail') is None: if error_count > 3: raise Exception('未成功进入房间') From 9f726a958748d13c50eefce8f192777c6fbd4ed6 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sun, 14 May 2023 02:09:50 -0700 Subject: [PATCH 44/49] =?UTF-8?q?feat:=20=E8=82=89=E9=B8=BD=E5=BC=80?= =?UTF-8?q?=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 1 + arknights_mower/templates/conf.yml | 1 + menu.py | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 4e21bdec9..095bc58f8 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -106,6 +106,7 @@ def inialize(tasks, scheduler=None): maa_config['maa_adb_path'] = conf['maa_adb_path'] maa_config['maa_adb'] = conf['adb'] maa_config['weekly_plan'] = conf['maa_weekly_plan'] + maa_config['roguelike'] = conf['maa_rg_enable'] == 1 base_scheduler.maa_config = maa_config base_scheduler.ADB_CONNECT = config.ADB_CONNECT[0] base_scheduler.error = False diff --git a/arknights_mower/templates/conf.yml b/arknights_mower/templates/conf.yml index 0e59ca828..172ebcfb5 100644 --- a/arknights_mower/templates/conf.yml +++ b/arknights_mower/templates/conf.yml @@ -8,6 +8,7 @@ free_blacklist: '' ling_xi: 1 maa_adb_path: D:\Program Files\Nox\bin\adb.exe maa_enable: 0 +maa_rg_enable: 0 maa_path: D:\MAA-v4.13.0-win-x64 maa_weekly_plan: - medicine: 0 diff --git a/menu.py b/menu.py index 2b6ad472d..d99a93db8 100644 --- a/menu.py +++ b/menu.py @@ -195,12 +195,17 @@ def menu(): key='radio_maa_enable_1', enable_events=True) maa_enable_0 = sg.Radio('禁用', 'maa_enable', default=conf['maa_enable'] == 0, key='radio_maa_enable_0', enable_events=True) + maa_rg_title = sg.Text('肉鸽:', size=10) + maa_rg_enable_1 = sg.Radio('启用', 'maa_rg_enable', default=conf['maa_rg_enable'] == 1, + key='radio_maa_rg_enable_1', enable_events=True) + maa_rg_enable_0 = sg.Radio('禁用', 'maa_rg_enable', default=conf['maa_rg_enable'] == 0, + key='radio_maa_rg_enable_0', enable_events=True) maa_path_title = sg.Text('MAA地址', size=25) maa_path = sg.InputText(conf['maa_path'], size=60, key='conf_maa_path', enable_events=True) maa_adb_path_title = sg.Text('adb地址', size=25) maa_adb_path = sg.InputText(conf['maa_adb_path'], size=60, key='conf_maa_adb_path', enable_events=True) maa_weekly_plan_title = sg.Text('周计划', size=25) - maa_layout = [[maa_enable_1, maa_enable_0], [maa_path_title, maa_path], [maa_adb_path_title, maa_adb_path], + maa_layout = [[maa_enable_1, maa_enable_0],[maa_rg_title,maa_rg_enable_1,maa_rg_enable_0], [maa_path_title, maa_path], [maa_adb_path_title, maa_adb_path], [maa_weekly_plan_title]] for i, v in enumerate(conf['maa_weekly_plan']): maa_layout.append([ From a321213c9a3bc1b85a2cfad8663aaa42ae018375 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Sun, 14 May 2023 02:18:33 -0700 Subject: [PATCH 45/49] bug fix --- diy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diy.py b/diy.py index 6e3ed42cd..ec7f86311 100644 --- a/diy.py +++ b/diy.py @@ -277,7 +277,7 @@ def save_state(): def load_state(): if not os.path.exists(state_file_name): - return None,None + return None with open(state_file_name, 'r') as f: state = json.load(f) From b89a615716958bd8aa857d67b61de1dc90a43143 Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Mon, 15 May 2023 10:21:41 -0700 Subject: [PATCH 46/49] =?UTF-8?q?fix:=20maa=5Fmall=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 1 - arknights_mower/solvers/base_schedule.py | 19 +++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 095bc58f8..8bd158491 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -166,7 +166,6 @@ def simulate(): if len(base_scheduler.tasks) > 0 and 'type' in base_scheduler.tasks[0].keys() and base_scheduler.tasks[0]['type'].split('_')[0] == 'maa': logger.info(f"开始执行 MAA {base_scheduler.tasks[0]['type'].split('_')[1]} 任务") base_scheduler.maa_plan_solver((base_scheduler.tasks[0]['type'].split('_')[1]).split(','), one_time=True) - del base_scheduler.tasks[0] continue base_scheduler.run() reconnect_tries = 0 diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 087a956d8..b22cce0d5 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -86,14 +86,6 @@ def run(self) -> None: self.initialize_operators() return super().run() - def get_group(self, rest_agent, agent, groupname, name): - for element in agent: - if element['group'] == groupname and name != element["agent"]: - rest_agent.append(element) - # 从大组里删除 - agent.remove(element) - return - def transition(self) -> None: self.recog.update() if self.scene() == Scene.INDEX: @@ -1860,17 +1852,16 @@ def maa_plan_solver(self,tasks ='All',one_time = False): time.sleep(0) self.device.exit(self.package_name) # 生息演算逻辑 结束 - remaining_time = 0 if one_time and len(self.tasks) == 1 else ( - self.tasks[1 if one_time else 0]["time"] - datetime.now()).total_seconds() + if one_time: + if len(self.tasks)>0: + del self.tasks[0] + return + remaining_time =(self.tasks[0]["time"] - datetime.now()).total_seconds() subject = f"开始休息 {'%.2f' % (remaining_time / 60)} 分钟,到{self.tasks[0]['time'].strftime('%H:%M:%S')}" context = f"下一次任务:{self.tasks[0]['plan']}" logger.info(context) logger.info(subject) self.send_email(context, subject) - if one_time: - if len(self.tasks)>0: - del self.tasks[0] - self.handle_error(True) if remaining_time>0: time.sleep(remaining_time) self.MAA = None From c7d79b5d90a190fda0bde8d8848b2319bd00fd9d Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Tue, 16 May 2023 22:19:13 -0700 Subject: [PATCH 47/49] =?UTF-8?q?update:=20=E8=8F=B2=E4=BA=9A=E6=A2=85?= =?UTF-8?q?=E5=A1=94=E5=8A=9F=E8=83=BD=E6=80=A7=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/solvers/base_schedule.py | 50 ++++++++++++++++++++---- arknights_mower/utils/operators.py | 13 ++++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index b22cce0d5..0923825a4 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -64,6 +64,7 @@ def __init__(self, device: Device = None, recog: Recognizer = None) -> None: self.enable_party = True self.digit_reader = DigitReader() self.error = False + self.clue_count = 0 def run(self) -> None: """ @@ -81,7 +82,6 @@ def run(self) -> None: self.todo_task = False self.collect_notification = False self.planned = False - self.clue_count = 0 if self.op_data is None or self.op_data.operators is None: self.initialize_operators() return super().run() @@ -216,6 +216,38 @@ def handle_error(self, force=False): self.tasks.append({'time': datetime.now()+timedelta(hours=2.5), 'plan': {}}) return True + def plan_fia(self): + fia_plan, fia_room = self.check_fia() + if fia_room is not None and fia_plan is not None: + current_time = self.task['time'] + candidate_lst = [] + # 复制最后一位的当前信息 + last_candidate = copy.deepcopy(self.op_data.operators[self.op_data.operators['菲亚梅塔'].replacement[-1]]) + plan_last = True + for name in self.op_data.operators['菲亚梅塔'].replacement[:-1]: + if name in self.op_data.operators: + # 必须有心情消耗速率才可以进行计算 + if not 0 < self.op_data.operators[name].depletion_rate < 2: + logger.info(f'{name}的心情消耗速率缺失或不在合理范围内') + plan_last = False + # 复制除去最后一位的当前信息 + data = copy.deepcopy(self.op_data.operators[name]) + data.mood = data.current_mood() + candidate_lst.append(data) + self.skip() + # 排序 + candidate_lst.sort(key=lambda x: (x.mood - x.lower_limit) / (x.upper_limit - x.lower_limit), reverse=False) + print(candidate_lst) + name = candidate_lst[0].name + # 只有主要充能干员心情在20以上才会考虑额外干员 + if plan_last and candidate_lst[0].current_mood() >= 20: + mood = last_candidate.current_mood() + logger.debug(f'{last_candidate.name},mood:{mood}') + if self.op_data.predict_fia(copy.deepcopy(candidate_lst),mood): + name = last_candidate.name + self.tasks.append({'time': current_time, + 'plan': {fia_room: [name, '菲亚梅塔']}}) + def plan_metadata(self): planned_index = [] for t in self.tasks: @@ -332,6 +364,8 @@ def infra_main(self): if metadata is not None: self.plan_metadata() # 如果任务名称包含干员名,则为动态生成的 + elif 'type' in self.task.keys() and self.task['type']=='菲亚梅塔': + self.plan_fia() elif 'type' in self.task.keys() and self.task['type'].split(',')[0] in agent_list: self.overtake_room() elif 'type' in self.task.keys() and self.task['type'] == 'impart': @@ -523,7 +557,7 @@ def plan_solver(self): logger.debug(f'当前基地数据--> {self.total_agent}') fia_plan, fia_room = self.check_fia() if fia_room is not None and fia_plan is not None: - if not any(fia_room in obj["plan"].keys() and len(obj["plan"][fia_room]) == 2 for obj in self.tasks): + if not any('type' in obj.keys() and obj['type']=='菲亚梅塔' for obj in self.tasks): fia_idx = self.op_data.operators['菲亚梅塔'].current_index if self.op_data.operators[ '菲亚梅塔'].current_index != -1 else \ self.op_data.operators['菲亚梅塔'].index @@ -534,9 +568,7 @@ def plan_solver(self): result = self.get_agent_from_room(fia_room, [fia_idx]) self.back() logger.info('下一次进行菲亚梅塔充能:' + result[fia_idx]['time'].strftime("%H:%M:%S")) - self.tasks.append({"time": result[fia_idx]['time'], "plan": {fia_room: [ - next(obj for obj in self.total_agent if obj.name in fia_plan).name, - "菲亚梅塔"]}}) + self.tasks.append({"time": result[fia_idx]['time'], "plan": {},'type':"菲亚梅塔"}) try: # 重新排序 self.total_agent.sort(key=lambda x: x.current_mood() - x.lower_limit, reverse=False) @@ -552,7 +584,7 @@ def plan_solver(self): # 忽略掉菲亚梅塔充能的干员 if high_free == 0 or low_free == 0: break - if fia_room is not None and op.name in self.op_data.operators['菲亚梅塔'].replacement: + if fia_room is not None and op.name in self.op_data.operators['菲亚梅塔'].replacement[:-1]: continue if op.name in self.op_data.workaholic_agent: continue @@ -633,7 +665,7 @@ def get_resting_plan(self, agents, exist_replacement, plan, high_free, low_free) _rep = next((obj for obj in x.replacement if (not ( self.op_data.operators[obj].current_room != '' and not self.op_data.operators[ obj].current_room.startswith('dormitory'))) and obj not in ['但书', - '龙舌兰'] and obj not in exist_replacement and obj not in __replacement), + '龙舌兰'] and obj not in exist_replacement and obj not in __replacement and self.op_data.operators[obj].current_room != x.room), None) if _rep is not None: __replacement.append(_rep) @@ -876,6 +908,7 @@ def share_clue(self): self.tap(((last_ori[0][0] + last_ori[2][0]) / 2, (last_ori[0][1] + last_ori[2][1]) / 2), interval=1) self.tap((self.recog.w * 0.93, self.recog.h * 0.15), interval=3) logger.info(f'赠送线索 {i} -->给一位随机的幸运儿') + self.clue_count-=1 break else: continue @@ -1855,10 +1888,11 @@ def maa_plan_solver(self,tasks ='All',one_time = False): if one_time: if len(self.tasks)>0: del self.tasks[0] + self.MAA = None return remaining_time =(self.tasks[0]["time"] - datetime.now()).total_seconds() subject = f"开始休息 {'%.2f' % (remaining_time / 60)} 分钟,到{self.tasks[0]['time'].strftime('%H:%M:%S')}" - context = f"下一次任务:{self.tasks[0]['plan']}" + context = f"下一次任务:{self.tasks[0]['plan'] if len(self.tasks[0]['plan']) != 0 else '空任务' if 'type' not in self.tasks[0] else self.tasks[0]['type']}" logger.info(context) logger.info(subject) self.send_email(context, subject) diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 414fe8556..759920a1b 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -24,6 +24,19 @@ def __init__(self, config, max_resting_count): def __repr__(self): return f'Operators(operators={self.operators})' + def predict_fia(self, operators, fia_mood, hours=240): + recover_hours = (24 - fia_mood) / 2 + for agent in operators: + agent.mood -= agent.depletion_rate * recover_hours + if agent.mood < 0.0: + return False + if recover_hours >= hours or 0 < recover_hours < 1: + return True + operators.sort(key=lambda x: (x.mood-x.lower_limit)/(x.upper_limit - x.lower_limit), reverse=False) + fia_mood = operators[0].mood + operators[0].mood = 24 + return self.predict_fia(operators, fia_mood, hours - recover_hours) + def reset_dorm_time(self): for name in self.operators.keys(): agent = self.operators[name] From 85c1611726cd9bcf51910cef8a19c648e74d763d Mon Sep 17 00:00:00 2001 From: Shawnsdaddy Date: Wed, 17 May 2023 15:18:15 -0700 Subject: [PATCH 48/49] =?UTF-8?q?update:=20=E6=A1=8C=E9=9D=A2=E7=89=880?= =?UTF-8?q?=E5=BF=83=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arknights_mower/__main__.py | 5 +++++ arknights_mower/solvers/base_schedule.py | 7 +++++++ arknights_mower/templates/conf.yml | 1 + arknights_mower/templates/plan.json | 3 ++- arknights_mower/utils/operators.py | 4 ++-- menu.py | 13 +++++++------ 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/arknights_mower/__main__.py b/arknights_mower/__main__.py index 8bd158491..9489274f4 100644 --- a/arknights_mower/__main__.py +++ b/arknights_mower/__main__.py @@ -49,6 +49,11 @@ def main(c, p, o={}, child_conn=None): agent_base_config[key]['ExhaustRequire'] = True else: agent_base_config[key] = {'ExhaustRequire': True} + for key in list(filter(None, plan['conf']['workaholic'].replace(',', ',').split(','))): + if key in agent_base_config.keys(): + agent_base_config[key]['Workaholic'] = True + else: + agent_base_config[key] = {'Workaholic': True} for key in list(filter(None, plan['conf']['resting_priority'].replace(',', ',').split(','))): if key in agent_base_config.keys(): agent_base_config[key]['RestingPriority'] = 'low' diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 0923825a4..80b60985f 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -84,6 +84,9 @@ def run(self) -> None: self.planned = False if self.op_data is None or self.op_data.operators is None: self.initialize_operators() + for name in self.op_data.workaholic_agent: + if name not in self.free_blacklist: + self.free_blacklist.append(name) return super().run() def transition(self) -> None: @@ -335,6 +338,7 @@ def plan_metadata(self): x].resting_priority == 'high': logger.debug(f"更新任务时间{dorm.time}") _time = __dorm.time + if x not in low_priority: low_priority.append(x) # 生成单个任务 @@ -612,6 +616,9 @@ def plan_solver(self): if op.group != '': exhaust_type = ','.join(self.op_data.groups[op.group]) self.tasks.append({"time": _time,"plan": {}, "type": exhaust_type}) + # 如果是生成的过去时间,则停止 plan 其他 + if _time < datetime.now(): + break continue if op.group != '': if op.group in self.op_data.exhaust_group: diff --git a/arknights_mower/templates/conf.yml b/arknights_mower/templates/conf.yml index 172ebcfb5..3269fa358 100644 --- a/arknights_mower/templates/conf.yml +++ b/arknights_mower/templates/conf.yml @@ -4,6 +4,7 @@ drone_count_limit: 92 drone_room: '' enable_party: 1 exhaust_require: '' +workaholic: '' free_blacklist: '' ling_xi: 1 maa_adb_path: D:\Program Files\Nox\bin\adb.exe diff --git a/arknights_mower/templates/plan.json b/arknights_mower/templates/plan.json index a40b23116..7d8ef007c 100644 --- a/arknights_mower/templates/plan.json +++ b/arknights_mower/templates/plan.json @@ -6,7 +6,8 @@ "max_resting_count": 4, "exhaust_require": "", "rest_in_full": "", - "resting_priority": "" + "resting_priority": "", + "workaholic": "" } } diff --git a/arknights_mower/utils/operators.py b/arknights_mower/utils/operators.py index 759920a1b..57694de6b 100644 --- a/arknights_mower/utils/operators.py +++ b/arknights_mower/utils/operators.py @@ -139,7 +139,7 @@ def add(self, operator): else: self.groups[operator.group].append(operator.name) if operator.workaholic and operator.name not in self.workaholic_agent: - self.workaholic_agent.append(operator.workaholic) + self.workaholic_agent.append(operator.name) def available_free(self, free_type='high', count=4): ret = 0 @@ -244,7 +244,7 @@ def need_to_refresh(self, h=2, r=""): def not_valid(self): if self.workaholic: - return True + return False if self.operator_type == 'high': if not self.room.startswith("dorm") and self.current_room.startswith("dorm"): if self.mood == -1 or self.mood == 24: diff --git a/menu.py b/menu.py index d99a93db8..2068df33b 100644 --- a/menu.py +++ b/menu.py @@ -44,6 +44,7 @@ def build_plan(url): window['plan_radio_ling_xi_' + str(plan['conf']['ling_xi'])].update(True) window['plan_int_max_resting_count'].update(plan['conf']['max_resting_count']) window['plan_conf_exhaust_require'].update(plan['conf']['exhaust_require']) + window['plan_conf_workaholic'].update(plan['conf']['workaholic']) window['plan_conf_rest_in_full'].update(plan['conf']['rest_in_full']) window['plan_conf_resting_priority'].update(plan['conf']['resting_priority']) except Exception as e: @@ -170,13 +171,13 @@ def menu(): exhaust_require = sg.InputText(plan['conf']['exhaust_require'], size=60, key='plan_conf_exhaust_require', enable_events=True) + workaholic_title = sg.Text('0心情工作的干员:', size=25) + workaholic = sg.InputText(plan['conf']['workaholic'], size=60, + key='plan_conf_workaholic', enable_events=True) + resting_priority_title = sg.Text('宿舍低优先级干员:', size=25) resting_priority = sg.InputText(plan['conf']['resting_priority'], size=60, key='plan_conf_resting_priority', enable_events=True) - # ling_xi_assist_title = sg.Text('协助令夕心情调配的干员:', size=25) - # ling_xi_assist = sg.InputText(conf['ling_xi_assist'], size=60, - # key='conf_ling_xi_assist', enable_events=True) - # --------外部调用设置页面 # mail mail_enable_1 = sg.Radio('启用', 'mail_enable', default=conf['mail_enable'] == 1, @@ -238,9 +239,9 @@ def menu(): [reload_room_title, reload_room], [rest_in_full_title, rest_in_full], [exhaust_require_title, exhaust_require], + [workaholic_title,workaholic], [resting_priority_title, resting_priority], - # [ling_xi_assist_title, ling_xi_assist] 去除协助令夕心情调配项 - [start_automatically], + [start_automatically], ], pad=((10, 10), (10, 10))) other_tab = sg.Tab(' 外部调用 ', From 08392677c45a78a3104510f2872335ea89728066 Mon Sep 17 00:00:00 2001 From: Luowen <1048879349@qq.com> Date: Thu, 18 May 2023 11:00:27 +0800 Subject: [PATCH 49/49] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 290 +++++------------------------------------------------- 1 file changed, 23 insertions(+), 267 deletions(-) diff --git a/README.md b/README.md index 86f2b7b2e..bb66595bd 100644 --- a/README.md +++ b/README.md @@ -1,312 +1,68 @@
-![logo](https://github.com/Konano/arknights-mower/raw/main/logo.png) +![logo](https://github.com/ArkMowers/arknights-mower/raw/main/logo.png) # arknights-mower -[![GitHub License](https://img.shields.io/github/license/Konano/arknights-mower?style=flat-square)](https://github.com/Konano/arknights-mower/blob/master/LICENSE) +[![GitHub License](https://img.shields.io/github/license/ArkMowers/arknights-mower?style=flat-square)](https://github.com/ArkMowers/arknights-mower/blob/master/LICENSE) [![PyPI](https://img.shields.io/pypi/v/arknights-mower?style=flat-square)](https://pypi.org/project/arknights-mower/) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/arknights-mower?style=flat-square)](https://pypi.org/project/arknights-mower/) -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/Konano/arknights-mower/Upload%20PyPI?style=flat-square)](https://github.com/Konano/arknights-mower/actions/workflows/python-publish.yml) -![GitHub last commit (branch)](https://img.shields.io/github/last-commit/Konano/arknights-mower/main?style=flat-square) -[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/Konano/arknights-mower?style=flat-square)](https://codeclimate.com/github/Konano/arknights-mower) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ArkMowers/arknights-mower/Upload%20PyPI?style=flat-square)](https://github.com/ArkMowers/arknights-mower/actions/workflows/python-publish.yml) +![GitHub last commit (branch)](https://img.shields.io/github/last-commit/ArkMowers/arknights-mower/main?style=flat-square) +[![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/ArkMowers/arknights-mower?style=flat-square)](https://codeclimate.com/github/ArkMowers/arknights-mower) 7*24 小时不间断长草,让你忘掉这个游戏!
- ## ⚠ 注意事项 - 本程序不支持国服以外的明日方舟区服,支持官服和 Bilibili 服。 - 原理上,使用本程序没有任何被判定为作弊并被封号的风险,但是作者不对使用此程序造成的任何损失负责。 -- 开发作者课业繁重,有时不太能及时反馈和修复 Bug,见谅一下。 - +- 开发组人数稀少,有时不太能及时反馈和修复 Bug,见谅一下。也欢迎更多有能力有意向的朋友参与。 +- 本软件目前仅支持1920*1080 分辨率,使用夜神模拟器可以解决大部分问题 ## 主要功能 - 自动打开《明日方舟》,支持官服和 Bilibili 服 - 自动登录 - - 账户密码需要手动输入 -- 自动访友收取信用点 -- 自动前往信用商店,领取信用点并按指定优先级购买商品 -- 自动确认任务完成 -- 自动刷体力 - - 默认进行上一次完成的关卡 - - 可设置成优先完成剿灭任务 - - 可自动通过体力药剂和源石回复体力 - - 可限定关卡次数和序列 - - 可指定关卡,包括主线、插曲、别传和资源收集四大区域 -- 自动完成公招 -- 自动收取邮件奖励 -- 自动收取并安放线索 -- 自动消耗无人机加速制造站或贸易站 -- 自动更换基建排班干员(建议搭配配置文件使用, 也可命令行直接输入) + - 账户密码需要手动输入 +- 读取基建心情,根据排班表***动态换班***力求最高工休比 +- 支持***跑单操作***,可设置仅跑单模式 +- 支持调用maa执行除基建外的长草活动 +- 支持邮件提醒 - 自动使用菲亚梅塔恢复指定房间心情最低干员的心情并重回岗位(工作位置不变以避免重新暖机) [[参考使用场景](https://www.bilibili.com/video/BV1mZ4y1z7wx)] -- 支持游戏任意分辨率(低于 1080p 的分辨率可能会有一些问题) - -## 安装 - -程序分为 Pypi 版本和 Windows 可执行文件版本两种。 - -Pypi 版本可通过 pip 直接安装: - -```bash -pip3 install arknights-mower -``` - -也可以在 [Releases](https://github.com/Konano/arknights-mower/releases) 下载 Windows 可执行文件版本。 - -## 运行须知 - -运行脚本需要安装 ADB 并与安卓模拟器进行连接。 -### ADB 配置 -ADB 下载地址: -- Windows: https://dl.google.com/android/repository/platform-tools-latest-windows.zip -- Mac: https://dl.google.com/android/repository/platform-tools-latest-darwin.zip -- Linux: https://dl.google.com/android/repository/platform-tools-latest-linux.zip - -下载 ADB 后需要将 ADB 所在目录添加到环境变量中。请确认 `adb devices` 中列出了目标模拟器或设备: - -``` -$ adb devices -emulator-5554 device -``` - -Windows 下的夜神(Nox)模拟器会自动启动并连接自带的 ADB,如果对配置 ADB 比较苦手的人可以换用夜神(Nox)模拟器。 - -### 模拟器配置 - -_TODO:因为各家模拟器的运行情况都不一样,所以有必要梳理一下各家模拟器如何搭配程序使用,此处留一坑待填_ +## 安装 -Linux 下可以使用 Anbox 来运行 Android 模拟器,[参见教程](https://www.cnblogs.com/syisyuan/p/12811595.html)。 +在 [Releases](https://github.com/ArkMowers/arknights-mower/releases) 下载 Windows 可执行文件版本。 +在 [action](https://github.com/ArkMowers/arknights-mower/actions/workflows/pyinstaller-win-shawn.yml) 产物下载最新测试版本 +或进入下方qq群文件领取,目前软件迭代速度较快,进入群内可获取一手版本 ## 使用教程 -第一次运行程序时,会在可执行文件的同目录(Windows 可执行文件版本)或 Home 目录(Linux 下为 `~/`,Windows 下为 `%HOMEPATH%` 或 `C:/Users/你的用户名/`)处生成配置文件 `config.yaml`(Windows 可执行文件版本)或 `.ark_mower.yaml`(Pypi 版本)。 - -**强烈建议在开始使用程序前仔细阅读配置文件内的注释说明,并根据自身情况修改配置文件中各项的值,否则可能无法正常运行。** - -Pypi 版本只支持命令行模式启动,Windows 可执行文件版本支持命令行模式启动和双击文件启动。 - -直接双击运行 Windows 可执行文件版本将会执行配置文件内所设定的计划任务,自动进行收邮件、收信用点、收基建产物、刷体力等操作。 - -若想更进一步指定运行的功能,则需要通过命令行模式启动。Windows 可执行文件版本需要通过 cmd 或 powershell 指定命令行运行的参数。 +* 下载安装后,打开软件 +* 设置adb地址(如127.0.0.1:5555) +* 配置排班表[[配置方法](https://www.bilibili.com/video/BV1KT411s7Ar)]或前往qq群寻找现成的排班表导入 +* 点击开始执行 +* 详细配置内容请参考[[功能文档](https://arkmowers.github.io/arknights-mower/)] -命令行模式下的使用说明如下: -``` -$ arknights-mower -usage: arknights-mower command [command args] [--config filepath] [--debug] -commands (prefix abbreviation accepted): - base [plan] [-c] [-d[F][N]] [-f[F][N]] - 自动处理基建的信赖/货物/订单/线索/无人机 - plan 自动更换基建排班干员(建议搭配配置文件使用,也可命令行直接输入) - -c 是否自动收集并使用线索 - -d 是否自动消耗无人机,F 表示第几层(1-3),N 表示从左往右第几个房间(1-3) - -f 是否自动使用菲亚梅塔恢复指定房间心情最差干员的心情并恢复原位,F、N 含义同上 - credit - 自动访友获取信用点 - mail - 自动收取邮件 - mission - 收集每日任务和每周任务奖励 - shop [items ...] - 自动前往商店消费信用点 - items 优先考虑的物品,若不指定则使用配置文件中的优先级,默认为从上到下从左到右购买 - recruit [agents ...] - 自动进行公共招募 - agents 优先考虑的公招干员,若不指定则使用配置文件中的优先级,默认为高稀有度优先 - operation [level] [n] [-r[N]] [-R[N]] [-e|-E] - 自动进行作战,可指定次数或直到理智不足 - level 指定关卡名称,未指定则默认前往上一次关卡 - n 指定作战次数,未指定则默认作战直到理智不足 - -r 是否自动回复理智,最多回复 N 次,N 未指定则表示不限制回复次数 - -R 是否使用源石回复理智,最多回复 N 次,N 未指定则表示不限制回复次数 - -e 是否优先处理未完成的每周剿灭,优先使用代理卡;-E 表示只使用代理卡而不消耗理智 - operation --plan - (使用配置文件中的参数以及计划)自动进行作战 - version - 输出版本信息 - help - 输出本段消息 - schedule - 执行配置文件中的计划任务 - --debug - 启用调试功能,调试信息将会输出到 /root/work/arknights-mower/log 中 - --config filepath - 指定配置文件,默认使用 /root/work/arknights-mower/config.yaml -``` - -命令行模式下的具体使用例子如下: - -``` -arknights-mower operation -# 重复刷上一次关卡,直到理智不足停止 -arknights-mower operation 99 -# 重复刷上一次关卡 99 次 -arknights-mower operation -r5 -# 重复刷上一次关卡,使用理智药自动回复理智,最多消耗 5 瓶(直到理智不足停止) -arknights-mower operation -r -# 重复刷上一次关卡,使用理智药自动回复理智,直到理智药用完为止 -arknights-mower operation 1-7 99 -R5 -# 重复刷 1-7 关卡 99 次,使用源石自动回复理智,最多消耗 5 颗 -arknights-mower operation GT-1 99 -r5 -R5 -# 重复刷 GT-1 关卡 99 次,使用理智药以及源石自动回复理智,最多消耗 5 瓶理智药和 5 颗源石 -arknights-mower recruit 因陀罗 火神 -# 公招自动化,优先选择保底星数高的组合,若有多种标签组合保底星数一致则优先选择包含优先级高的干员的组合,公招干员的优先级从高到低分别是因陀罗和火神,默认为高稀有度优先 -arknights-mower shop 招聘许可 赤金 龙门币 -# 在商场使用信用点消费,购买物品的优先级从高到低分别是招聘许可、赤金和龙门币,其余物品不购买 -arknights-mower base -f12 plan_2 -# 自动使用菲亚梅塔恢复B102房间心情最差干员的心情,并保持原位;自动进行配置文件中名为`plan_2`的的基建排班 -arknights-mower base -c -d33 -# 自动收取基建中的信赖/货物/订单;自动放置线索;自动前往 B303 房间(地下 3 层从左往右数第 3 间)使用无人机加速生产或贸易订单; -arknights-mower base room_1_2 柏喙 巫恋 龙舌兰 contact 絮雨 dormitory_1 杜林 Free Free Free Free -# 自动更换基建B102房间干员为 柏喙 巫恋 龙舌兰, 更换办公室干员为 絮雨, 更换1号宿舍干员为 杜林和任意4个空闲干员(房间名请参考 base.json) -``` - -命令可使用前缀或首字母缩写,如: - -``` -arknights-mower h -# 输出帮助信息 -arknights-mower ope -# 重复刷上一次关卡,直到理智不足停止 -arknights-mower o 1-7 99 -r5 -R5 -# 重复刷 1-7 关卡 99 次,使用理智药以及源石自动回复理智,最多消耗 5 瓶理智药和 5 颗源石 -``` - -**请注意:基建自动换班需要搭配配置文件使用。** - -## 更多高级功能 - -如果想定制更加复杂的定时计划等其他高级功能,可根据个人需求修改 [diy.py](https://github.com/Konano/arknights-mower/blob/main/diy.py) 并运行,具体见文件内注释说明。 - -如果想添加其他的功能,你甚至可以创建一个继承 `BaseSolver` 的自定义类,通过现有接口实现自己的想法。这里展示了一种可能的例子: - -```python -from arknights_mower.strategy import Solver - -# 自定义基建排班 -# 这里自定义了一套排班策略,实现的是两班倒,分为四个阶段 -# 阶段 1 和 2 为第一班,阶段 3 和 4 为第二班 -# 第一班的干员在阶段 3 和 4 分两批休息,第二班同理 -# 每个阶段耗时 6 小时 - -# 若菲亚梅塔出现在列表中,则会优先选择菲亚梅塔,以防止其与意料之外的干员交换心情 - -plan = { - # 阶段 1 - 'plan_1': { - # 控制中枢 - 'central': ['夕', '令', '凯尔希', '阿米娅', '玛恩纳'], - # 办公室 - 'contact': ['艾雅法拉'], - # 宿舍 - 'dormitory_1': ['杜林', '闪灵', '安比尔', '空弦', '缠丸'], - 'dormitory_2': ['推进之王', '琴柳', '赫默', '杰西卡', '调香师'], - 'dormitory_3': ['夜莺', '波登可', '夜刀', '古米', '空爆'], - 'dormitory_4': ['空', 'Lancet-2', '香草', '史都华德', '刻俄柏'], - # 会客室 - 'meeting': ['陈', '红'], - # 制造站 + 贸易站 + 发电站 - 'room_1_1': ['德克萨斯', '能天使', '拉普兰德'], - 'room_1_2': ['断罪者', '食铁兽', '槐琥'], - 'room_1_3': ['阿消'], - 'room_2_1': ['巫恋', '柏喙', '慕斯'], - 'room_2_2': ['红豆', '霜叶', '白雪'], - 'room_2_3': ['雷蛇'], - 'room_3_1': ['Castle-3', '梅尔', '白面鸮'], - 'room_3_2': ['格雷伊'], - 'room_3_3': ['砾', '夜烟', '斑点'] - }, - # 阶段 2 - 'plan_2': { - # 注释掉了部分和阶段 1 一样排班计划的房间,加快排班速度 - # 'contact': ['艾雅法拉'], - 'dormitory_1': ['杜林', '闪灵', '芬', '稀音', '克洛丝'], - 'dormitory_2': ['推进之王', '琴柳', '清流', '森蚺', '温蒂'], - 'dormitory_3': ['夜莺', '波登可', '伊芙利特', '深靛', '炎熔'], - 'dormitory_4': ['空', 'Lancet-2', '远山', '星极', '普罗旺斯'], - # 'meeting': ['陈', '红'], - # 'room_1_1': ['德克萨斯', '能天使', '拉普兰德'], - # 'room_1_2': ['断罪者', '食铁兽', '槐琥'], - # 'room_1_3': ['阿消'], - # 'room_2_1': ['巫恋', '柏喙', '慕斯'], - # 'room_2_2': ['红豆', '霜叶', '白雪'], - # 'room_2_3': ['雷蛇'], - # 'room_3_1': ['Castle-3', '梅尔', '白面鸮'], - # 'room_3_2': ['格雷伊'], - # 'room_3_3': ['砾', '夜烟', '斑点'] - }, - 'plan_3': { - 'contact': ['普罗旺斯'], - 'dormitory_1': ['杜林', '闪灵', '格雷伊', '雷蛇', '阿消'], - 'dormitory_2': ['推进之王', '琴柳', '德克萨斯', '能天使', '拉普兰德'], - 'dormitory_3': ['夜莺', '波登可', '巫恋', '柏喙', '慕斯'], - 'dormitory_4': ['空', 'Lancet-2', '艾雅法拉', '陈', '红'], - 'meeting': ['远山', '星极'], - 'room_1_1': ['安比尔', '空弦', '缠丸'], - 'room_1_2': ['赫默', '杰西卡', '调香师'], - 'room_1_3': ['伊芙利特'], - 'room_2_1': ['夜刀', '古米', '空爆'], - 'room_2_2': ['香草', '史都华德', '刻俄柏'], - 'room_2_3': ['深靛'], - 'room_3_1': ['芬', '稀音', '克洛丝'], - 'room_3_2': ['炎熔'], - 'room_3_3': ['清流', '森蚺', '温蒂'] - }, - 'plan_4': { - # 'contact': ['普罗旺斯'], - 'dormitory_1': ['杜林', '闪灵', '断罪者', '食铁兽', '槐琥'], - 'dormitory_2': ['推进之王', '琴柳', '红豆', '霜叶', '白雪'], - 'dormitory_3': ['夜莺', '波登可', 'Castle-3', '梅尔', '白面鸮'], - 'dormitory_4': ['空', 'Lancet-2', '砾', '夜烟', '斑点'], - # 'meeting': ['远山', '星极'], - # 'room_1_1': ['安比尔', '空弦', '缠丸'], - # 'room_1_2': ['赫默', '杰西卡', '调香师'], - # 'room_1_3': ['伊芙利特'], - # 'room_2_1': ['夜刀', '古米', '空爆'], - # 'room_2_2': ['香草', '史都华德', '刻俄柏'], - # 'room_2_3': ['深靛'], - # 'room_3_1': ['芬', '稀音', '克洛丝'], - # 'room_3_2': ['炎熔'], - # 'room_3_3': ['清流', '森蚺', '温蒂'] - } -} - -Solver().base(arrange=plan) -``` 欢迎大家提交 Pull requests 增加更多的功能! -## 常见问题 Q&A - -#### 运行时出现错误:An error occurred when loading the configuration file - -配置文件出现格式错误,可以结合 [在线 YAML 校验器](https://www.bejson.com/validators/yaml_editor/) 进行检查。 - -#### 大量出现「识别出了点小差错」并卡死在特定界面 - -当前版本在非 1080p(1920x1080)分辨率下,对于部分界面的识别可能会出现错误,将模拟器修改为 1080p 分辨率可以解决大部分问题。如果在分辨率修改后问题仍未解决,可以在 Issue 页面提出。 - -#### 提示「未检测到相应设备。请运行 `adb devices` 确认列表中列出了目标模拟器或设备。」 - -- 夜神(Nox)模拟器:[解决办法](https://github.com/Konano/arknights-mower/issues/117#issuecomment-1118447644) - ## 遇到报错?想要更多功能? 如果你在使用过程中遇到问题,欢迎通过提交 Issue 的方式报错或者提问。报告 Issue 时建议附上调试信息以便定位问题。 也欢迎加入交流群讨论: -- [Telegram Group](https://t.me/joinchat/eFkqRj1IWm9kYTBl) +- [Telegram Group](https://t.me/ark_mover) - [QQ Group](https://jq.qq.com/?_wv=1027&k=4gWboTVI): 239200680 ## Star History
-[![Star History Chart](https://api.star-history.com/svg?repos=Konano/arknights-mower&type=Date)](https://star-history.com/#Konano/arknights-mower&Date) +[![Star History Chart](https://api.star-history.com/svg?repos=ArkMowers/arknights-mower&type=Date)](https://star-history.com/#ArkMowers/arknights-mower&Date)