From 6b2163bc340077f5d0106eb04f487af8d6d04edd Mon Sep 17 00:00:00 2001 From: HarcoChen Date: Thu, 6 Aug 2026 10:55:50 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=A2=9C=E8=89=B2?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E4=B8=8D=E9=80=9A=E8=BF=87=E7=9A=84=E9=97=A8?= =?UTF-8?q?=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/task/MaaEnd/AutoProxy.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/task/MaaEnd/AutoProxy.py b/app/task/MaaEnd/AutoProxy.py index 7b9138b0..2c1053ee 100644 --- a/app/task/MaaEnd/AutoProxy.py +++ b/app/task/MaaEnd/AutoProxy.py @@ -407,8 +407,11 @@ async def main_task(self): "脚本后任务", ) - if "游戏分辨率设置错误" in self.cur_user_log.status: - logger.info("检测到游戏分辨率设置错误,跳过后续重试") + if ( + "游戏分辨率设置错误" in self.cur_user_log.status + or "颜色识别失败" in self.cur_user_log.status + ): + logger.info("检测到游戏画面参数错误,跳过后续重试") break async def handle_pre_maaend_error( @@ -816,6 +819,8 @@ async def check_log(self, log_content: list[str], latest_time: datetime) -> None self.cur_user_log.status = "MaaEnd 任务启动失败" elif "resolution check failed" in log or "分辨率不符合要求" in log: self.cur_user_log.status = "游戏分辨率设置错误,请重设分辨率比例为16:9" + elif "识别颜色失败" in log or "Color identification failed" in log: + self.cur_user_log.status = "MaaEnd 颜色识别失败,请关闭滤镜或 HDR" elif "任务失败: AccountSwitch" in log: self.cur_user_log.status = "MaaEnd 账号切换失败" elif ( From e0580fc31b500f691ed36f23b9bff8bfa4d825ea Mon Sep 17 00:00:00 2001 From: HarcoChen Date: Wed, 5 Aug 2026 23:49:23 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=E6=A8=A1=E7=89=88=EF=BC=8C=E9=87=87=E7=94=A8=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=85=9C=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/task/MaaEnd/ManualReview.py | 2 +- app/task/MaaEnd/ScriptConfig.py | 29 ++--- res/templates/MaaEnd/config/mxu-MaaEnd.json | 121 -------------------- 3 files changed, 9 insertions(+), 143 deletions(-) delete mode 100644 res/templates/MaaEnd/config/mxu-MaaEnd.json diff --git a/app/task/MaaEnd/ManualReview.py b/app/task/MaaEnd/ManualReview.py index f5f9e18d..be49512f 100644 --- a/app/task/MaaEnd/ManualReview.py +++ b/app/task/MaaEnd/ManualReview.py @@ -300,7 +300,7 @@ async def _run_maaend_account_switch(self, account_id: str) -> None: controller_type=str( self.script_config.get("Game", "ControllerType") ), - template_set=local_config, + fallback_set=local_config, ) maaend_instance = maaend_set["instances"][0] maaend_instance["tasks"] = [] diff --git a/app/task/MaaEnd/ScriptConfig.py b/app/task/MaaEnd/ScriptConfig.py index 30fef286..7873d272 100644 --- a/app/task/MaaEnd/ScriptConfig.py +++ b/app/task/MaaEnd/ScriptConfig.py @@ -39,7 +39,7 @@ def normalize_maaend_config( maaend_set: dict[str, Any], controller_type: str, - template_set: dict[str, Any] | None = None, + fallback_set: dict[str, Any] | None = None, ) -> dict[str, Any]: """将 MaaEnd 配置收束为 AUTO-MAS 单实例配置""" @@ -61,8 +61,8 @@ def select_instance(source_set: dict[str, Any]) -> dict[str, Any] | None: return None selected_instance = select_instance(maaend_set) - if selected_instance is None and template_set is not None: - selected_instance = select_instance(template_set) + if selected_instance is None and fallback_set is not None: + selected_instance = select_instance(fallback_set) if selected_instance is None: raise ValueError("MaaEnd 配置文件中未找到可用实例") @@ -131,16 +131,12 @@ async def set_maaend(self): if (self.config_file_path / "mxu-MaaEnd.json").exists(): shutil.rmtree(self.maaend_set_path, ignore_errors=True) shutil.copytree(self.config_file_path, self.maaend_set_path) - else: - maaend_template_path = ( - Path.cwd() / "res/templates/MaaEnd/config/mxu-MaaEnd.json" + elif self.maaend_set_path.exists(): + shutil.copytree( + self.maaend_set_path, + self.config_file_path, + dirs_exist_ok=True, ) - if maaend_template_path.exists(): - shutil.rmtree(self.maaend_set_path, ignore_errors=True) - self.maaend_set_path.mkdir(parents=True, exist_ok=True) - shutil.copy2( - maaend_template_path, self.maaend_set_path / "mxu-MaaEnd.json" - ) maaend_set_path = self.maaend_set_path / "mxu-MaaEnd.json" if not maaend_set_path.exists(): @@ -149,18 +145,9 @@ async def set_maaend(self): ) maaend_set = json.loads(maaend_set_path.read_text(encoding="utf-8")) - maaend_template_path = ( - Path.cwd() / "res/templates/MaaEnd/config/mxu-MaaEnd.json" - ) - template_config = ( - json.loads(maaend_template_path.read_text(encoding="utf-8")) - if maaend_template_path.exists() - else None - ) maaend_set = normalize_maaend_config( maaend_set, self.script_config.get("Game", "ControllerType"), - template_config, ) maaend_set_path.write_text( diff --git a/res/templates/MaaEnd/config/mxu-MaaEnd.json b/res/templates/MaaEnd/config/mxu-MaaEnd.json deleted file mode 100644 index 450893d0..00000000 --- a/res/templates/MaaEnd/config/mxu-MaaEnd.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "instances": [ - { - "id": "44d6qo2", - "name": "电脑端-前台", - "controllerName": "Win32-Front", - "resourceName": "官服", - "tasks": [ - { - "id": "5zqhjux", - "taskName": "VisitFriends", - "enabled": true, - "optionValues": {} - }, - { - "id": "diyt9yn", - "taskName": "DijiangRewards", - "enabled": true, - "optionValues": {} - }, - { - "id": "g8597rn", - "taskName": "CreditShoppingN2", - "enabled": true, - "optionValues": {} - }, - { - "id": "0bzqbf2", - "taskName": "DeliveryJobs", - "enabled": true, - "optionValues": {} - }, - { - "id": "8vfq6y1", - "taskName": "SellProduct", - "enabled": true, - "optionValues": {} - }, - { - "id": "es8dug8", - "taskName": "AutoStockpile", - "enabled": true, - "optionValues": {} - }, - { - "id": "740f85h", - "taskName": "AutoStockStaple", - "enabled": true, - "optionValues": {} - }, - { - "id": "jjusssw", - "taskName": "AutoSell", - "enabled": true, - "optionValues": {} - }, - { - "id": "gj70e22", - "taskName": "EnvironmentMonitoring", - "enabled": true, - "optionValues": {} - }, - { - "id": "mwg371e", - "taskName": "SeizeEntrustTask", - "enabled": true, - "optionValues": {} - }, - { - "id": "7u9ebfh", - "taskName": "AutoCollect", - "enabled": true, - "optionValues": {} - }, - { - "id": "y0k1zue", - "taskName": "AutoUseSpMedication", - "enabled": true, - "optionValues": {} - }, - { - "id": "agfpwsh", - "taskName": "ResourceRecycleStation", - "enabled": true, - "optionValues": {} - }, - { - "id": "qmwzjgu", - "taskName": "AutoEcoFarm", - "enabled": true, - "optionValues": {} - }, - { - "id": "5ej6pg9", - "taskName": "AutoEssence", - "enabled": true, - "optionValues": {} - }, - { - "id": "d947el4", - "taskName": "ProtocolSpace", - "enabled": true, - "optionValues": {} - }, - { - "id": "hiu9ttk", - "taskName": "DailyRewards", - "enabled": true, - "optionValues": {} - } - ] - } - ], - "settings": { - "language": "zh-CN", - "onboardingCompleted": true - }, - "customAccents": [], - "newTaskNames": [], - "presetInitialized": true -} From 5dcfc960a985de9e27d8d691fdfef8bc9a5c6075 Mon Sep 17 00:00:00 2001 From: HarcoChen Date: Thu, 6 Aug 2026 10:19:09 +0800 Subject: [PATCH 3/6] =?UTF-8?q?refactor(maaend):=20=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=99=A8=E5=92=8C=E6=9C=BA=E5=88=B6=E5=88=B7=E5=8F=96=E9=80=89?= =?UTF-8?q?=E9=A1=B9=E6=94=B9=E4=B8=BA=E5=8A=A8=E6=80=81=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/scripts.py | 28 ++++++++++ app/core/config.py | 16 ++++++ app/core/maa_manager.py | 37 ++++++++++++- app/models/config.py | 23 ++++---- app/models/schema.py | 24 ++++----- app/task/MaaEnd/AutoProxy.py | 9 ++-- app/task/MaaEnd/ScriptConfig.py | 52 +++++++++++++++++++ app/task/MaaEnd/manager.py | 16 +++--- app/utils/constants.py | 20 +------ frontend/src/api/index.ts | 1 + frontend/src/api/models/MaaEndConfig_Game.ts | 2 +- frontend/src/api/models/MaaEndOptionsOut.ts | 27 ++++++++++ .../src/api/models/MaaEndUserConfig_Task.ts | 2 +- frontend/src/api/services/GetService.ts | 20 +++++++ frontend/src/api/services/Service.ts | 20 +++++++ frontend/src/composables/useScriptApi.ts | 17 +++++- frontend/src/types/script.ts | 3 +- frontend/src/utils/maaEndProtocolSpace.ts | 23 ++------ .../EditView/Script/MaaEndScriptEdit.vue | 41 +++++++++++---- .../views/EditView/User/MaaEndUserEdit.vue | 15 +++++- .../MaaEndUserEdit/TaskConfigSection.vue | 11 ++-- 21 files changed, 309 insertions(+), 98 deletions(-) create mode 100644 frontend/src/api/models/MaaEndOptionsOut.ts diff --git a/app/api/scripts.py b/app/api/scripts.py index 8893719d..24ffda75 100644 --- a/app/api/scripts.py +++ b/app/api/scripts.py @@ -305,6 +305,34 @@ async def import_script_config_file( return OutBase(message="脚本配置文件已导入") +@router.post( + "/maaend/options", + tags=["Get"], + summary="获取 MaaEnd 动态选项", + response_model=MaaEndOptionsOut, + status_code=200, +) +async def get_maaend_options(options: ScriptDeleteIn = Body(...)) -> MaaEndOptionsOut: + try: + data = await Config.get_maaend_options(options.scriptId) + return MaaEndOptionsOut( + controllers=[ComboBoxItem(**item) for item in data["controllers"]], + controllerTypes=data["controllerTypes"], + essenceLocations=[ + ComboBoxItem(**item) for item in data["essenceLocations"] + ], + ) + except Exception as e: + return MaaEndOptionsOut( + code=500, + status="error", + message=f"{type(e).__name__}: {str(e)}", + controllers=[], + controllerTypes={}, + essenceLocations=[], + ) + + @router.post( "/user/get", tags=["Get"], diff --git a/app/core/config.py b/app/core/config.py index b78592fb..635c5722 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -679,6 +679,22 @@ async def get_script(self, script_id: str | None) -> tuple[list, dict]: index = data.pop("instances", []) return list(index), data + async def get_maaend_options( + self, script_id: str + ) -> dict[str, list[dict[str, str]]]: + """读取指定 MaaEnd 安装目录中的动态选项。""" + + script_config = self.ScriptConfig[uuid.UUID(script_id)] + if not isinstance(script_config, MaaEndConfig): + raise TypeError("脚本配置类型错误, 不是 MaaEnd 类型") + root_path = str(script_config.get("Info", "Path") or "").strip() + if not root_path: + raise ValueError("MaaEnd 路径未配置") + + from app.task.MaaEnd.ScriptConfig import load_maaend_options + + return await asyncio.to_thread(load_maaend_options, Path(root_path)) + async def update_script( self, script_id: str, data: Dict[str, Dict[str, Any]] ) -> None: diff --git a/app/core/maa_manager.py b/app/core/maa_manager.py index a77ae1d8..5a130401 100644 --- a/app/core/maa_manager.py +++ b/app/core/maa_manager.py @@ -19,6 +19,7 @@ # Contact: DLmaster_361@163.com +import asyncio import json from ctypes import c_void_p from pathlib import Path @@ -45,7 +46,7 @@ from .config import Config from app.models.emulator import DeviceInfo -from app.utils import get_logger +from app.utils import get_logger, ProcessRunner logger = get_logger("MaaFW管理") @@ -145,12 +146,44 @@ async def convert_adb(raw_info: DeviceInfo) -> AdbDevice: RuntimeError: 如果无法找到指定设备,则抛出异常,异常信息包含相关的错误信息 """ - for emulator in Toolkit.find_adb_devices(): + for emulator in await asyncio.to_thread(Toolkit.find_adb_devices): if raw_info.adb_address == emulator.address: return emulator else: raise RuntimeError("无法找到指定设备") + @staticmethod + async def ensure_adb_connectable( + raw_info: DeviceInfo, timeout: float = 30 + ) -> AdbDevice: + """等待目标设备进入 ADB 可连接状态。""" + + loop = asyncio.get_running_loop() + deadline = loop.time() + timeout + last_error = "" + while loop.time() < deadline: + try: + adb_device = await _MaaFWManager.convert_adb(raw_info) + if ":" in adb_device.address: + await ProcessRunner.run_process( + adb_device.adb_path, "connect", adb_device.address, timeout=10 + ) + result = await ProcessRunner.run_process( + adb_device.adb_path, + "-s", adb_device.address, "get-state", + timeout=10, + ) + if result.returncode == 0 and result.stdout.strip() == "device": + logger.success(f"ADB 设备已就绪: {adb_device.address}") + return adb_device + last_error = result.stderr.strip() or result.stdout.strip() + except Exception as e: + last_error = str(e) + await asyncio.sleep(1) + + detail = f": {last_error}" if last_error else "" + raise RuntimeError(f"ADB 设备连接超时: {raw_info.adb_address}{detail}") + async def get_adb_tasker( self, device_info: DeviceInfo, diff --git a/app/models/config.py b/app/models/config.py index 8ffd64bc..366ae3dc 100644 --- a/app/models/config.py +++ b/app/models/config.py @@ -32,7 +32,6 @@ MATERIALS_MAP, RESOURCE_STAGE_INFO, MAA_STAGE_KEY, - MAAEND_AUTO_ESSENCE_LOCATION_OPTIONS, MAAEND_PROTOCOL_SPACE_TASK_OPTIONS, MAAEND_SANITY_TASK_DEFAULTS, MAAEND_SANITY_TASK_DETAIL_LABELS, @@ -115,7 +114,7 @@ def init_maaend_task_config(config) -> None: "Task", "AutoEssenceSpecifiedLocation", MAAEND_SANITY_TASK_DEFAULTS["AutoEssenceSpecifiedLocation"], - OptionsValidator(list(MAAEND_AUTO_ESSENCE_LOCATION_OPTIONS)), + StringValidator(), ) for task_name in MAAEND_TASKS: @@ -980,9 +979,14 @@ def getTags(self) -> str: if sanity_task_type == "Essence" else task_config[sanity_task_type] ) + detail_label = ( + detail_key + if sanity_task_type == "Essence" + else MAAEND_SANITY_TASK_DETAIL_LABELS[detail_key] + ) tags.append( { - "text": f"详细任务:{MAAEND_SANITY_TASK_DETAIL_LABELS[detail_key]}", + "text": f"详细任务:{detail_label}", "color": "blue", } ) @@ -1052,13 +1056,12 @@ def __init__(self) -> None: self.Game_ControllerType = ConfigItem( "Game", "ControllerType", - "Win32-Front", - OptionsValidator( - [ - "Win32-Front", - "ADB", - ] - ), + "", + StringValidator(), + ) + ## 控制器协议类型 + self.Game_ControllerProtocol = ConfigItem( + "Game", "ControllerProtocol", "", StringValidator() ) ## 终末地游戏路径 self.Game_Path = ConfigItem("Game", "Path", "", FileValidator()) diff --git a/app/models/schema.py b/app/models/schema.py index bda6a038..ad7ec488 100644 --- a/app/models/schema.py +++ b/app/models/schema.py @@ -76,6 +76,12 @@ class ComboBoxOut(OutBase): data: List[ComboBoxItem] = Field(..., description="下拉框选项") +class MaaEndOptionsOut(OutBase): + controllers: List[ComboBoxItem] = Field(..., description="MaaEnd 控制器选项") + controllerTypes: dict[str, str] = Field(..., description="控制器协议类型映射") + essenceLocations: List[ComboBoxItem] = Field(..., description="MaaEnd 基质刷取地点选项") + + class GetStageIn(BaseModel): type: Literal[ "User", @@ -863,17 +869,9 @@ class MaaEndUserConfig_Task(BaseModel): RewardsSetOption: Optional[Literal["RewardsSetA", "RewardsSetB"]] = Field( default=None, description="奖励组选项" ) - AutoEssenceSpecifiedLocation: Optional[ - Literal[ - "VFTheHub", - "VFOriginiumSciencePark", - "VFOriginLodespring", - "VFPowerPlateau", - "WLWulingCity", - "WLQingboStockade", - "WLMarkerStone", - ] - ] = Field(default=None, description="基质刷取指定地点") + AutoEssenceSpecifiedLocation: Optional[str] = Field( + default=None, description="基质刷取指定地点" + ) IfSanity: Optional[bool] = Field(default=None, description="理智任务") IfAutoUseSpMedication: Optional[bool] = Field( default=None, description="应急理智加强剂" @@ -945,9 +943,7 @@ class MaaEndConfig_Run(BaseModel): class MaaEndConfig_Game(BaseModel): - ControllerType: Optional[Literal["Win32-Front", "ADB"]] = Field( - default=None, description="控制器类型" - ) + ControllerType: Optional[str] = Field(default=None, description="控制器类型") Path: Optional[str] = Field(default=None, description="终末地客户端路径") Arguments: Optional[str] = Field(default=None, description="游戏启动参数") WaitTime: Optional[int] = Field(default=None, ge=60, description="游戏等待时间") diff --git a/app/task/MaaEnd/AutoProxy.py b/app/task/MaaEnd/AutoProxy.py index 2c1053ee..16bf2716 100644 --- a/app/task/MaaEnd/AutoProxy.py +++ b/app/task/MaaEnd/AutoProxy.py @@ -240,7 +240,7 @@ async def main_task(self): controller_type = self.script_config.get("Game", "ControllerType") try: if self.emulator_manager is None: - if controller_type != "ADB" and is_process_running("Endfield.exe"): + if is_process_running("Endfield.exe"): logger.info( "检测到终末地客户端进程已在运行,跳过由 MAS 重复启动游戏" ) @@ -544,9 +544,8 @@ async def set_maaend(self, device_info: DeviceInfo | None) -> None: if device_info is not None: from app.core import MaaFWManager - maaend_instance["savedDevice"] = { - "adbDeviceName": (await MaaFWManager.convert_adb(device_info)).name - } + adb_device = await MaaFWManager.ensure_adb_connectable(device_info) + maaend_instance["savedDevice"] = {"adbDeviceName": adb_device.name} maaend_tasks = maaend_instance["tasks"] account_id = str(self.cur_user_config.get("Info", "Id")).strip() @@ -744,7 +743,7 @@ def get_task_book_name(task: dict[str, object]) -> str: and target_task_name == "AutoEssence" ): task.setdefault("optionValues", {}) - task["optionValues"]["AutoEssenceSpecifiedLocation"] = { + task["optionValues"]["AutoEssenceChooseLocation"] = { "type": "select", "caseName": sanity_task_config["AutoEssenceSpecifiedLocation"], } diff --git a/app/task/MaaEnd/ScriptConfig.py b/app/task/MaaEnd/ScriptConfig.py index 7873d272..048db54d 100644 --- a/app/task/MaaEnd/ScriptConfig.py +++ b/app/task/MaaEnd/ScriptConfig.py @@ -20,6 +20,7 @@ import json +import json5 import shutil import asyncio from pathlib import Path @@ -36,6 +37,57 @@ logger = get_logger("MaaEnd 脚本设置") +def load_maaend_options(root_path: Path) -> dict[str, list[dict[str, str]]]: + root_path = root_path.resolve() + config = json5.loads( + (root_path / "config/mxu-MaaEnd.json").read_text(encoding="utf-8") + ) + interface_path = root_path / "interface.json" + interface = json5.loads(interface_path.read_text(encoding="utf-8")) + language = str(config["settings"]["language"]) + language = ( + "zh_cn" if language.lower() == "system" else language.lower().replace("-", "_") + ) + locale = json5.loads( + (interface_path.parent / interface["languages"][language]).read_text( + encoding="utf-8" + ) + ) + + def options(cases: list[dict[str, str]]) -> list[dict[str, str]]: + return [ + { + "label": locale.get(case["label"][1:], case["name"]) + if (case.get("label") or "").startswith("$") + else case.get("label") or case["name"], + "value": case["name"], + } + for case in cases + ] + + task_path = next( + ( + interface_path.parent / path + for path in interface["import"] + if Path(path).stem == "AutoEssence" + ), + None, + ) + if task_path is None: + raise ValueError(f"MaaEnd Interface 未导入 AutoEssence 任务: {interface_path}") + + task = json5.loads(task_path.read_text(encoding="utf-8")) + essence_cases = task["option"]["AutoEssenceChooseLocation"]["cases"] + + return { + "controllers": options(interface["controller"]), + "controllerTypes": { + case["name"]: case["type"] for case in interface["controller"] + }, + "essenceLocations": options(essence_cases), + } + + def normalize_maaend_config( maaend_set: dict[str, Any], controller_type: str, diff --git a/app/task/MaaEnd/manager.py b/app/task/MaaEnd/manager.py index d721dcc2..45408935 100644 --- a/app/task/MaaEnd/manager.py +++ b/app/task/MaaEnd/manager.py @@ -57,6 +57,7 @@ def __init__(self, script_info: ScriptItem): self.task_info = script_info.task_info self.script_info = script_info self.check_result = "-" + self.controller_protocol = "" async def check(self) -> str: if self.task_info.mode not in METHOD_BOOK: @@ -70,16 +71,19 @@ async def check(self) -> str: if not (Path(script_config.get("Info", "Path")) / "MaaEnd.exe").exists(): return "MaaEnd.exe文件不存在, 请检查MaaEnd路径设置!" - if (script_config.get("Game", "ControllerType") == "ADB") and ( + self.controller_protocol = script_config.get("Game", "ControllerProtocol") + + if self.controller_protocol == "Adb" and ( script_config.get("Game", "EmulatorId") == "-" or script_config.get("Game", "EmulatorIndex") in ["", "-"] ): return "未完成模拟器配置, 请检查脚本配置中的模拟器设置!" - elif ( - script_config.get("Game", "ControllerType").startswith("Win32") - and not Path(script_config.get("Game", "Path")).exists() - ): + elif self.controller_protocol == "Win32" and not Path( + script_config.get("Game", "Path") + ).exists(): return "未完成游戏配置, 请检查脚本配置中的游戏设置!" + elif self.controller_protocol not in ("Adb", "Win32"): + return "MaaEnd 控制器协议未配置, 请重新选择控制器!" if self.task_info.mode == "AutoProxy" and not ( Path( @@ -106,7 +110,7 @@ async def prepare(self): self.temp_path = Path.cwd() / f"data/{self.script_info.script_id}/Temp" # 初始化模拟器管理器 - if self.script_config.get("Game", "ControllerType") == "ADB": + if self.controller_protocol == "Adb": self.emulator_manager = await EmulatorManager.get_emulator_instance( self.script_config.get("Game", "EmulatorId") ) diff --git a/app/utils/constants.py b/app/utils/constants.py index 62c5e20b..ec2feaf9 100644 --- a/app/utils/constants.py +++ b/app/utils/constants.py @@ -241,13 +241,6 @@ "AdvancedProgression3": "高阶培养 III - 快子遴捡晶格", "AdvancedProgression4": "高阶培养 IV - 象限拟合液", "AdvancedProgression5": "高阶培养 V - 三相纳米片", - "VFTheHub": "枢纽区", - "VFOriginiumSciencePark": "源石研究园", - "VFOriginLodespring": "矿脉源区", - "VFPowerPlateau": "供能高地", - "WLWulingCity": "武陵城区", - "WLQingboStockade": "清波寨", - "WLMarkerStone": "首墩", } """MaaEnd理智任务详细选项展示文案""" @@ -272,17 +265,6 @@ } """MaaEnd协议空间任务选项列表""" -MAAEND_AUTO_ESSENCE_LOCATION_OPTIONS = ( - "VFTheHub", - "VFOriginiumSciencePark", - "VFOriginLodespring", - "VFPowerPlateau", - "WLWulingCity", - "WLQingboStockade", - "WLMarkerStone", -) -"""MaaEnd基质刷取地点选项列表""" - MAAEND_STAGE_WITH_AB = set(["OperatorEXP", "Promotions", "SkillUp", "WeaponTune"]) """MAAEnd任务包含AB关的关卡列表""" @@ -347,7 +329,7 @@ "WeaponProgression": "WeaponEXP", "CrisisDrills": "AdvancedProgression1", "RewardsSetOption": "RewardsSetA", - "AutoEssenceSpecifiedLocation": "VFTheHub", + "AutoEssenceSpecifiedLocation": "", } """MaaEnd理智任务字段默认值""" diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index c3f0bb5d..d543027e 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -106,6 +106,7 @@ export type { MaaEndConfig } from './models/MaaEndConfig'; export type { MaaEndConfig_Game } from './models/MaaEndConfig_Game'; export type { MaaEndConfig_Info } from './models/MaaEndConfig_Info'; export type { MaaEndConfig_Run } from './models/MaaEndConfig_Run'; +export type { MaaEndOptionsOut } from './models/MaaEndOptionsOut'; export type { MaaEndUserConfig } from './models/MaaEndUserConfig'; export type { MaaEndUserConfig_Data } from './models/MaaEndUserConfig_Data'; export type { MaaEndUserConfig_Info } from './models/MaaEndUserConfig_Info'; diff --git a/frontend/src/api/models/MaaEndConfig_Game.ts b/frontend/src/api/models/MaaEndConfig_Game.ts index cf135a14..ea36435b 100644 --- a/frontend/src/api/models/MaaEndConfig_Game.ts +++ b/frontend/src/api/models/MaaEndConfig_Game.ts @@ -6,7 +6,7 @@ export type MaaEndConfig_Game = { /** * 控制器类型 */ - ControllerType?: ('Win32-Front' | 'ADB' | null); + ControllerType?: (string | null); /** * 终末地客户端路径 */ diff --git a/frontend/src/api/models/MaaEndOptionsOut.ts b/frontend/src/api/models/MaaEndOptionsOut.ts new file mode 100644 index 00000000..df6d05bd --- /dev/null +++ b/frontend/src/api/models/MaaEndOptionsOut.ts @@ -0,0 +1,27 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { ComboBoxItem } from './ComboBoxItem'; +export type MaaEndOptionsOut = { + /** + * 状态码 + */ + code?: number; + /** + * 操作状态 + */ + status?: string; + /** + * 操作消息 + */ + message?: string; + /** + * MaaEnd 控制器选项 + */ + controllers: Array; + /** + * MaaEnd 基质刷取地点选项 + */ + essenceLocations: Array; +}; diff --git a/frontend/src/api/models/MaaEndUserConfig_Task.ts b/frontend/src/api/models/MaaEndUserConfig_Task.ts index 7d5969ba..018281b6 100644 --- a/frontend/src/api/models/MaaEndUserConfig_Task.ts +++ b/frontend/src/api/models/MaaEndUserConfig_Task.ts @@ -26,7 +26,7 @@ export type MaaEndUserConfig_Task = { /** * 基质刷取指定地点 */ - AutoEssenceSpecifiedLocation?: ('VFTheHub' | 'VFOriginiumSciencePark' | 'VFOriginLodespring' | 'VFPowerPlateau' | 'WLWulingCity' | 'WLQingboStockade' | 'WLMarkerStone' | null); + AutoEssenceSpecifiedLocation?: (string | null); /** * 理智任务 */ diff --git a/frontend/src/api/services/GetService.ts b/frontend/src/api/services/GetService.ts index e9fb7f36..828f029e 100644 --- a/frontend/src/api/services/GetService.ts +++ b/frontend/src/api/services/GetService.ts @@ -20,6 +20,7 @@ import type { HistoryDataGetOut } from '../models/HistoryDataGetOut'; import type { HistorySearchIn } from '../models/HistorySearchIn'; import type { HistorySearchOut } from '../models/HistorySearchOut'; import type { InfoOut } from '../models/InfoOut'; +import type { MaaEndOptionsOut } from '../models/MaaEndOptionsOut'; import type { NoticeOut } from '../models/NoticeOut'; import type { OCRScreenshotIn } from '../models/OCRScreenshotIn'; import type { OCRScreenshotOut } from '../models/OCRScreenshotOut'; @@ -60,6 +61,25 @@ export class GetService { url: '/api/info/version', }); } + /** + * 获取 MaaEnd 动态选项 + * @param requestBody + * @returns MaaEndOptionsOut Successful Response + * @throws ApiError + */ + public static getMaaendOptionsApiScriptsMaaendOptionsPost( + requestBody: ScriptDeleteIn, + ): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/scripts/maaend/options', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } /** * 获取关卡号下拉框信息 * @param requestBody diff --git a/frontend/src/api/services/Service.ts b/frontend/src/api/services/Service.ts index b289a3d2..761a49f7 100644 --- a/frontend/src/api/services/Service.ts +++ b/frontend/src/api/services/Service.ts @@ -30,6 +30,7 @@ import type { HistorySearchIn } from '../models/HistorySearchIn'; import type { HistorySearchOut } from '../models/HistorySearchOut'; import type { HSRStageOptionsOut } from '../models/HSRStageOptionsOut'; import type { InfoOut } from '../models/InfoOut'; +import type { MaaEndOptionsOut } from '../models/MaaEndOptionsOut'; import type { NoticeOut } from '../models/NoticeOut'; import type { OutBase } from '../models/OutBase'; import type { PlanCreateIn } from '../models/PlanCreateIn'; @@ -117,6 +118,25 @@ export class Service { url: '/api/core/close', }); } + /** + * 获取 MaaEnd 动态选项 + * @param requestBody + * @returns MaaEndOptionsOut Successful Response + * @throws ApiError + */ + public static getMaaendOptionsApiScriptsMaaendOptionsPost( + requestBody: ScriptDeleteIn, + ): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/scripts/maaend/options', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } /** * 获取后端git版本信息 * @returns VersionOut Successful Response diff --git a/frontend/src/composables/useScriptApi.ts b/frontend/src/composables/useScriptApi.ts index cb54a55d..0705657a 100644 --- a/frontend/src/composables/useScriptApi.ts +++ b/frontend/src/composables/useScriptApi.ts @@ -10,6 +10,7 @@ import { type SrcConfig, type HSRConfig, type HSRStageOptionsData, + type MaaEndOptionsOut, ScriptCreateIn, type ScriptReorderIn, HsrService, @@ -695,7 +696,7 @@ export function useScriptApi() { AutoEssenceSpecifiedLocation: maaEndUserData.Task?.AutoEssenceSpecifiedLocation != null ? maaEndUserData.Task.AutoEssenceSpecifiedLocation - : 'VFTheHub', + : '', IfSanity: maaEndUserData.Task?.IfSanity != null ? maaEndUserData.Task.IfSanity @@ -1231,6 +1232,19 @@ export function useScriptApi() { } } + const getMaaEndOptions = async (scriptId: string): Promise => { + try { + const response = await Service.getMaaendOptionsApiScriptsMaaendOptionsPost({ scriptId }) + if (response?.code !== 200) throw new Error(response?.message || '接口返回异常') + return response + } catch (err) { + const errorMsg = err instanceof Error ? err.message : '获取 MaaEnd 动态选项失败' + error.value = errorMsg + logger.error(`获取 MaaEnd 动态选项失败: ${errorMsg}`) + return null + } + } + // 删除脚本 const deleteScript = async (scriptId: string): Promise => { loading.value = true @@ -1337,6 +1351,7 @@ export function useScriptApi() { getScriptsWithUsers, getScript, getHsrStageOptions, + getMaaEndOptions, deleteScript, updateScript, reorderScript, diff --git a/frontend/src/types/script.ts b/frontend/src/types/script.ts index a0c079e4..8ab22205 100644 --- a/frontend/src/types/script.ts +++ b/frontend/src/types/script.ts @@ -139,7 +139,8 @@ export interface MaaEndScriptConfig { AccountSwitchMethod: 'MAS' | 'MAAEND' } Game: { - ControllerType: 'Win32-Front' | 'ADB' | null + ControllerType: string | null + ControllerProtocol: string | null Path: string Arguments: string WaitTime: number diff --git a/frontend/src/utils/maaEndProtocolSpace.ts b/frontend/src/utils/maaEndProtocolSpace.ts index e96f00bd..13d1b10f 100644 --- a/frontend/src/utils/maaEndProtocolSpace.ts +++ b/frontend/src/utils/maaEndProtocolSpace.ts @@ -23,17 +23,7 @@ export const REWARD_OPTIONS = [ export type RewardSetOption = (typeof REWARD_OPTIONS)[number]['value'] -export const AUTO_ESSENCE_LOCATION_OPTIONS = [ - { label: '枢纽区', value: 'VFTheHub' }, - { label: '源石研究园', value: 'VFOriginiumSciencePark' }, - { label: '矿脉源区', value: 'VFOriginLodespring' }, - { label: '供能高地', value: 'VFPowerPlateau' }, - { label: '武陵城区', value: 'WLWulingCity' }, - { label: '清波寨', value: 'WLQingboStockade' }, - { label: '首墩', value: 'WLMarkerStone' }, -] as const - -export type AutoEssenceLocation = (typeof AUTO_ESSENCE_LOCATION_OPTIONS)[number]['value'] +export type AutoEssenceLocation = string export const PROTOCOL_SPACE_TASK_OPTIONS_MAP = { OperatorProgression: [ @@ -163,10 +153,6 @@ export const PROTOCOL_SPACE_TASK_LABEL_MAP = Object.fromEntries( .map(option => [option.value, option.label]) ) as Record -export const AUTO_ESSENCE_LOCATION_LABEL_MAP = Object.fromEntries( - AUTO_ESSENCE_LOCATION_OPTIONS.map(option => [option.value, option.label]) -) as Record - export const PROTOCOL_SPACE_TASK_TITLE_MAP: Record = { OperatorProgression: '干员养成任务', WeaponProgression: '武器养成任务', @@ -189,7 +175,7 @@ export const createDefaultMaaEndSanityConfig = (): MaaEndSanityConfig => ({ WeaponProgression: 'WeaponEXP', CrisisDrills: 'AdvancedProgression1', RewardsSetOption: 'RewardsSetA', - AutoEssenceSpecifiedLocation: 'VFTheHub', + AutoEssenceSpecifiedLocation: '', }) export const getProtocolSpaceTaskField = (tab: ProtocolSpaceTab): CurrentTaskField => @@ -219,7 +205,7 @@ export const isProtocolSpaceRewardEnabled = (config: MaaEndSanityConfig): boolea export const getSanityTaskDisplayValue = (rawConfig?: Partial | null) => { const config = normalizeMaaEndSanityConfig(rawConfig) if (config.SanityTaskType === 'Essence') { - return AUTO_ESSENCE_LOCATION_LABEL_MAP[config.AutoEssenceSpecifiedLocation] + return config.AutoEssenceSpecifiedLocation } return PROTOCOL_SPACE_TASK_LABEL_MAP[getCurrentProtocolTaskValue(config)] } @@ -235,9 +221,6 @@ export const normalizeMaaEndSanityConfig = ( if (!SANITY_TASK_TYPE_LABEL_MAP[config.SanityTaskType]) { config.SanityTaskType = 'OperatorProgression' } - if (!AUTO_ESSENCE_LOCATION_LABEL_MAP[config.AutoEssenceSpecifiedLocation]) { - config.AutoEssenceSpecifiedLocation = 'VFTheHub' - } if (!REWARD_LABEL_MAP[config.RewardsSetOption]) { config.RewardsSetOption = 'RewardsSetA' } diff --git a/frontend/src/views/EditView/Script/MaaEndScriptEdit.vue b/frontend/src/views/EditView/Script/MaaEndScriptEdit.vue index 2e83e262..836fa7ed 100644 --- a/frontend/src/views/EditView/Script/MaaEndScriptEdit.vue +++ b/frontend/src/views/EditView/Script/MaaEndScriptEdit.vue @@ -260,7 +260,7 @@ - +