From 56d831e627a70914cbe5ab78fee16a4ad6b34d2d Mon Sep 17 00:00:00 2001 From: status102 Date: Wed, 13 Sep 2023 22:29:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E6=88=98=E6=96=97?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=88=98=E6=96=97=E5=88=97=E8=A1=A8=E9=80=89?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/tasks.json | 37 +++ resource/template/AdverseDifficulty.png | Bin 0 -> 1548 bytes resource/template/NormalDifficulty.png | Bin 0 -> 2144 bytes src/MaaCore/MaaCore.vcxproj | 4 + src/MaaCore/MaaCore.vcxproj.filters | 12 + src/MaaCore/Task/Interface/CopilotTask.cpp | 62 +++- src/MaaCore/Task/Interface/CopilotTask.h | 7 + .../Task/Miscellaneous/BattleFormationTask.h | 4 +- .../CopilotListNotificationPlugin.cpp | 24 ++ .../CopilotListNotificationPlugin.h | 16 + .../Task/Miscellaneous/TaskFileReloadTask.cpp | 40 +++ .../Task/Miscellaneous/TaskFileReloadTask.h | 19 ++ src/MaaWpfGui/Constants/ConfigurationKeys.cs | 1 + src/MaaWpfGui/Main/AsstProxy.cs | 47 ++- src/MaaWpfGui/Res/Localizations/en-us.xaml | 2 + src/MaaWpfGui/Res/Localizations/ja-jp.xaml | 2 + src/MaaWpfGui/Res/Localizations/ko-kr.xaml | 2 + src/MaaWpfGui/Res/Localizations/zh-cn.xaml | 2 + src/MaaWpfGui/Res/Localizations/zh-tw.xaml | 2 + .../ViewModels/CopilotItemViewModel.cs | 104 ++++++ .../ViewModels/UI/CopilotViewModel.cs | 210 +++++++++++- src/MaaWpfGui/Views/UI/CopilotView.xaml | 313 ++++++++++++------ 22 files changed, 785 insertions(+), 125 deletions(-) create mode 100644 resource/template/AdverseDifficulty.png create mode 100644 resource/template/NormalDifficulty.png create mode 100644 src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp create mode 100644 src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h create mode 100644 src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp create mode 100644 src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h create mode 100644 src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs diff --git a/resource/tasks.json b/resource/tasks.json index d62dd92e06..e869d21ff0 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -610,6 +610,27 @@ 50 ] }, + "ChangeToAdverseDifficulty": { + "template": "AdverseDifficulty.png", + "action": "ClickSelf", + "roi": [ + 625, + 640, + 80, + 65 + ], + "maxTimes": 3, + "next": [ + "AdverseConfirm", + "#self" + ] + }, + "AdverseConfirm": { + "baseTask": "ChangeToAdverseDifficulty", + "action": "DoNothing", + "template": "NormalDifficulty.png", + "next": [] + }, "Episode": { "Doc": "base_task", "algorithm": "JustReturn", @@ -7021,6 +7042,12 @@ "Stop" ] }, + "BattleQuickFormationCheck": { + "baseTask": "BattleQuickFormation", + "template": "BattleQuickFormation.png", + "action": "DoNothing", + "next": [] + }, "BattleQuickFormation": { "action": "ClickSelf", "roi": [ @@ -13097,6 +13124,16 @@ "baseTask": "BattleStartPre", "action": "DoNothing" }, + "Copilot@BattleStartPreFlag": { + "baseTask": "BattleStartPre", + "action": "DoNothing", + "roi":[ + 0, + 0, + 1280, + 720 + ] + }, "BattleFormationOCRNameFlag": { "templThreshold": 0.6, "roi": [ diff --git a/resource/template/AdverseDifficulty.png b/resource/template/AdverseDifficulty.png new file mode 100644 index 0000000000000000000000000000000000000000..56b49bfa60bac166218065a32b8f155525da9c86 GIT binary patch literal 1548 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 W)Syva>r3JQ0000 + + @@ -234,8 +236,10 @@ + + diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index f3a8ed3d92..ae11bef9b1 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -633,6 +633,12 @@ 源文件\Task\Infrast + + 源文件\Task\Miscellaneous + + + 源文件\Task\Miscellaneous + @@ -1049,5 +1055,11 @@ 源文件\Task\Infrast + + 源文件\Task\Miscellaneous + + + 源文件\Task\Miscellaneous + \ No newline at end of file diff --git a/src/MaaCore/Task/Interface/CopilotTask.cpp b/src/MaaCore/Task/Interface/CopilotTask.cpp index 2fffa38a47..42a5b45590 100644 --- a/src/MaaCore/Task/Interface/CopilotTask.cpp +++ b/src/MaaCore/Task/Interface/CopilotTask.cpp @@ -3,33 +3,48 @@ #include #include "Config/Miscellaneous/CopilotConfig.h" +#include "Config/TaskData.h" #include "Task/Miscellaneous/BattleFormationTask.h" #include "Task/Miscellaneous/BattleProcessTask.h" +#include "Task/Miscellaneous/CopilotListNotificationPlugin.h" +#include "Task/Miscellaneous/TaskFileReloadTask.h" #include "Task/ProcessTask.h" #include "Utils/Logger.hpp" #include "Utils/Platform.hpp" asst::CopilotTask::CopilotTask(const AsstCallback& callback, Assistant* inst) : InterfaceTask(callback, inst, TaskType), + m_task_file_reload_task_ptr(std::make_shared(callback, inst, TaskType)), + m_navigate_task_ptr(std::make_shared(callback, inst, TaskType)), + m_not_use_prts_task_ptr(std::make_shared(callback, inst, TaskType)), + m_adverse_select_task_ptr(std::make_shared(callback, inst, TaskType)), m_formation_task_ptr(std::make_shared(callback, inst, TaskType)), m_battle_task_ptr(std::make_shared(callback, inst, TaskType)), m_stop_task_ptr(std::make_shared(callback, inst, TaskType)) { LogTraceFunction; + m_subtasks.emplace_back(m_task_file_reload_task_ptr); + m_subtasks.emplace_back(m_navigate_task_ptr); + m_subtasks.emplace_back(m_not_use_prts_task_ptr); + + // 选择突袭模式 + m_adverse_select_task_ptr->set_tasks({ "ChangeToAdverseDifficulty", "AdverseConfirm" }); + m_subtasks.emplace_back(m_adverse_select_task_ptr); + auto start_1_tp = std::make_shared(callback, inst, TaskType); start_1_tp->set_tasks({ "BattleStartPre" }).set_retry_times(0).set_ignore_error(true); m_subtasks.emplace_back(start_1_tp); - m_subtasks.emplace_back(m_formation_task_ptr); + m_subtasks.emplace_back(m_formation_task_ptr)->set_retry_times(0); auto start_2_tp = std::make_shared(callback, inst, TaskType); start_2_tp->set_tasks({ "BattleStartAll" }).set_ignore_error(false); + m_copilot_list_notification_ptr = start_2_tp->register_plugin(); m_subtasks.emplace_back(start_2_tp); m_subtasks.emplace_back(m_battle_task_ptr)->set_retry_times(0); - m_stop_task_ptr->set_tasks({ "ClickCornerUntilStartButton" }); m_stop_task_ptr->set_enable(false); m_subtasks.emplace_back(m_stop_task_ptr); } @@ -56,10 +71,14 @@ bool asst::CopilotTask::set_params(const json::value& params) Log.error("CopilotConfig parse failed"); return false; } + m_task_file_reload_task_ptr->set_magic_code(match[1].str()); } - else if (!Copilot.load(utils::path(*filename_opt))) { - Log.error("CopilotConfig parse failed"); - return false; + else { + if (!Copilot.load(utils::path(*filename_opt))) { + Log.error("CopilotConfig parse failed"); + return false; + } + m_task_file_reload_task_ptr->set_path(std::move(*filename_opt)); } m_stage_name = Copilot.get_stage_name(); @@ -70,6 +89,8 @@ bool asst::CopilotTask::set_params(const json::value& params) bool with_formation = params.get("formation", false); m_formation_task_ptr->set_enable(with_formation); + + // 自动补信赖 m_formation_task_ptr->set_add_trust(params.get("add_trust", false)); m_formation_task_ptr->set_add_user_additional(params.get("add_user_additional", false)); auto user_additional_opt = params.find("user_additional"); @@ -88,21 +109,46 @@ bool asst::CopilotTask::set_params(const json::value& params) m_formation_task_ptr->set_user_additional(std::move(user_additional)); } + // 是否在当前页面左右滑动寻找关卡 + // 启用队列的话,这项为true + bool need_navigate = params.get("need_navigate", false); + m_task_file_reload_task_ptr->set_enable(need_navigate); + + // 不使用代理指挥 + m_not_use_prts_task_ptr->set_enable(need_navigate && with_formation); + m_not_use_prts_task_ptr->set_tasks({ "NotUsePrts", "Stop" }); + + bool is_adverse = params.get("is_adverse", false); + m_adverse_select_task_ptr->set_enable(need_navigate && is_adverse); + + // 防止在关卡名展开的情况下无法滑动,调整滑动区域 + std::string m_navigate_name = params.get("navigate_name", std::string()); + Task.get(m_navigate_name + "@Copilot@ClickStageName")->text = { m_navigate_name }; + Task.get(m_navigate_name + "@Copilot@ClickedCorrectStage")->text = { m_navigate_name }; + Task.get(m_navigate_name + "@Copilot@FullStageNavigation")->specific_rect = Rect(600, 100, 20, 20); + m_navigate_task_ptr->set_tasks({ m_navigate_name + "@Copilot@StageNavigationBegin" }); + m_navigate_task_ptr->set_enable(need_navigate); + std::string support_unit_name = params.get("support_unit_name", std::string()); m_formation_task_ptr->set_support_unit_name(std::move(support_unit_name)); size_t loop_times = params.get("loop_times", 1); if (loop_times > 1) { + m_stop_task_ptr->set_tasks({ "ClickCornerUntilStartButton" }); + m_stop_task_ptr->set_enable(true); + + // 追加 m_subtasks.reserve(m_subtasks.size() * loop_times); auto raw_end = m_subtasks.end(); for (size_t i = 1; i < loop_times; ++i) { // FIXME: 如果多次调用 set_params,这里复制的会有问题 m_subtasks.insert(m_subtasks.end(), m_subtasks.begin(), raw_end); } - m_stop_task_ptr->set_enable(true); } - else { - m_stop_task_ptr->set_enable(false); + else if (need_navigate) { + Task.get("Copilot@BattleStartPreFlag")->text.emplace_back(m_navigate_name); + m_stop_task_ptr->set_tasks({ "Copilot@ClickCornerUntilStartButton" }); + m_stop_task_ptr->set_enable(true); } return true; diff --git a/src/MaaCore/Task/Interface/CopilotTask.h b/src/MaaCore/Task/Interface/CopilotTask.h index 323fcb9a46..d7335e55c3 100644 --- a/src/MaaCore/Task/Interface/CopilotTask.h +++ b/src/MaaCore/Task/Interface/CopilotTask.h @@ -5,8 +5,10 @@ namespace asst { + class TaskFileReloadTask; class BattleProcessTask; class BattleFormationTask; + class CopilotListNotificationPlugin; class ProcessTask; // 抄作业任务 @@ -22,8 +24,13 @@ namespace asst std::string get_stage_name() const { return m_stage_name; } private: + std::shared_ptr m_task_file_reload_task_ptr = nullptr; + std::shared_ptr m_navigate_task_ptr = nullptr; + std::shared_ptr m_not_use_prts_task_ptr = nullptr; + std::shared_ptr m_adverse_select_task_ptr = nullptr; std::shared_ptr m_formation_task_ptr = nullptr; std::shared_ptr m_battle_task_ptr = nullptr; + std::shared_ptr m_copilot_list_notification_ptr = nullptr; std::shared_ptr m_stop_task_ptr = nullptr; std::string m_stage_name; }; diff --git a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h index 26ea9d1c88..ca3b07a307 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h +++ b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h @@ -25,8 +25,11 @@ namespace asst void append_additional_formation(AdditionalFormation formation); void set_support_unit_name(std::string name); + // 是否追加自定干员 void set_add_user_additional(bool add_user_additional); + // 设置追加自定干员列表 void set_user_additional(std::vector> user_additional); + // 是否追加低信赖干员 void set_add_trust(bool add_trust); enum class DataResource @@ -45,7 +48,6 @@ namespace asst bool add_additional(); // 补充刷信赖的干员,从最小的开始 bool add_trust_operators(); - bool enter_selection_page(); bool select_opers_in_cur_page(std::vector& groups); void swipe_page(); diff --git a/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp new file mode 100644 index 0000000000..011f40381c --- /dev/null +++ b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp @@ -0,0 +1,24 @@ +#include "CopilotListNotificationPlugin.h" + +bool asst::CopilotListNotificationPlugin::verify(AsstMsg msg, const json::value& details) const +{ + if (msg != AsstMsg::SubTaskStart || details.get("subtask", std::string()) != "ProcessTask") { + return false; + } + + const std::string task = details.at("details").at("task").as_string(); + if (task != "BattleStartAll" && task.starts_with("BattleStart")) { + return true; + } + else { + return false; + } +} + +bool asst::CopilotListNotificationPlugin::_run() +{ + json::value info = basic_info_with_what("CopilotListEnterSuccess"); + callback(AsstMsg::SubTaskExtraInfo, info); + + return true; +} diff --git a/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h new file mode 100644 index 0000000000..6c47221d00 --- /dev/null +++ b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h @@ -0,0 +1,16 @@ +#pragma once +#include "Task/AbstractTaskPlugin.h" + +namespace asst +{ + class CopilotListNotificationPlugin : public AbstractTaskPlugin + { + public: + using AbstractTaskPlugin::AbstractTaskPlugin; + virtual ~CopilotListNotificationPlugin() override = default; + virtual bool verify(AsstMsg msg, const json::value& details) const override; + + private: + virtual bool _run() override; + }; +} diff --git a/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp new file mode 100644 index 0000000000..ee49794fbf --- /dev/null +++ b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp @@ -0,0 +1,40 @@ +#include "TaskFileReloadTask.h" + +#include "Config/Miscellaneous/CopilotConfig.h" +#include "Utils/Logger.hpp" + +void asst::TaskFileReloadTask::set_magic_code(std::string code) +{ + is_magic_code = true; + m_file = std::move(code); +} + +void asst::TaskFileReloadTask::set_path(std::string path) +{ + is_path = true; + m_file = std::move(path); +} + +bool asst::TaskFileReloadTask::_run() +{ + if (is_magic_code) { + if (!Copilot.parse_magic_code(m_file)) { + Log.error("CopilotConfig parse failed"); + return false; + } + } + else if (is_path) { + if (!Copilot.load(utils::path(m_file))) { + Log.error("CopilotConfig parse failed"); + return false; + } + } + else { + return false; + } + + json::value info = basic_info_with_what("CopilotListLoadTaskFileSuccess"); + info["details"]["stage_name"] = Copilot.get_stage_name(); + callback(AsstMsg::SubTaskExtraInfo, info); + return true; +} diff --git a/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h new file mode 100644 index 0000000000..695f536451 --- /dev/null +++ b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h @@ -0,0 +1,19 @@ +#pragma once +#include "Task/AbstractTaskPlugin.h" + +namespace asst +{ + class TaskFileReloadTask : public AbstractTask + { + public: + using AbstractTask::AbstractTask; + virtual ~TaskFileReloadTask() override = default; + void set_magic_code(std::string code); + void set_path(std::string path); + + private: + virtual bool _run() override; + std::string m_file; + bool is_path = false, is_magic_code = false; + }; +} diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index 4e77ed7760..64def5a771 100644 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -127,6 +127,7 @@ namespace MaaWpfGui.Constants public const string CopilotAddUserAdditional = "Copilot.AddUserAdditional"; public const string CopilotUserAdditional = "Copilot.UserAdditional"; public const string CopilotLoopTimes = "Copilot.LoopTimes"; + public const string CopilotTaskList = "Copilot.CopilotTaskList"; public const string UpdateProxy = "VersionUpdate.Proxy"; public const string VersionType = "VersionUpdate.VersionType"; diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index db8e830004..a4dbcfb686 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -15,15 +15,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; -using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; using HandyControl.Data; -using HandyControl.Tools.Extension; using MaaWpfGui.Constants; using MaaWpfGui.Extensions; using MaaWpfGui.Helper; @@ -573,7 +572,11 @@ namespace MaaWpfGui.Main Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("CompleteTask") + taskChain); if (isCoplitTaskChain) { - runningState.SetIdle(true); + if (!Instances.CopilotViewModel.UseCopilotList || Instances.CopilotViewModel.CopilotItemViewModels.All(model => !model.IsChecked)) + { + runningState.SetIdle(true); + } + Instances.CopilotViewModel.AddLog(LocalizationHelper.GetString("CompleteCombat"), UiLogColor.Info); } @@ -1058,6 +1061,12 @@ namespace MaaWpfGui.Main } break; + case "CopilotListLoadTaskFileSuccess": + Instances.CopilotViewModel.AddLog("Parse " + subTaskDetails["stage_name"].ToString() + " Success"); + break; + case "CopilotListEnterSuccess": + Instances.CopilotViewModel.EnterCopilotTask(); + break; case "SSSStage": { @@ -1832,35 +1841,37 @@ namespace MaaWpfGui.Main /// 是否追加信赖干员 /// 是否追加自定干员 /// 自定干员列表 + /// 是否导航至关卡(启用自动战斗序列) + /// 关卡名 + /// 是不是突袭 /// 任务类型 /// 任务重复执行次数 + /// 是否启动战斗 /// 是否成功。 - public bool AsstStartCopilot(string filename, bool formation, bool add_trust, bool add_user_additional, string user_additional, string type, int loop_times) + public bool AsstStartCopilot(string filename, bool formation, bool add_trust, bool add_user_additional, JArray user_additional, bool need_navigate, string navigate_name, bool is_adverse, string type, int loop_times, bool asst_start = true) { - JArray m_user_additional = new JArray(); - Regex regex = new Regex(@"(?<=;)(?[^,;]+)(?:, *(?\d))? *", RegexOptions.Compiled); - MatchCollection matches = regex.Matches(";" + user_additional); - foreach (Match match in matches) - { - m_user_additional.Add(new JObject - { - ["name"] = match.Groups[1].Value.Trim(), - ["skill"] = match.Groups[2].Value.IsNullOrEmpty() ? 0 : int.Parse(match.Groups[2].Value), - }); - } - var task_params = new JObject { ["filename"] = filename, ["formation"] = formation, ["add_trust"] = add_trust, ["add_user_additional"] = add_user_additional, - ["user_additional"] = m_user_additional, + ["user_additional"] = user_additional, + ["need_navigate"] = need_navigate, + ["navigate_name"] = navigate_name, + ["is_adverse"] = is_adverse, ["loop_times"] = loop_times, }; AsstTaskId id = AsstAppendTaskWithEncoding(type, task_params); _latestTaskId[TaskType.Copilot] = id; - return id != 0 && AsstStart(); + if (asst_start) + { + return id != 0 && AsstStart(); + } + else + { + return id != 0; + } } public bool AsstStartVideoRec(string filename) diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index c816728f6c..47412f8525 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -446,6 +446,8 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla Add low-trust operators Add custom operators Use ";" as the separator, "," to separate the operator name and skills, for example: W, 3; Ash, 2 + Battle list (Please switch to the level selection page before starting) + Right click to add raid difficulty Loop Times Start Video Link diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml index 10fb166a69..b6d39ad072 100644 --- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml +++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml @@ -438,6 +438,8 @@ Bilibili: ログイン インターフェイスに表示されるアカウント 信頼性の低いオペレーターを追加する カスタム戦術要員の追加 使用「;」オペレータ名とスキルを区切るには、区切り文字として「,」を使用します。例: W, 3; Ash, 2 + バトルリスト(開始前にレベル選択ページに切り替えてください) + 右クリックしてレイドの難易度を追加します ループ回数 開始 映像へのハイパーリンク diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml index d727e678da..7e9bd0f9ef 100644 --- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml +++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml @@ -450,6 +450,8 @@ Bilibili: 로그인 인터페이스에 표시되는 계정 이름(예: Zhang San 신뢰도가 낮은 운영자 추가 맞춤 연산자 추가 사용 ";" 운영자 이름과 기술을 구분하기 위해 구분 기호 ","를 사용합니다. 예: W, 3; Ash, 2 + 전투 목록(시작하기 전에 레벨 선택 페이지로 전환하세요) + 공격대 난이도를 추가하려면 마우스 오른쪽 버튼을 클릭하세요. 반복 횟수 시작 영상 링크 diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 65075a6c86..6a8415acce 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -468,6 +468,8 @@ 追加自定干员 以英文";"为分隔符,英文","分隔干员名与技能,例: 史尔特尔,3;艾雅法拉,1 循环次数 + 战斗列表 (开始前请切换至关卡选择页面) + 右键添加突袭难度 开始 视频链接 diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml index ecff9cc6ed..2eaf730d22 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml @@ -448,6 +448,8 @@ 補充低信賴幹員 追加自定幹員 使用";"作為分隔符,用","分隔操作員姓名和技能,例:史尔特尔,3;艾雅法拉,1 + 戰鬥列表 (開始前請切換至關卡選擇頁面) + 右鍵添加突襲難度 循環次數 開始 影片連結 diff --git a/src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs b/src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs new file mode 100644 index 0000000000..8c974070e3 --- /dev/null +++ b/src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs @@ -0,0 +1,104 @@ +using System.Security.RightsManagement; +using Stylet; +using Vanara.PInvoke; + +namespace MaaWpfGui.ViewModels +{ + public class CopilotItemViewModel : PropertyChangedBase + { + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// The original Name of file + public CopilotItemViewModel(string name, string filePath) + { + Name = name; + FilePath = filePath; + IsChecked = true; + } + + private string _filePath; + + /// + /// Gets or sets the original_name. + /// + public string FilePath + { + get => _filePath; + set => SetAndNotify(ref _filePath, value); + } + + private string _name; + + /// + /// Gets or sets the name. + /// + public string Name + { + get => _name; + set => SetAndNotify(ref _name, value); + } + + private bool _isChecked; + + /// + /// Gets or sets a value indicating whether gets or sets whether the key is checked. + /// + public bool IsChecked + { + get => _isChecked; + set + { + SetAndNotify(ref _isChecked, value); + } + } + + // 换成图标的话要这个,暂时没用 + private string _iconPath; + + /// + /// Gets or sets the icon path. + /// + // ReSharper disable once UnusedMember.Global + public string IconPath + { + get => _iconPath; + set => SetAndNotify(ref _iconPath, value); + } + + private string _token; + + /// + /// Gets or sets the token. + /// + // ReSharper disable once UnusedMember.Global + public string Token + { + get => _token; + set => SetAndNotify(ref _token, value); + } + + private string _runStatus; + + /// + /// Gets or sets the running status. + /// + // ReSharper disable once UnusedMember.Global + public string RunStatus + { + get => _runStatus; + set => SetAndNotify(ref _runStatus, value); + } + + private int _index = 0; + + public int Index + { + get => _index; + set => SetAndNotify(ref _index, value); + } + + public int GetIndex() => Index; + } +} diff --git a/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs b/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs index c03cfd9bd8..2a01e55948 100644 --- a/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs @@ -21,14 +21,17 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using HandyControl.Tools.Extension; using MaaWpfGui.Constants; using MaaWpfGui.Helper; using MaaWpfGui.States; using Microsoft.Win32; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Serilog; using Stylet; using DataFormats = System.Windows.Forms.DataFormats; +using Task = System.Threading.Tasks.Task; namespace MaaWpfGui.ViewModels.UI { @@ -46,6 +49,11 @@ namespace MaaWpfGui.ViewModels.UI /// public ObservableCollection LogItemViewModels { get; } + /// + /// Gets or private sets the view models of Copilot items. + /// + public ObservableCollection CopilotItemViewModels { get; private set; } = new ObservableCollection(); + /// /// Initializes a new instance of the class. /// @@ -56,6 +64,21 @@ namespace MaaWpfGui.ViewModels.UI AddLog(LocalizationHelper.GetString("CopilotTip")); _runningState = RunningState.Instance; _runningState.IdleChanged += RunningState_IdleChanged; + + var copilotTaskList = ConfigurationHelper.GetValue(ConfigurationKeys.CopilotTaskList, string.Empty); + if (!string.IsNullOrEmpty(copilotTaskList)) + { + JArray jArray = JArray.Parse(copilotTaskList); + foreach (var item in jArray) + { + if ((item as JObject).TryGetValue("file_path", out var token) && File.Exists(token.ToString())) + { + CopilotItemViewModels.Add(new CopilotItemViewModel((string)item["name"], (string)item["file_path"]) { IsChecked = (bool)item["is_checked"] }); + } + } + + CopilotItemIndexChanged(); + } } private void RunningState_IdleChanged(object sender, bool e) @@ -236,6 +259,14 @@ namespace MaaWpfGui.ViewModels.UI if (doc != null && doc.TryGetValue("title", out var titleValue)) { title = titleValue.ToString(); + + // 为自动作战列表匹配名字 + var linkParser = new Regex(@"([a-z]{0,3})(\d{0,2})-(EX-)?(\d{1,2})", RegexOptions.Compiled | RegexOptions.IgnoreCase); + foreach (Match match in linkParser.Matches(title)) + { + CopilotTaskName = match.Value; + break; + } } if (title.Length != 0) @@ -503,6 +534,144 @@ namespace MaaWpfGui.ViewModels.UI } } + /// + /// Gets or sets a value indicating whether to use auto-formation. + /// + private bool _useCopilotList = false; + + public bool UseCopilotList + { + get => _useCopilotList; + set + { + SetAndNotify(ref _useCopilotList, value); + } + } + + /// + /// Gets or sets a value indicating whether to use auto-formation. + /// + private string _copilotTaskName = string.Empty; + + public string CopilotTaskName + { + get => _copilotTaskName; + set + { + SetAndNotify(ref _copilotTaskName, value); + } + } + + private static string copilotJsonDir = "cache/copilot"; + + public void AddCopilotTask() + { + var stage_name = CopilotTaskName.Trim().Replace("突袭", "-Adverse"); + if (!stage_name.IsNullOrEmpty()) + { + AddCopilotTaskToList(stage_name); + } + } + + public void AddCopilotTask_Adverse() + { + var stage_name = CopilotTaskName.Trim().Replace("突袭", "-Adverse"); + if (!stage_name.EndsWith("-Adverse")) + { + stage_name += "-Adverse"; + } + + if (!stage_name.IsNullOrEmpty()) + { + AddCopilotTaskToList(stage_name); + } + } + + public void AddCopilotTaskToList(string stage_name) + { + var jsonPath = $"{copilotJsonDir}/{stage_name}.json"; + + try + { + Directory.CreateDirectory(copilotJsonDir); + } + catch + { + } + + try + { + File.Copy(IsDataFromWeb ? TempCopilotFile : Filename, jsonPath, true); + var item = new CopilotItemViewModel(stage_name, jsonPath) + { + Index = CopilotItemViewModels.Count, + }; + CopilotItemViewModels.Add(item); + SaveCopilotTask(); + } + catch (Exception ex) + { + AddLog(LocalizationHelper.GetString("CopilotJsonError"), UiLogColor.Error); + Log.Error(ex.ToString()); + } + } + + public void SaveCopilotTask() + { + JArray jArray = new JArray(CopilotItemViewModels.Select(item => new JObject + { + ["name"] = item.Name, + ["file_path"] = item.FilePath, + ["is_checked"] = item.IsChecked, + }).ToArray()); + ConfigurationHelper.SetValue(ConfigurationKeys.CopilotTaskList, JsonConvert.SerializeObject(jArray)); + } + + public void DeleteCopilotTask(int index) + { + CopilotItemViewModels.RemoveAt(index); + CopilotItemIndexChanged(); + } + + public void ClearCopilotTask() + { + CopilotItemViewModels.Clear(); + SaveCopilotTask(); + } + + public void EnterCopilotTask() + { + Application.Current.Dispatcher.InvokeAsync(() => + { + for (int i = 0; i < CopilotItemViewModels.Count; i++) + { + if (CopilotItemViewModels[i].IsChecked) + { + CopilotItemViewModels[i].IsChecked = false; + break; + } + } + + SaveCopilotTask(); + }); + } + + /// + /// 更新任务顺序 + /// + public void CopilotItemIndexChanged() + { + Application.Current.Dispatcher.InvokeAsync(() => + { + for (int i = 0; i < CopilotItemViewModels.Count; i++) + { + CopilotItemViewModels[i].Index = i; + } + + SaveCopilotTask(); + }); + } + public bool Loop { get; set; } private int _loopTimes = int.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.CopilotLoopTimes, "1")); @@ -558,14 +727,51 @@ namespace MaaWpfGui.ViewModels.UI AddLog(errMsg, UiLogColor.Error); } - bool ret = Instances.AsstProxy.AsstStartCopilot(IsDataFromWeb ? TempCopilotFile : Filename, Form, AddTrust, AddUserAdditional, UserAdditional, _taskType, - Loop ? LoopTimes : 1); + JArray mUserAdditional = new JArray(); + Regex regex = new Regex(@"(?<=;)(?[^,;]+)(?:, *(?\d))? *", RegexOptions.Compiled); + MatchCollection matches = regex.Matches(";" + UserAdditional); + foreach (Match match in matches) + { + mUserAdditional.Add(new JObject + { + ["name"] = match.Groups[1].Value.Trim(), + ["skill"] = match.Groups[2].Value.IsNullOrEmpty() ? 0 : int.Parse(match.Groups[2].Value), + }); + } + + bool ret = true; + if (UseCopilotList) + { + bool startAny = false; + foreach (var model in CopilotItemViewModels) + { + if (model.IsChecked) + { + ret &= Instances.AsstProxy.AsstStartCopilot(model.FilePath, Form, AddTrust, AddUserAdditional, mUserAdditional, UseCopilotList, model.Name.Replace("-Adverse", string.Empty), model.Name.Contains("-Adverse"), _taskType, Loop ? LoopTimes : 1, false); + startAny = true; + } + } + + // 一个都没启动,怎会有如此无聊之人 + if (!startAny) + { + return; + } + + ret &= Instances.AsstProxy.AsstStart(); + } + else + { + ret &= Instances.AsstProxy.AsstStartCopilot(IsDataFromWeb ? TempCopilotFile : Filename, Form, AddTrust, AddUserAdditional, mUserAdditional, UseCopilotList, string.Empty, false, _taskType, Loop ? LoopTimes : 1); + } + if (ret) { AddLog(LocalizationHelper.GetString("Running")); } else { + Instances.AsstProxy.AsstStop(); _runningState.SetIdle(true); AddLog(LocalizationHelper.GetString("CopilotFileReadError"), UiLogColor.Error); } diff --git a/src/MaaWpfGui/Views/UI/CopilotView.xaml b/src/MaaWpfGui/Views/UI/CopilotView.xaml index 759b6674f7..464c955535 100644 --- a/src/MaaWpfGui/Views/UI/CopilotView.xaml +++ b/src/MaaWpfGui/Views/UI/CopilotView.xaml @@ -6,6 +6,7 @@ xmlns:constants="clr-namespace:MaaWpfGui.Constants" xmlns:controls="clr-namespace:MaaWpfGui.Styles.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:dd="urn:gong-wpf-dragdrop" xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:helper="clr-namespace:MaaWpfGui.Helper" xmlns:local="clr-namespace:MaaWpfGui" @@ -31,7 +32,7 @@ @@ -62,90 +63,22 @@ Style="{StaticResource ButtonDefault}" ToolTip="{DynamicResource PasteClipboardTip}" /> -