diff --git a/README.md b/README.md index 3f55221..3d5d9ca 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ MAA多账号管理与自动化软件 [![GitHub Issues](https://img.shields.io/github/issues/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/issues) [![GitHub Contributors](https://img.shields.io/github/contributors/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/graphs/contributors) [![GitHub License](https://img.shields.io/github/license/DLmaster361/AUTO_MAA?style=flat-square)](https://github.com/DLmaster361/AUTO_MAA/blob/main/LICENSE) +[![mirrorc](https://img.shields.io/badge/Mirror%E9%85%B1-%239af3f6?logo=countingworkspro&logoColor=4f46e5)](https://mirrorchyan.com/zh/projects?rid=AUTO_MAA) ## 软件介绍 diff --git a/app/core/config.py b/app/core/config.py index bae7513..231ab69 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -409,27 +409,24 @@ class MaaConfig(QConfig): "ExitEmulator", OptionsValidator(["NoAction", "ExitGame", "ExitEmulator"]), ) - self.RunSet_EnhanceTask = OptionsConfigItem( - "RunSet", - "EnhanceTask", - "None", - OptionsValidator(["None", "KillADB", "KillEmulator", "KillADB&Emulator"]), - ) self.RunSet_ProxyTimesLimit = RangeConfigItem( "RunSet", "ProxyTimesLimit", 0, RangeValidator(0, 1024) ) + self.RunSet_RunTimesLimit = RangeConfigItem( + "RunSet", "RunTimesLimit", 3, RangeValidator(1, 1024) + ) self.RunSet_AnnihilationTimeLimit = RangeConfigItem( "RunSet", "AnnihilationTimeLimit", 40, RangeValidator(1, 1024) ) self.RunSet_RoutineTimeLimit = RangeConfigItem( "RunSet", "RoutineTimeLimit", 10, RangeValidator(1, 1024) ) - self.RunSet_RunTimesLimit = RangeConfigItem( - "RunSet", "RunTimesLimit", 3, RangeValidator(1, 1024) - ) self.RunSet_AnnihilationWeeklyLimit = ConfigItem( "RunSet", "AnnihilationWeeklyLimit", False, BoolValidator() ) + self.RunSet_AutoUpdateMaa = ConfigItem( + "RunSet", "AutoUpdateMaa", False, BoolValidator() + ) def toDict(self, serialize=True): """convert config items to `dict`""" @@ -521,17 +518,22 @@ class MaaUserConfig(QConfig): "Info", "Annihilation", False, BoolValidator() ) self.Info_Routine = ConfigItem("Info", "Routine", False, BoolValidator()) - self.Info_Infrastructure = ConfigItem( - "Info", "Infrastructure", False, BoolValidator() + self.Info_InfrastMode = OptionsConfigItem( + "Info", + "InfrastMode", + "Normal", + OptionsValidator(["Normal", "Rotation", "Custom"]), ) self.Info_Password = ConfigItem("Info", "Password", "") self.Info_Notes = ConfigItem("Info", "Notes", "无") self.Info_MedicineNumb = ConfigItem( "Info", "MedicineNumb", 0, RangeValidator(0, 1024) ) + self.Info_SeriesNumb = ConfigItem("Info", "SeriesNumb", 1, RangeValidator(1, 6)) self.Info_GameId = ConfigItem("Info", "GameId", "-") self.Info_GameId_1 = ConfigItem("Info", "GameId_1", "-") self.Info_GameId_2 = ConfigItem("Info", "GameId_2", "-") + self.Info_GameId_Remain = ConfigItem("Info", "GameId_Remain", "-") self.Data_LastProxyDate = ConfigItem("Data", "LastProxyDate", "2000-01-01") self.Data_LastAnnihilationDate = ConfigItem( @@ -541,6 +543,9 @@ class MaaUserConfig(QConfig): "Data", "ProxyTimes", 0, RangeValidator(0, 1024) ) self.Data_IfPassCheck = ConfigItem("Data", "IfPassCheck", True, BoolValidator()) + self.Data_CustomInfrastPlanIndex = ConfigItem( + "Data", "CustomInfrastPlanIndex", "0" + ) def toDict(self, serialize=True): """convert config items to `dict`""" @@ -609,7 +614,7 @@ class MaaUserConfig(QConfig): class AppConfig(GlobalConfig): - VERSION = "4.3.4.0" + VERSION = "4.3.5.0" gameid_refreshed = Signal() PASSWORD_refreshed = Signal() @@ -1289,6 +1294,10 @@ class AppConfig(GlobalConfig): user_config.set( user_config.Data_IfPassCheck, info["Config"]["Data"]["IfPassCheck"] ) + user_config.set( + user_config.Data_CustomInfrastPlanIndex, + info["Config"]["Data"]["CustomInfrastPlanIndex"], + ) self.user_info_changed.emit() diff --git a/app/core/network.py b/app/core/network.py index 2f5d718..5c91d8b 100644 --- a/app/core/network.py +++ b/app/core/network.py @@ -78,6 +78,8 @@ class _Network(QThread): def get_json(self, url: str) -> None: """通过get方法获取json数据""" + response = None + for _ in range(self.max_retries): try: response = requests.get(url, timeout=self.timeout) @@ -94,7 +96,9 @@ class _Network(QThread): self.loop.quit() def get_file(self, url: str, path: Path) -> None: - """通过get方法获取json数据""" + """通过get方法下载文件""" + + response = None try: response = requests.get(url, timeout=10) diff --git a/app/core/task_manager.py b/app/core/task_manager.py index 3b6d93f..51ad27f 100644 --- a/app/core/task_manager.py +++ b/app/core/task_manager.py @@ -154,6 +154,7 @@ class Task(QThread): Config.running_list.remove(task[2]) task[1] = "完成" + self.update_task_list.emit(self.task_list) logger.info(f"任务完成:{task[0]}") self.push_info_bar.emit("info", "任务完成", task[0], 3000) diff --git a/app/models/MAA.py b/app/models/MAA.py index 8b5f254..e036f08 100644 --- a/app/models/MAA.py +++ b/app/models/MAA.py @@ -28,11 +28,12 @@ v4.3 from loguru import logger from PySide6.QtCore import QObject, Signal, QEventLoop, QFileSystemWatcher, QTimer import json -from datetime import datetime, timedelta import subprocess import shutil import time import re +import win32com.client +from datetime import datetime, timedelta from pathlib import Path from jinja2 import Environment, FileSystemLoader from typing import Union, List, Dict @@ -90,6 +91,7 @@ class MaaManager(QObject): self.interrupt.connect(self.quit_monitor) self.maa_version = None + self.maa_update_package = "" self.set = config["Config"].toDict() self.data = {} @@ -287,6 +289,41 @@ class MaaManager(QObject): self.emulator_arguments = set["Configurations"]["Default"][ "Start.EmulatorAddCommand" ].split() + # 如果是快捷方式,进行解析 + if ( + self.emulator_path.suffix == ".lnk" + and self.emulator_path.exists() + ): + try: + shell = win32com.client.Dispatch("WScript.Shell") + shortcut = shell.CreateShortcut(str(self.emulator_path)) + self.emulator_path = Path(shortcut.TargetPath) + self.emulator_arguments = shortcut.Arguments.split() + except Exception as e: + logger.error( + f"{self.name} | 解析快捷方式时出现异常:{e}" + ) + self.push_info_bar.emit( + "error", + "解析快捷方式时出现异常", + "请检查快捷方式", + -1, + ) + self.if_open_emulator = True + break + elif not self.emulator_path.exists(): + logger.error( + f"{self.name} | 模拟器快捷方式不存在:{self.emulator_path}" + ) + self.push_info_bar.emit( + "error", + "启动模拟器时出现异常", + "模拟器快捷方式不存在", + -1, + ) + self.if_open_emulator = True + break + self.ADB_path = Path( set["Configurations"]["Default"]["Connect.AdbPath"] ) @@ -309,26 +346,23 @@ class MaaManager(QObject): == "True" ) - # 增强任务:任务开始前强杀ADB - if "ADB" in self.set["RunSet"]["EnhanceTask"]: - System.kill_process(self.ADB_path) - else: - try: - subprocess.run( - [self.ADB_path, "disconnect", self.ADB_address], - creationflags=subprocess.CREATE_NO_WINDOW, - ) - except subprocess.CalledProcessError as e: - # 忽略错误,因为可能本来就没有连接 - logger.warning(f"{self.name} | 释放ADB时出现异常:{e}") - except Exception as e: - logger.error(f"{self.name} | 释放ADB时出现异常:{e}") - self.push_info_bar.emit( - "error", - "释放ADB时出现异常", - "请检查MAA中ADB路径设置", - -1, - ) + # 任务开始前释放ADB + try: + subprocess.run( + [self.ADB_path, "disconnect", self.ADB_address], + creationflags=subprocess.CREATE_NO_WINDOW, + ) + except subprocess.CalledProcessError as e: + # 忽略错误,因为可能本来就没有连接 + logger.warning(f"{self.name} | 释放ADB时出现异常:{e}") + except Exception as e: + logger.error(f"{self.name} | 释放ADB时出现异常:{e}") + self.push_info_bar.emit( + "error", + "释放ADB时出现异常", + "请检查MAA中ADB路径设置", + -1, + ) if self.if_open_emulator_process: try: @@ -359,13 +393,37 @@ class MaaManager(QObject): self.start_monitor(start_time, mode_book[mode]) if self.maa_result == "Success!": + + # 标记任务完成 + run_book[mode] = True + + # 从配置文件中解析所需信息 + with self.maa_set_path.open( + mode="r", encoding="utf-8" + ) as f: + data = json.load(f) + user_data["Data"]["CustomInfrastPlanIndex"] = data[ + "Configurations" + ]["Default"]["Infrast.CustomInfrastPlanIndex"] + + if ( + data["Global"]["VersionUpdate.package"] + and ( + self.maa_root_path + / data["Global"]["VersionUpdate.package"] + ).exists() + ): + self.maa_update_package = data["Global"][ + "VersionUpdate.package" + ] + logger.info( f"{self.name} | 用户: {user[0]} - MAA进程完成代理任务" ) - run_book[mode] = True self.update_log_text.emit( "检测到MAA进程完成代理任务\n正在等待相关程序结束\n请等待10s" ) + for _ in range(10): if self.isInterruptionRequested: break @@ -382,13 +440,28 @@ class MaaManager(QObject): # 无命令行中止MAA与其子程序 System.kill_process(self.maa_exe_path) - if "Emulator" in self.set["RunSet"]["EnhanceTask"]: - System.kill_process(self.emulator_path) - else: - self.emulator_process.terminate() - self.emulator_process.wait() + # 中止模拟器进程 + self.emulator_process.terminate() + self.emulator_process.wait() self.if_open_emulator = True + + # 从配置文件中解析所需信息 + with self.maa_set_path.open( + mode="r", encoding="utf-8" + ) as f: + data = json.load(f) + if ( + data["Global"]["VersionUpdate.package"] + and ( + self.maa_root_path + / data["Global"]["VersionUpdate.package"] + ).exists() + ): + self.maa_update_package = data["Global"][ + "VersionUpdate.package" + ] + # 推送异常通知 Notify.push_plyer( "用户自动代理出现异常!", @@ -404,34 +477,52 @@ class MaaManager(QObject): # 移除静默进程标记 Config.silence_list.remove(self.emulator_path) - # 增强任务:任务结束后强杀ADB和模拟器或释放进程 - if "ADB" in self.set["RunSet"]["EnhanceTask"]: - System.kill_process(self.ADB_path) - else: - try: - subprocess.run( - [self.ADB_path, "disconnect", self.ADB_address], - creationflags=subprocess.CREATE_NO_WINDOW, - ) - except subprocess.CalledProcessError as e: - # 忽略错误,因为可能本来就没有连接 - logger.warning(f"{self.name} | 释放ADB时出现异常:{e}") - except Exception as e: - logger.error(f"{self.name} | 释放ADB时出现异常:{e}") - self.push_info_bar.emit( - "error", - "释放ADB时出现异常", - "请检查MAA中ADB路径设置", - -1, - ) + # 任务结束后释放ADB + try: + subprocess.run( + [self.ADB_path, "disconnect", self.ADB_address], + creationflags=subprocess.CREATE_NO_WINDOW, + ) + except subprocess.CalledProcessError as e: + # 忽略错误,因为可能本来就没有连接 + logger.warning(f"{self.name} | 释放ADB时出现异常:{e}") + except Exception as e: + logger.error(f"{self.name} | 释放ADB时出现异常:{e}") + self.push_info_bar.emit( + "error", + "释放ADB时出现异常", + "请检查MAA中ADB路径设置", + -1, + ) + # 任务结束后再次手动中止模拟器进程,防止退出不彻底 if self.if_kill_emulator: - if "Emulator" in self.set["RunSet"]["EnhanceTask"]: - System.kill_process(self.emulator_path) - else: - self.emulator_process.terminate() - self.emulator_process.wait() + self.emulator_process.terminate() + self.emulator_process.wait() self.if_open_emulator = True + # 执行MAA解压更新动作 + if self.maa_update_package: + + logger.info( + f"{self.name} | 检测到MAA更新,正在执行更新动作" + ) + + self.update_log_text.emit( + f"检测到MAA存在更新\nMAA正在执行更新动作\n请等待10s" + ) + self.set_maa("更新MAA", None) + subprocess.Popen( + [self.maa_exe_path], + creationflags=subprocess.CREATE_NO_WINDOW, + ) + for _ in range(10): + if self.isInterruptionRequested: + break + time.sleep(1) + System.kill_process(self.maa_exe_path) + + logger.info(f"{self.name} | 更新动作结束") + # 记录剿灭情况 if ( mode == "Annihilation" @@ -747,7 +838,7 @@ class MaaManager(QObject): self.update_log_text.emit("".join(logs)) # 获取MAA版本号 - if not self.maa_version: + if not self.set["RunSet"]["AutoUpdateMaa"] and not self.maa_version: section_match = re.search(r"={35}(.*?)={35}", log, re.DOTALL) if section_match: @@ -859,7 +950,7 @@ class MaaManager(QObject): """配置MAA运行参数""" logger.info(f"{self.name} | 配置MAA运行参数: {mode}/{index}") - if "设置MAA" not in self.mode: + if "设置MAA" not in self.mode and "更新MAA" not in mode: user_data = self.data[index]["Config"] # 配置MAA前关闭可能未正常退出的MAA进程 @@ -874,7 +965,7 @@ class MaaManager(QObject): self.config_path / "Default/gui.json", self.maa_set_path, ) - elif (mode == "设置MAA_全局") or ( + elif (mode in ["设置MAA_全局", "更新MAA"]) or ( ("自动代理" in mode or "人工排查" in mode) and user_data["Info"]["Mode"] == "简洁" ): @@ -901,7 +992,7 @@ class MaaManager(QObject): with self.maa_set_path.open(mode="r", encoding="utf-8") as f: data = json.load(f) - if "设置MAA" not in mode and ( + if ("设置MAA" not in self.mode and "更新MAA" not in mode) and ( ( user_data["Info"]["Mode"] == "简洁" and user_data["Info"]["Server"] == "Bilibili" @@ -949,10 +1040,20 @@ class MaaManager(QObject): data["Configurations"]["Default"][ "Start.RunDirectly" ] = "True" # 启动MAA后直接运行 - data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = ( - "True" if self.if_open_emulator else "False" + data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = str( + self.if_open_emulator ) # 启动MAA后自动开启模拟器 + data["Global"][ + "VersionUpdate.ScheduledUpdateCheck" + ] = "False" # 定时检查更新 + data["Global"]["VersionUpdate.AutoDownloadUpdatePackage"] = str( + self.set["RunSet"]["AutoUpdateMaa"] + ) # 自动下载更新包 + data["Global"][ + "VersionUpdate.AutoInstallUpdatePackage" + ] = "False" # 自动安装更新包 + if Config.get(Config.function_IfSilence): data["Global"]["Start.MinimizeDirectly"] = "True" # 启动MAA后直接最小化 data["Global"]["GUI.UseTray"] = "True" # 显示托盘图标 @@ -972,21 +1073,22 @@ class MaaManager(QObject): if user_data["Info"]["Mode"] == "简洁": - data["Global"][ - "VersionUpdate.ScheduledUpdateCheck" - ] = "False" # 定时检查更新 - data["Global"][ - "VersionUpdate.AutoDownloadUpdatePackage" - ] = "False" # 自动下载更新包 - data["Global"][ - "VersionUpdate.AutoInstallUpdatePackage" - ] = "False" # 自动安装更新包 data["Configurations"]["Default"]["Start.ClientType"] = user_data[ "Info" ][ "Server" ] # 客户端类型 + # 整理任务顺序 + data["Configurations"]["Default"]["TaskQueue.Order.WakeUp"] = "0" + data["Configurations"]["Default"]["TaskQueue.Order.Recruiting"] = "1" + data["Configurations"]["Default"]["TaskQueue.Order.Base"] = "2" + data["Configurations"]["Default"]["TaskQueue.Order.Combat"] = "3" + data["Configurations"]["Default"]["TaskQueue.Order.Mall"] = "4" + data["Configurations"]["Default"]["TaskQueue.Order.Mission"] = "5" + data["Configurations"]["Default"]["TaskQueue.Order.AutoRoguelike"] = "6" + data["Configurations"]["Default"]["TaskQueue.Order.Reclamation"] = "7" + if "剿灭" in mode: data["Configurations"]["Default"][ @@ -1097,55 +1199,47 @@ class MaaManager(QObject): if user_data["Info"]["GameId_2"] != "-" else "" ) # 备选关卡2 + data["Configurations"]["Default"]["Fight.RemainingSanityStage"] = ( + user_data["Info"]["GameId_Remain"] + if user_data["Info"]["GameId_Remain"] != "-" + else "" + ) # 剩余理智关卡 data["Configurations"]["Default"][ - "Fight.RemainingSanityStage" - ] = "" # 剩余理智关卡 - # 连战次数 - if user_data["Info"]["GameId"] == "1-7": - data["Configurations"]["Default"][ - "MainFunction.Series.Quantity" - ] = "6" - else: - data["Configurations"]["Default"][ - "MainFunction.Series.Quantity" - ] = "1" + "MainFunction.Series.Quantity" + ] = str( + user_data["Info"]["SeriesNumb"] + ) # 连战次数 data["Configurations"]["Default"][ "Penguin.IsDrGrandet" ] = "False" # 博朗台模式 data["Configurations"]["Default"][ "GUI.CustomStageCode" ] = "True" # 手动输入关卡名 - # 备选关卡 - if ( - user_data["Info"]["GameId_1"] == "-" - and user_data["Info"]["GameId_2"] == "-" - ): - data["Configurations"]["Default"][ - "GUI.UseAlternateStage" - ] = "False" - else: - data["Configurations"]["Default"][ - "GUI.UseAlternateStage" - ] = "True" + data["Configurations"]["Default"][ + "GUI.UseAlternateStage" + ] = "True" # 备选关卡 data["Configurations"]["Default"][ "Fight.UseRemainingSanityStage" - ] = "False" # 使用剩余理智 + ] = "True" # 使用剩余理智 data["Configurations"]["Default"][ "Fight.UseExpiringMedicine" ] = "True" # 无限吃48小时内过期的理智药 # 自定义基建配置 - if user_data["Info"]["Infrastructure"]: + if user_data["Info"]["InfrastMode"] == "Custom": if ( self.data[index]["Path"] / "Infrastructure/infrastructure.json" ).exists(): + data["Configurations"]["Default"][ - "Infrast.CustomInfrastEnabled" - ] = "True" # 启用自定义基建配置 + "Infrast.InfrastMode" + ] = "Custom" # 基建模式 data["Configurations"]["Default"][ "Infrast.CustomInfrastPlanIndex" - ] = "1" # 自定义基建配置索引 + ] = user_data["Data"][ + "CustomInfrastPlanIndex" + ] # 自定义基建配置索引 data["Configurations"]["Default"][ "Infrast.DefaultInfrast" ] = "user_defined" # 内置配置 @@ -1170,11 +1264,13 @@ class MaaManager(QObject): ) data["Configurations"]["Default"][ "Infrast.CustomInfrastEnabled" - ] = "False" # 禁用自定义基建配置 + ] = "Normal" # 基建模式 else: data["Configurations"]["Default"][ - "Infrast.CustomInfrastEnabled" - ] = "False" # 禁用自定义基建配置 + "Infrast.InfrastMode" + ] = user_data["Info"][ + "InfrastMode" + ] # 基建模式 elif user_data["Info"]["Mode"] == "详细": @@ -1207,19 +1303,22 @@ class MaaManager(QObject): if user_data["Info"]["GameId_2"] != "-" else "" ) # 备选关卡2 - - # 备选关卡 - if ( - user_data["Info"]["GameId_1"] == "-" - and user_data["Info"]["GameId_2"] == "-" - ): - data["Configurations"]["Default"][ - "GUI.UseAlternateStage" - ] = "False" - else: - data["Configurations"]["Default"][ - "GUI.UseAlternateStage" - ] = "True" + data["Configurations"]["Default"]["Fight.RemainingSanityStage"] = ( + user_data["Info"]["GameId_Remain"] + if user_data["Info"]["GameId_Remain"] != "-" + else "" + ) # 剩余理智关卡 + data["Configurations"]["Default"][ + "MainFunction.Series.Quantity" + ] = str( + user_data["Info"]["SeriesNumb"] + ) # 连战次数 + data["Configurations"]["Default"][ + "GUI.UseAlternateStage" + ] = "True" # 备选关卡 + data["Configurations"]["Default"][ + "Fight.UseRemainingSanityStage" + ] = "True" # 使用剩余理智 # 人工排查配置 elif "人工排查" in mode: @@ -1237,8 +1336,8 @@ class MaaManager(QObject): data["Global"]["GUI.UseTray"] = "True" # 显示托盘图标 data["Global"]["GUI.MinimizeToTray"] = "True" # 最小化时隐藏至托盘 - data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = ( - "True" if self.if_open_emulator else "False" + data["Configurations"]["Default"]["Start.OpenEmulatorAfterLaunch"] = str( + self.if_open_emulator ) # 启动MAA后自动开启模拟器 # 账号切换 @@ -1352,8 +1451,63 @@ class MaaManager(QObject): "TaskQueue.Reclamation.IsChecked" ] = "False" # 生息演算 + elif mode == "更新MAA": + + data["Current"] = "Default" # 切换配置 + for i in range(1, 9): + data["Global"][f"Timer.Timer{i}"] = "False" # 时间设置 + data["Configurations"]["Default"][ + "MainFunction.PostActions" + ] = "0" # 完成后无动作 + data["Configurations"]["Default"][ + "Start.RunDirectly" + ] = "False" # 启动MAA后直接运行 + data["Configurations"]["Default"][ + "Start.OpenEmulatorAfterLaunch" + ] = "False" # 启动MAA后自动开启模拟器 + data["Global"]["Start.MinimizeDirectly"] = "True" # 启动MAA后直接最小化 + data["Global"]["GUI.UseTray"] = "True" # 显示托盘图标 + data["Global"]["GUI.MinimizeToTray"] = "True" # 最小化时隐藏至托盘 + data["Global"][ + "VersionUpdate.package" + ] = self.maa_update_package # 更新包路径 + + data["Global"][ + "VersionUpdate.ScheduledUpdateCheck" + ] = "False" # 定时检查更新 + data["Global"][ + "VersionUpdate.AutoDownloadUpdatePackage" + ] = "False" # 自动下载更新包 + data["Global"][ + "VersionUpdate.AutoInstallUpdatePackage" + ] = "True" # 自动安装更新包 + data["Configurations"]["Default"][ + "TaskQueue.WakeUp.IsChecked" + ] = "False" # 开始唤醒 + data["Configurations"]["Default"][ + "TaskQueue.Recruiting.IsChecked" + ] = "False" # 自动公招 + data["Configurations"]["Default"][ + "TaskQueue.Base.IsChecked" + ] = "False" # 基建换班 + data["Configurations"]["Default"][ + "TaskQueue.Combat.IsChecked" + ] = "False" # 刷理智 + data["Configurations"]["Default"][ + "TaskQueue.Mission.IsChecked" + ] = "False" # 领取奖励 + data["Configurations"]["Default"][ + "TaskQueue.Mall.IsChecked" + ] = "False" # 获取信用及购物 + data["Configurations"]["Default"][ + "TaskQueue.AutoRoguelike.IsChecked" + ] = "False" # 自动肉鸽 + data["Configurations"]["Default"][ + "TaskQueue.Reclamation.IsChecked" + ] = "False" # 生息演算 + # 启动模拟器仅生效一次 - if "设置MAA" not in mode and self.if_open_emulator: + if "设置MAA" not in mode and "更新MAA" not in mode and self.if_open_emulator: self.if_open_emulator = False # 覆写配置文件 diff --git a/app/ui/Widget.py b/app/ui/Widget.py index bfd7901..520adce 100644 --- a/app/ui/Widget.py +++ b/app/ui/Widget.py @@ -621,6 +621,53 @@ class PushAndSwitchButtonSettingCard(SettingCard): self.switchButton.setText("开" if isChecked else "关") +class PushAndComboBoxSettingCard(SettingCard): + """Setting card with push & combo box""" + + clicked = Signal() + + def __init__( + self, + icon: Union[str, QIcon, FluentIconBase], + title: str, + content: Union[str, None], + text: str, + texts: List[str], + qconfig: QConfig, + configItem: OptionsConfigItem, + parent=None, + ): + + super().__init__(icon, title, content, parent) + self.qconfig = qconfig + self.configItem = configItem + self.comboBox = ComboBox(self) + self.button = PushButton(text, self) + self.hBoxLayout.addWidget(self.button, 0, Qt.AlignRight) + self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight) + self.hBoxLayout.addSpacing(16) + self.button.clicked.connect(self.clicked) + + self.optionToText = {o: t for o, t in zip(configItem.options, texts)} + for text, option in zip(texts, configItem.options): + self.comboBox.addItem(text, userData=option) + + self.comboBox.setCurrentText(self.optionToText[self.qconfig.get(configItem)]) + self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged) + configItem.valueChanged.connect(self.setValue) + + def _onCurrentIndexChanged(self, index: int): + + self.qconfig.set(self.configItem, self.comboBox.itemData(index)) + + def setValue(self, value): + if value not in self.optionToText: + return + + self.comboBox.setCurrentText(self.optionToText[value]) + self.qconfig.set(self.configItem, value) + + class SpinBoxSettingCard(SettingCard): """Setting card with SpinBox""" diff --git a/app/ui/member_manager.py b/app/ui/member_manager.py index 1f3f6ca..2fef2e9 100644 --- a/app/ui/member_manager.py +++ b/app/ui/member_manager.py @@ -69,6 +69,7 @@ from .Widget import ( ComboBoxSettingCard, SwitchSettingCard, PushAndSwitchButtonSettingCard, + PushAndComboBoxSettingCard, ) @@ -613,21 +614,7 @@ class MemberManager(QWidget): configItem=self.config.RunSet_TaskTransitionMethod, parent=self, ) - self.card_EnhanceTask = ComboBoxSettingCard( - icon=FluentIcon.PAGE_RIGHT, - title="自动代理增效任务", - content="自动代理时的额外操作,此操作无法区分多开模拟器,可能会干扰其他任务,也可能关闭您正在使用的模拟器", - texts=[ - "禁用", - "强制关闭ADB", - "强制关闭所有模拟器", - "强制关闭ADB和所有模拟器", - ], - qconfig=self.config, - configItem=self.config.RunSet_EnhanceTask, - parent=self, - ) - self.ProxyTimesLimit = SpinBoxSettingCard( + self.card_ProxyTimesLimit = SpinBoxSettingCard( icon=FluentIcon.PAGE_RIGHT, title="用户单日代理次数上限", content="当用户本日代理成功次数达到该阈值时跳过代理,阈值为“0”时视为无代理次数上限", @@ -636,25 +623,7 @@ class MemberManager(QWidget): configItem=self.config.RunSet_ProxyTimesLimit, parent=self, ) - self.AnnihilationTimeLimit = SpinBoxSettingCard( - icon=FluentIcon.PAGE_RIGHT, - title="剿灭代理超时限制", - content="MAA日志无变化时间超过该阈值视为超时,单位为分钟", - range=(1, 1024), - qconfig=self.config, - configItem=self.config.RunSet_AnnihilationTimeLimit, - parent=self, - ) - self.RoutineTimeLimit = SpinBoxSettingCard( - icon=FluentIcon.PAGE_RIGHT, - title="自动代理超时限制", - content="MAA日志无变化时间超过该阈值视为超时,单位为分钟", - range=(1, 1024), - qconfig=self.config, - configItem=self.config.RunSet_RoutineTimeLimit, - parent=self, - ) - self.RunTimesLimit = SpinBoxSettingCard( + self.card_RunTimesLimit = SpinBoxSettingCard( icon=FluentIcon.PAGE_RIGHT, title="代理重试次数限制", content="若超过该次数限制仍未完成代理,视为代理失败", @@ -663,7 +632,25 @@ class MemberManager(QWidget): configItem=self.config.RunSet_RunTimesLimit, parent=self, ) - self.AnnihilationWeeklyLimit = SwitchSettingCard( + self.card_AnnihilationTimeLimit = SpinBoxSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="剿灭代理超时限制", + content="MAA日志无变化时间超过该阈值视为超时,单位为分钟", + range=(1, 1024), + qconfig=self.config, + configItem=self.config.RunSet_AnnihilationTimeLimit, + parent=self, + ) + self.card_RoutineTimeLimit = SpinBoxSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="自动代理超时限制", + content="MAA日志无变化时间超过该阈值视为超时,单位为分钟", + range=(1, 1024), + qconfig=self.config, + configItem=self.config.RunSet_RoutineTimeLimit, + parent=self, + ) + self.card_AnnihilationWeeklyLimit = SwitchSettingCard( icon=FluentIcon.PAGE_RIGHT, title="每周剿灭仅执行到上限", content="每周剿灭模式执行到上限,本周剩下时间不再执行剿灭任务", @@ -671,16 +658,24 @@ class MemberManager(QWidget): configItem=self.config.RunSet_AnnihilationWeeklyLimit, parent=self, ) + self.card_AutoUpdateMaa = SwitchSettingCard( + icon=FluentIcon.PAGE_RIGHT, + title="自动代理时自动更新MAA", + content="执行自动代理任务时自动更新MAA,关闭后仍会进行MAA版本检查", + qconfig=self.config, + configItem=self.config.RunSet_AutoUpdateMaa, + parent=self, + ) widget = QWidget() Layout = QVBoxLayout(widget) Layout.addWidget(self.card_TaskTransitionMethod) - Layout.addWidget(self.card_EnhanceTask) - Layout.addWidget(self.ProxyTimesLimit) - Layout.addWidget(self.AnnihilationTimeLimit) - Layout.addWidget(self.RoutineTimeLimit) - Layout.addWidget(self.RunTimesLimit) - Layout.addWidget(self.AnnihilationWeeklyLimit) + Layout.addWidget(self.card_ProxyTimesLimit) + Layout.addWidget(self.card_RunTimesLimit) + Layout.addWidget(self.card_AnnihilationTimeLimit) + Layout.addWidget(self.card_RoutineTimeLimit) + Layout.addWidget(self.card_AnnihilationWeeklyLimit) + Layout.addWidget(self.card_AutoUpdateMaa) self.viewLayout.setContentsMargins(0, 0, 0, 0) self.viewLayout.setSpacing(0) self.addGroupWidget(widget) @@ -1049,7 +1044,7 @@ class MemberManager(QWidget): self.name = name self.dashboard = TableWidget(self) - self.dashboard.setColumnCount(10) + self.dashboard.setColumnCount(11) self.dashboard.setHorizontalHeaderLabels( [ "用户名", @@ -1059,8 +1054,9 @@ class MemberManager(QWidget): "代理情况", "给药量", "关卡选择", - "备选关卡-1", - "备选关卡-2", + "备选 - 1", + "备选 - 2", + "剩余理智", "详", ] ) @@ -1070,14 +1066,14 @@ class MemberManager(QWidget): self.dashboard.horizontalHeader().setSectionResizeMode( col, QHeaderView.ResizeMode.ResizeToContents ) - for col in range(6, 9): + for col in range(6, 10): self.dashboard.horizontalHeader().setSectionResizeMode( col, QHeaderView.ResizeMode.Stretch ) self.dashboard.horizontalHeader().setSectionResizeMode( - 9, QHeaderView.ResizeMode.Fixed + 10, QHeaderView.ResizeMode.Fixed ) - self.dashboard.setColumnWidth(9, 32) + self.dashboard.setColumnWidth(10, 32) self.viewLayout.addWidget(self.dashboard) self.viewLayout.setContentsMargins(3, 0, 3, 3) @@ -1207,8 +1203,22 @@ class MemberManager(QWidget): else config.get(config.Info_GameId_2) ), ) + self.dashboard.setItem( + int(name[3:]) - 1, + 9, + QTableWidgetItem( + Config.gameid_dict["ALL"]["text"][ + Config.gameid_dict["ALL"]["value"].index( + config.get(config.Info_GameId_Remain) + ) + ] + if config.get(config.Info_GameId_Remain) + in Config.gameid_dict["ALL"]["value"] + else config.get(config.Info_GameId_Remain) + ), + ) self.dashboard.setCellWidget( - int(name[3:]) - 1, 9, button + int(name[3:]) - 1, 10, button ) class UserMemberSettingBox(HeaderCardWidget): @@ -1307,13 +1317,18 @@ class MemberManager(QWidget): configItem=self.config.Info_Routine, parent=self, ) - self.card_Infrastructure = PushAndSwitchButtonSettingCard( + self.card_InfrastMode = PushAndComboBoxSettingCard( icon=FluentIcon.CAFE, - title="自定义基建", - content="自定义基建相关设置项", + title="基建模式", + content="配置文件仅在自定义基建中生效", text="选择配置文件", + texts=[ + "常规模式", + "一键轮休", + "自定义基建", + ], qconfig=self.config, - configItem=self.config.Info_Infrastructure, + configItem=self.config.Info_InfrastMode, parent=self, ) self.card_Password = PasswordLineEditSettingCard( @@ -1344,6 +1359,15 @@ class MemberManager(QWidget): configItem=self.config.Info_MedicineNumb, parent=self, ) + self.card_SeriesNumb = SpinBoxSettingCard( + icon=FluentIcon.GAME, + title="连战次数", + content="连战次数较大时建议搭配剩余理智关卡使用", + range=(1, 6), + qconfig=self.config, + configItem=self.config.Info_SeriesNumb, + parent=self, + ) self.card_GameId = EditableComboBoxSettingCard( icon=FluentIcon.GAME, title="关卡选择", @@ -1356,7 +1380,7 @@ class MemberManager(QWidget): ) self.card_GameId_1 = EditableComboBoxSettingCard( icon=FluentIcon.GAME, - title="备选关卡-1", + title="备选关卡 - 1", content="按下回车以添加自定义关卡号", value=Config.gameid_dict["ALL"]["value"], texts=Config.gameid_dict["ALL"]["text"], @@ -1366,7 +1390,7 @@ class MemberManager(QWidget): ) self.card_GameId_2 = EditableComboBoxSettingCard( icon=FluentIcon.GAME, - title="备选关卡-2", + title="备选关卡 - 2", content="按下回车以添加自定义关卡号", value=Config.gameid_dict["ALL"]["value"], texts=Config.gameid_dict["ALL"]["text"], @@ -1374,6 +1398,16 @@ class MemberManager(QWidget): configItem=self.config.Info_GameId_2, parent=self, ) + self.card_GameId_Remain = EditableComboBoxSettingCard( + icon=FluentIcon.GAME, + title="剩余理智关卡", + content="按下回车以添加自定义关卡号", + value=Config.gameid_dict["ALL"]["value"], + texts=Config.gameid_dict["ALL"]["text"], + qconfig=self.config, + configItem=self.config.Info_GameId_Remain, + parent=self, + ) self.card_UserLable = UserLableSettingCard( icon=FluentIcon.INFO, @@ -1402,16 +1436,19 @@ class MemberManager(QWidget): h4_layout = QHBoxLayout() h4_layout.addWidget(self.card_Annihilation) h4_layout.addWidget(self.card_Routine) - h4_layout.addWidget(self.card_Infrastructure) + h4_layout.addWidget(self.card_InfrastMode) h5_layout = QHBoxLayout() h5_layout.addWidget(self.card_Password) h5_layout.addWidget(self.card_Notes) h6_layout = QHBoxLayout() h6_layout.addWidget(self.card_MedicineNumb) - h6_layout.addWidget(self.card_GameId) + h6_layout.addWidget(self.card_SeriesNumb) h7_layout = QHBoxLayout() + h7_layout.addWidget(self.card_GameId) h7_layout.addWidget(self.card_GameId_1) - h7_layout.addWidget(self.card_GameId_2) + h8_layout = QHBoxLayout() + h8_layout.addWidget(self.card_GameId_2) + h8_layout.addWidget(self.card_GameId_Remain) Layout = QVBoxLayout() Layout.addLayout(h1_layout) @@ -1422,6 +1459,7 @@ class MemberManager(QWidget): Layout.addLayout(h5_layout) Layout.addLayout(h6_layout) Layout.addLayout(h7_layout) + Layout.addLayout(h8_layout) self.viewLayout.addLayout(Layout) self.viewLayout.setContentsMargins(3, 0, 3, 3) @@ -1435,7 +1473,7 @@ class MemberManager(QWidget): self.card_Routine.clicked.connect( lambda: self.set_maa("Routine") ) - self.card_Infrastructure.clicked.connect( + self.card_InfrastMode.clicked.connect( self.set_infrastructure ) Config.gameid_refreshed.connect(self.refresh_gameid) @@ -1450,12 +1488,12 @@ class MemberManager(QWidget): self.card_Routine.setVisible(False) self.card_Server.setVisible(True) self.card_Annihilation.button.setVisible(False) - self.card_Infrastructure.setVisible(True) + self.card_InfrastMode.setVisible(True) elif self.config.get(self.config.Info_Mode) == "详细": self.card_Server.setVisible(False) - self.card_Infrastructure.setVisible(False) + self.card_InfrastMode.setVisible(False) self.card_Annihilation.button.setVisible(True) self.card_Routine.setVisible(True) @@ -1473,6 +1511,10 @@ class MemberManager(QWidget): Config.gameid_dict["ALL"]["value"], Config.gameid_dict["ALL"]["text"], ) + self.card_GameId_Remain.reLoadOptions( + Config.gameid_dict["ALL"]["value"], + Config.gameid_dict["ALL"]["text"], + ) def refresh_password(self): diff --git a/resources/docs/MAA_config_info.txt b/resources/docs/MAA_config_info.txt index a7cf7fb..484cf60 100644 --- a/resources/docs/MAA_config_info.txt +++ b/resources/docs/MAA_config_info.txt @@ -10,6 +10,14 @@ "TaskQueue.Mall.IsChecked": "True" #获取信用及购物 "TaskQueue.AutoRoguelike.IsChecked": "False" #自动肉鸽 "TaskQueue.Reclamation.IsChecked": "False" #生息演算 +"TaskQueue.Order.WakeUp": "0" +"TaskQueue.Order.Recruiting": "1" +"TaskQueue.Order.Base": "2" +"TaskQueue.Order.Combat": "3" +"TaskQueue.Order.Mall": "4" +"TaskQueue.Order.Mission": "5" +"TaskQueue.Order.AutoRoguelike": "6" +"TaskQueue.Order.Reclamation": "7" #刷理智 "MainFunction.UseMedicine": "True" #吃理智药 "MainFunction.UseMedicine.Quantity": "999" #吃理智药数量 @@ -30,8 +38,8 @@ "Penguin.EnablePenguin": "True" #上报企鹅物流 "Yituliu.EnableYituliu": "True" #上报一图流 #基建换班 -"Infrast.CustomInfrastEnabled": "True" #启用自定义基建配置 -"Infrast.CustomInfrastPlanIndex": "1" #自定义基建配置索引 +"Infrast.InfrastMode": "Normal"、"Rotation"、"Custom" #基建模式 +"Infrast.CustomInfrastPlanIndex": "1" #自定义基建配置索引号 "Infrast.DefaultInfrast": "user_defined" #内置配置 "Infrast.IsCustomInfrastFileReadOnly": "False" #自定义基建配置文件只读 "Infrast.CustomInfrastFile": "" #自定义基建配置文件地址 @@ -49,4 +57,5 @@ G"Start.MinimizeDirectly": "True" #启动MAA后直接最小化 G"GUI.UseTray": "True" #显示托盘图标 G"GUI.MinimizeToTray": "False" #最小化时隐藏至托盘 "Start.EmulatorPath" #模拟器路径 -"Start.EmulatorAddCommand": "-v 2" #附加命令 \ No newline at end of file +"Start.EmulatorAddCommand": "-v 2" #附加命令 +G"VersionUpdate.package": "MirrorChyanAppv5.15.6.zip" #更新包标识 \ No newline at end of file diff --git a/resources/version.json b/resources/version.json index b0097fc..a487841 100644 --- a/resources/version.json +++ b/resources/version.json @@ -1,93 +1,29 @@ { - "main_version": "4.3.4.0", + "main_version": "4.3.5.0", "updater_version": "1.0.0.0", "announcement": "\n## 新增功能\n- 屏蔽MuMu模拟器开屏广告功能上线\n- 更新器支持多线程下载\n- 添加强制关闭ADB与模拟器等增强任务项\n## 修复BUG\n- 修复统计信息HTML模板公招匹配错误\n- 修复密码显示按钮动画异常\n- 修复`检测到MAA未能实际执行任务`报错被异常屏蔽\n- 修复MAA超时判定异常失效\n## 程序优化\n- 关机等电源操作添加100s倒计时\n- 人工排查弹窗方法优化\n- 人工排查时自动屏蔽静默操作\n- 公告样式优化", "version_info": { - "4.3.4.0": { - "修复BUG": [ - "同步到MAAv5.15.4的tasks目录结构变化" - ] - }, - "4.3.4.7": { + "4.3.5.0": { "新增功能": [ - "主调度台支持直接启动多开调度台" - ], - "程序优化": [ - "历史记录保留时间选项扩展" - ] - }, - "4.3.4.6": { - "新增功能": [ - "历史记录添加`按周合并`、`按月合并`功能", - "新增MAA稳定版更新提醒" + "用户设置中新增连战次数与剩余理智关卡两项配置项", + "支持自动代理时更新MAA" ], "修复BUG": [ - "修复历史记录选项卡无法回收的问题" + "适配MAAv5.16.0基建模式", + "适配自定义基建自动轮换功能" ], "程序优化": [ - "历史记录添加`选中最近一月`、`选中最近一周`选项与打开日志文件所在目录功能", - "MAA报错判定结果文案拆分优化" + "移除增效任务" ] }, - "4.3.4.5": { + "4.3.5.2": { "修复BUG": [ - "修复启动时运行主任务的历史记录与完成后任务异常" - ], + "修复无法建立网络连接时软件卡死问题" + ] + }, + "4.3.5.1": { "程序优化": [ - "历史记录转为自行搜索", - "历史记录时间条目排序规则优化" - ] - }, - "4.3.4.4": { - "修复BUG": [ - "修复更新时主程序退出不彻底" - ], - "程序优化": [ - "ADB路径与模拟器路径添加报错提示", - "ADB路径兼容相对路径" - ] - }, - "4.3.4.3": { - "修复BUG": [ - "修复更新器使用mirrorc下载时删除已弃用的文件卡死" - ] - }, - "4.3.4.2": { - "程序优化": [ - "调度队列历史记录归入配置类管理", - "添加.gitignore", - "工作流删除冗余部分", - "自动代理与人工排查结束后MAA恢复到全局配置 #40", - "网络相关操作由子线程执行" - ] - }, - "4.3.4.1": { - "新增功能": [ - "开始任务前自动释放ADB端口" - ], - "程序优化": [ - "request 添加超时限制", - "用户任务运行流程改进", - "自动代理中模拟器改由AUTO_MAA控制", - "修正部分配置项文案" - ] - }, - "4.3.3.0": { - "修复BUG": [ - "修复更新器无法下载MAA的异常" - ], - "程序优化": [ - "自动发版改为手动触发" - ] - }, - "4.3.2.0": { - "修复BUG": [ - "修复更新器无法启动的异常" - ] - }, - "4.3.1.0": { - "修复BUG": [ - "覆盖规避v4.3.0错误包" + "模拟器路径适配快捷方式" ] } },