diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs
index 00954cf46c..73eb9d5312 100644
--- a/src/MaaWpfGui/Main/AsstProxy.cs
+++ b/src/MaaWpfGui/Main/AsstProxy.cs
@@ -2623,50 +2623,6 @@ namespace MaaWpfGui.Main
return id != 0 && AsstStart();
}
- ///
- /// 自动抄作业。
- ///
- /// 作业 JSON 的文件路径,绝对、相对路径均可。
- /// 是否进行 “快捷编队”。
- /// 是否追加信赖干员
- /// 是否追加自定干员
- /// 自定干员列表
- /// 是否导航至关卡(启用自动战斗序列)
- /// 关卡名
- /// 是不是突袭
- /// 任务类型
- /// 任务重复执行次数
- /// 是否使用理智药
- /// 是否启动战斗
- /// 是否成功。
- public bool AsstStartCopilot(string filename, bool formation, bool addTrust, bool addUserAdditional, JArray userAdditional, bool needNavigate, string navigateName, bool isRaid, AsstTaskType type, int loopTimes, bool useSanityPotion, bool asstStart = true)
- {
- var taskParams = new JObject
- {
- ["filename"] = filename,
- ["formation"] = formation,
- ["add_trust"] = addTrust,
- ["need_navigate"] = needNavigate,
- ["is_raid"] = isRaid,
- ["loop_times"] = loopTimes,
- ["use_sanity_potion"] = useSanityPotion,
- };
-
- if (addUserAdditional)
- {
- taskParams["user_additional"] = userAdditional;
- }
-
- if (needNavigate)
- {
- taskParams["navigate_name"] = navigateName;
- }
-
- AsstTaskId id = AsstAppendTaskWithEncoding(type, taskParams);
- _taskStatus.Add(id, TaskType.Copilot);
- return id != 0 && (!asstStart || AsstStart());
- }
-
public bool AsstStartVideoRec(string filename)
{
var taskParams = new JObject
diff --git a/src/MaaWpfGui/Models/AsstTasks/AsstBaseTask.cs b/src/MaaWpfGui/Models/AsstTasks/AsstBaseTask.cs
new file mode 100644
index 0000000000..351cf4a8cf
--- /dev/null
+++ b/src/MaaWpfGui/Models/AsstTasks/AsstBaseTask.cs
@@ -0,0 +1,30 @@
+//
+// MaaWpfGui - A part of the MaaCoreArknights project
+// Copyright (C) 2021 MistEO and Contributors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License v3.0 only as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY
+//
+#nullable enable
+using System;
+using MaaWpfGui.Services;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace MaaWpfGui.Models.AsstTasks;
+
+[JsonObject(MemberSerialization.OptIn)]
+public class AsstBaseTask
+{
+ public virtual AsstTaskType TaskType { get; private set; }
+
+ public virtual (AsstTaskType TaskType, JObject Params) Serialize()
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/MaaWpfGui/Models/AsstTasks/AsstCopilotTask.cs b/src/MaaWpfGui/Models/AsstTasks/AsstCopilotTask.cs
new file mode 100644
index 0000000000..aa88294f84
--- /dev/null
+++ b/src/MaaWpfGui/Models/AsstTasks/AsstCopilotTask.cs
@@ -0,0 +1,110 @@
+//
+// MaaWpfGui - A part of the MaaCoreArknights project
+// Copyright (C) 2021 MistEO and Contributors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License v3.0 only as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY
+//
+#nullable enable
+using System.Collections.Generic;
+using MaaWpfGui.Services;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace MaaWpfGui.Models.AsstTasks;
+
+///
+/// 自动抄作业。
+///
+public class AsstCopilotTask : AsstBaseTask
+{
+ public override AsstTaskType TaskType => AsstTaskType.Copilot;
+
+ ///
+ /// Gets or sets 作业 JSON 的文件路径,绝对、相对路径均可
+ ///
+ public string FileName { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a value indicating whether 自动编队
+ ///
+ public bool Formation { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether 追加信赖干员
+ ///
+ public bool AddTrust { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether 导航至关卡(启用自动战斗序列、取消代理)
+ ///
+ public bool NeedNavigate { get; set; }
+
+ ///
+ /// Gets or sets 关卡名,仅导航用,Wpf会自动读取地图对应的关卡名
+ ///
+ public string? StageName { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether 突袭难度
+ ///
+ public bool IsRaid { get; set; }
+
+ ///
+ /// Gets or sets 重复次数
+ ///
+ public int LoopTimes { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether 使用理智药
+ ///
+ public bool UseSanityPotion { get; set; }
+
+ ///
+ /// Gets or sets 自定干员列表
+ ///
+ public List? UserAdditionals { get; set; }
+
+ public override (AsstTaskType TaskType, JObject Params) Serialize()
+ {
+ var taskParams = new JObject
+ {
+ ["filename"] = FileName,
+ ["formation"] = Formation,
+ ["add_trust"] = AddTrust,
+ ["need_navigate"] = NeedNavigate,
+ ["is_raid"] = IsRaid,
+ ["loop_times"] = LoopTimes,
+ ["use_sanity_potion"] = UseSanityPotion,
+ };
+
+ if (UserAdditionals?.Count > 0)
+ {
+ taskParams["user_additional"] = JsonConvert.SerializeObject(UserAdditionals);
+ }
+
+ if (NeedNavigate)
+ {
+ taskParams["navigate_name"] = StageName;
+ }
+
+ return (TaskType, taskParams);
+ }
+
+ public class UserAdditional
+ {
+ ///
+ /// Gets or sets 干员名,ocr文本,跟随客户端语言
+ ///
+ [JsonProperty("name")]
+ public string Name { get; set; } = string.Empty;
+
+ [JsonProperty("skill")]
+ public int Skill { get; set; }
+ }
+}
diff --git a/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs b/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs
index 9b4d38e912..b26b391c0c 100644
--- a/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs
+++ b/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs
@@ -25,15 +25,17 @@ using System.Windows.Controls;
using System.Windows.Input;
using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
+using MaaWpfGui.Main;
using MaaWpfGui.Models;
+using MaaWpfGui.Models.AsstTasks;
using MaaWpfGui.Services;
using MaaWpfGui.States;
using Microsoft.Win32;
using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using Serilog;
using Stylet;
using static MaaWpfGui.Helper.CopilotHelper;
+using static MaaWpfGui.Models.AsstTasks.AsstCopilotTask;
using DataFormats = System.Windows.Forms.DataFormats;
using Task = System.Threading.Tasks.Task;
@@ -56,7 +58,7 @@ namespace MaaWpfGui.ViewModels.UI
private const string TempCopilotFile = "cache/_temp_copilot.json";
private static readonly string[] _supportExt = [".json", ".mp4", ".m4s", ".mkv", ".flv", ".avi"];
private const string CopilotJsonDir = "config/copilot";
- private const string StageNameRegex = @"(?:[a-z]{0,3})(?:\d{0,2})-(?:(?:A|B|C|D|EX|S|TR|MO)-?)?(?:\d{1,2})(\(Raid\)(?=\.json))?";
+ private const string StageNameRegex = @"(?:[a-z]{0,3})(?:\d{0,2})-(?:(?:A|B|C|D|EX|S|TR|MO)-?)?(?:\d{1,2})";
private const string InvalidStageNameChars = @"[:',\.\(\)\|\[\]\?,。【】{};:]"; // 无效字符
[GeneratedRegex(InvalidStageNameChars)]
@@ -1151,27 +1153,39 @@ namespace MaaWpfGui.ViewModels.UI
}
Regex regex = new Regex(@"(?<=;)(?[^,;]+)(?:, *(?\d))?(?=;)", RegexOptions.Compiled);
- JArray userAdditional = new(regex.Matches(";" + UserAdditional + ";").ToList().Select(match => new JObject
+
+ var userAdditional = regex.Matches(";" + UserAdditional + ";").ToList().Select(match => new UserAdditional
{
- ["name"] = match.Groups[1].Value.Trim(),
- ["skill"] = string.IsNullOrEmpty(match.Groups[2].Value) ? 0 : int.Parse(match.Groups[2].Value),
- }));
+ Name = match.Groups[1].Value.Trim(),
+ Skill = string.IsNullOrEmpty(match.Groups[2].Value) ? 0 : int.Parse(match.Groups[2].Value),
+ });
bool ret = true;
if (UseCopilotList)
{
_copilotIdList.Clear();
- bool startAny = false;
- foreach (var model in CopilotItemViewModels.Where(i => i.IsChecked))
- {
- _copilotIdList.Add(model.CopilotId);
- ret &= Instances.AsstProxy.AsstStartCopilot(model.FilePath, Form, AddTrust, AddUserAdditional, userAdditional, UseCopilotList, model.Name, model.IsRaid, _taskType, Loop ? LoopTimes : 1, _useSanityPotion, false);
- startAny = true;
- }
+ var tasks = CopilotItemViewModels.Where(i => i.IsChecked).Select(model =>
+ {
+ _copilotIdList.Add(model.CopilotId);
+ var task = new AsstCopilotTask()
+ {
+ FileName = model.FilePath,
+ Formation = _form,
+ AddTrust = _addTrust,
+ UserAdditionals = userAdditional.ToList(),
+ NeedNavigate = UseCopilotList,
+ StageName = model.Name,
+ IsRaid = model.IsRaid,
+ LoopTimes = Loop ? LoopTimes : 1,
+ UseSanityPotion = _useSanityPotion,
+ };
+ var (type, param) = task.Serialize();
+ return Instances.AsstProxy.AsstAppendTaskWithEncoding(AsstProxy.TaskType.Copilot, type, param);
+ }).ToList();
- if (startAny)
+ if (tasks.Count > 0)
{
- ret &= Instances.AsstProxy.AsstStart();
+ ret = tasks.All(t => t) && Instances.AsstProxy.AsstStart();
}
else
{// 一个都没启动,怎会有如此无聊之人
@@ -1181,7 +1195,18 @@ namespace MaaWpfGui.ViewModels.UI
}
else
{
- ret &= Instances.AsstProxy.AsstStartCopilot(IsDataFromWeb ? TempCopilotFile : Filename, Form, AddTrust, AddUserAdditional, userAdditional, UseCopilotList, string.Empty, false, _taskType, Loop ? LoopTimes : 1, false);
+ var task = new AsstCopilotTask()
+ {
+ FileName = IsDataFromWeb ? TempCopilotFile : Filename,
+ Formation = _form,
+ AddTrust = _addTrust,
+ UserAdditionals = userAdditional.ToList(),
+ NeedNavigate = false,
+ LoopTimes = Loop ? LoopTimes : 1,
+ UseSanityPotion = _useSanityPotion,
+ };
+ ret = Instances.AsstProxy.AsstAppendTaskWithEncoding(AsstProxy.TaskType.Copilot, _taskType, task.Serialize().Params);
+ ret &= Instances.AsstProxy.AsstStart();
}
if (ret)