From 979f6699ccdf7b89757259f6ebd39308f4f90e46 Mon Sep 17 00:00:00 2001 From: Yoake <120039624+Yoak3n@users.noreply.github.com> Date: Tue, 6 May 2025 16:56:37 +0800 Subject: [PATCH] =?UTF-8?q?Reapply=20"feat:=E5=AE=9E=E7=8E=B0=E8=87=AA?= =?UTF-8?q?=E9=80=82=E5=BA=94=E8=B0=83=E6=95=B4=E8=BF=9E=E6=88=98=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=20(#12555)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 7359653317d269a532a723d784b16244b8ed7256. 移除不相关的文件修改 --------- Co-authored-by: uye <99072975+ABA2396@users.noreply.github.com> --- resource/tasks/tasks.json | 6 + .../template/FightSeries-List-Exceeded.png | Bin 0 -> 336 bytes src/MaaCore/MaaCore.vcxproj | 2 + src/MaaCore/MaaCore.vcxproj.filters | 6 + .../Task/Fight/FightSeriesAdjustPlugin.cpp | 103 ++++++++++++++++++ .../Task/Fight/FightSeriesAdjustPlugin.h | 32 ++++++ .../Task/Fight/FightTimesTaskPlugin.cpp | 1 + src/MaaCore/Task/Interface/FightTask.cpp | 19 +++- src/MaaCore/Task/Interface/FightTask.h | 2 + .../FightSettingsUserControlModel.cs | 17 ++- .../TaskQueue/FightSettingsUserControl.xaml | 4 +- 11 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 resource/template/FightSeries-List-Exceeded.png create mode 100644 src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.cpp create mode 100644 src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.h diff --git a/resource/tasks/tasks.json b/resource/tasks/tasks.json index 453cfe55e4..08405af76c 100644 --- a/resource/tasks/tasks.json +++ b/resource/tasks/tasks.json @@ -1253,6 +1253,11 @@ "action": "ClickRect", "specificRect": [965, 200, 70, 50] }, + "FightSeries-List-Exceeded": { + "template": "FightSeries-List-Exceeded.png", + "roi": [965, 200, 70, 325], + "doc": "找到每一个需要补充理智的连战次数" + }, "StartButton1": { "doc": "绑定插件调整连战次数", "algorithm": "OcrDetect", @@ -1520,6 +1525,7 @@ "next": ["CloseStonePage"] }, "CloseStonePage": { + "Doc": "2025.5.5:next 在 FightSeriesAdjustPlugin 插件中被动态修改", "algorithm": "JustReturn", "action": "ClickRect", "specificRect": [0, 200, 300, 400], diff --git a/resource/template/FightSeries-List-Exceeded.png b/resource/template/FightSeries-List-Exceeded.png new file mode 100644 index 0000000000000000000000000000000000000000..c7e05fe2d10f5c5a97f8b58aee88d12c489edc31 GIT binary patch literal 336 zcmV-W0k8gvP)p0003ONklWD z2xPEZx-jwy0<|#<3UgSyafKuU5l|MUoS9i{-cBGAoeLy)i7(nGw)BwL@*`qP4~ov; zEjnjA80~ + @@ -446,6 +447,7 @@ + diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index a419bba7d0..ec4306b470 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -1328,6 +1328,9 @@ Source\Task\Roguelike + + Source\Task\Fight + @@ -1842,6 +1845,9 @@ Source\Task\Roguelike + + Source\Task\Fight + diff --git a/src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.cpp b/src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.cpp new file mode 100644 index 0000000000..81cb864822 --- /dev/null +++ b/src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.cpp @@ -0,0 +1,103 @@ +#include "FightSeriesAdjustPlugin.h" + +#include "Config/TaskData.h" +#include "Controller/Controller.h" +#include "Task/ProcessTask.h" +#include "Utils/Logger.hpp" +#include "Vision/MultiMatcher.h" +#include "Vision/RegionOCRer.h" + +bool asst::FightSeriesAdjustPlugin::verify(AsstMsg msg, const json::value& details) const +{ + if (msg != AsstMsg::SubTaskCompleted || details.get("subtask", std::string()) != "ProcessTask") { + return false; + } + + return details.get("details", "task", "").ends_with("CloseStonePage"); +} + +bool asst::FightSeriesAdjustPlugin::_run() +{ + LogTraceFunction; + + auto task = ProcessTask(*this, { "FightSeries-Open" }); + task.run(); + + int exceeded_num = get_exceeded_num(); + if (exceeded_num <= 6 && exceeded_num > 1) { + ProcessTask(*this, { "FightSeries-List-" + std::to_string(exceeded_num - 1) }).run(); + set_close_stone_page_next(true); + } + else { + set_close_stone_page_next(false); + } + return true; +} + +int asst::FightSeriesAdjustPlugin::get_exceeded_num() const +{ + const std::vector> list_y_ranges = { + { 505, 505 + 55 }, // List-1: [505, 560) + { 445, 445 + 55 }, // List-2: [445, 500) + { 383, 383 + 55 }, // List-3: [383, 438) + { 320, 320 + 55 }, // List-4: [320, 375) + { 260, 260 + 55 }, // List-5: [260, 315) + { 200, 200 + 50 } // List-6: [200, 250) + }; + + auto img = ctrler()->get_image(); + if (img.empty()) { + return 0; + } + MultiMatcher multi_matcher(img); + multi_matcher.set_task_info("FightSeries-List-Exceeded"); + if (!multi_matcher.analyze()) { + Log.info(__FUNCTION__, "Fight series exceeded analyze failed"); + LogInfo << __FUNCTION__ << "Falling back to OCR for exceeded number detection."; + + std::vector detected_numbers; + + for (const auto& range : list_y_ranges) { + RegionOCRer analyzer(img); + analyzer.set_task_info("NumberOcrReplace"); + analyzer.set_bin_threshold(150, 255); + analyzer.set_roi({ 980, range.first, 40, range.second - range.first }); + + auto result_opt = analyzer.analyze(); + if (result_opt && !result_opt->text.empty()) { + try { + int number = std::stoi(result_opt->text); + detected_numbers.push_back(number); + } + catch (const std::invalid_argument&) { + LogInfo << __FUNCTION__ << "OCR failed to parse number: " << result_opt->text; + } + } + } + + if (!detected_numbers.empty()) { + int max_number = *std::max_element(detected_numbers.begin(), detected_numbers.end()); + LogInfo << __FUNCTION__ << "Detected max number via OCR: " << max_number; + return max_number + 1; + } + + return -1; + } + auto match_result = multi_matcher.get_result(); + if (match_result.empty()) { + LogInfo << __FUNCTION__ << "No matches found for FightSeries-List-Exceeded."; + return -1; + } + sort_by_vertical_(match_result); + int exceeded_y_pos = match_result.back().rect.y; + for (size_t i = 0; i < list_y_ranges.size(); ++i) { + const auto& range = list_y_ranges[i]; + if (exceeded_y_pos >= range.first && exceeded_y_pos < range.second) { + int list_index = static_cast(i + 1); // 列表序号从 1 开始 + LogInfo << __FUNCTION__ << "Exceeded icon y=" << exceeded_y_pos << " is within List-" << list_index + << " range [" << range.first << ", " << range.second << ")."; + return list_index; + } + } + return 0; +} diff --git a/src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.h b/src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.h new file mode 100644 index 0000000000..fe6f0b2978 --- /dev/null +++ b/src/MaaCore/Task/Fight/FightSeriesAdjustPlugin.h @@ -0,0 +1,32 @@ +#pragma once +#include "Config/TaskData.h" +#include "Task/AbstractTaskPlugin.h" + +namespace asst +{ +class FightSeriesAdjustPlugin final : public AbstractTaskPlugin +{ +public: + using AbstractTaskPlugin::AbstractTaskPlugin; + virtual ~FightSeriesAdjustPlugin() override = default; + + virtual bool verify(AsstMsg msg, const json::value& details) const override; + + void set_close_stone_page_next(bool enable) const + { + Task.get("Fight@CloseStonePage")->next = + enable ? modified_close_stone_page_next : original_close_stone_page_next; + }; + +protected: + virtual bool _run() override; + +private: + // 临时处理 + std::vector original_close_stone_page_next = { "Fight@StageSNReturnFlag", "Fight@Stop" }; + std::vector modified_close_stone_page_next = { "Fight@StartButton1", + "Fight@StageSNReturnFlag", + "Fight@Stop" }; + int get_exceeded_num() const; +}; +} diff --git a/src/MaaCore/Task/Fight/FightTimesTaskPlugin.cpp b/src/MaaCore/Task/Fight/FightTimesTaskPlugin.cpp index 6cedcc4878..c890fc008e 100644 --- a/src/MaaCore/Task/Fight/FightTimesTaskPlugin.cpp +++ b/src/MaaCore/Task/Fight/FightTimesTaskPlugin.cpp @@ -38,3 +38,4 @@ bool asst::FightTimesTaskPlugin::_run() inited = true; return true; } + diff --git a/src/MaaCore/Task/Interface/FightTask.cpp b/src/MaaCore/Task/Interface/FightTask.cpp index de518f7d6e..24d50614b4 100644 --- a/src/MaaCore/Task/Interface/FightTask.cpp +++ b/src/MaaCore/Task/Interface/FightTask.cpp @@ -4,6 +4,7 @@ #include "Config/TaskData.h" #include "Task/Fight/DrGrandetTaskPlugin.h" +#include "Task/Fight/FightSeriesAdjustPlugin.h" #include "Task/Fight/FightTimesTaskPlugin.h" #include "Task/Fight/MedicineCounterTaskPlugin.h" #include "Task/Fight/SanityBeforeStageTaskPlugin.h" @@ -54,6 +55,8 @@ asst::FightTask::FightTask(const AsstCallback& callback, Assistant* inst) : m_fight_times_task_plugin_prt = m_fight_task_ptr->register_plugin(); m_fight_times_task_plugin_prt->set_retry_times(3); m_medicine_plugin = m_fight_task_ptr->register_plugin(); + m_fight_series_adjust_plugin_ptr = m_fight_task_ptr->register_plugin(); + m_fight_series_adjust_plugin_ptr->set_retry_times(3); m_subtasks.emplace_back(m_start_up_task_ptr); m_subtasks.emplace_back(m_stage_navigation_task_ptr); @@ -70,11 +73,23 @@ bool asst::FightTask::set_params(const json::value& params) const int expiring_medicine = params.get("expiring_medicine", 0); const int stone = params.get("stone", 0); const int times = params.get("times", INT_MAX); - const int series = params.get("series", 1); - if (series < 1 || series > 6) { + int series = params.get("series", 1); + + // 重置插件状态 1000 表示自动连战,-1 表示禁用连战切换 + m_fight_times_task_plugin_prt->set_enable(series != -1); + m_fight_series_adjust_plugin_ptr->set_close_stone_page_next(false); + m_fight_series_adjust_plugin_ptr->set_enable(series == 1000); + if (series == 1000) { + series = 6; + } + else if (series == -1) { + series = 1; + } + else if (series < 1 || series > 6) { Log.error("Invalid series"); return false; } + bool enable_penguin = params.get("report_to_penguin", false); bool enable_yituliu = params.get("report_to_yituliu", false); std::string penguin_id = params.get("penguin_id", ""); diff --git a/src/MaaCore/Task/Interface/FightTask.h b/src/MaaCore/Task/Interface/FightTask.h index 6b0848c4cd..9372c64c02 100644 --- a/src/MaaCore/Task/Interface/FightTask.h +++ b/src/MaaCore/Task/Interface/FightTask.h @@ -12,6 +12,7 @@ class StageNavigationTask; class DrGrandetTaskPlugin; class SideStoryReopenTask; class MedicineCounterTaskPlugin; +class FightSeriesAdjustPlugin; class FightTask final : public InterfaceTask { @@ -28,6 +29,7 @@ protected: std::shared_ptr m_stage_navigation_task_ptr = nullptr; std::shared_ptr m_fight_task_ptr = nullptr; std::shared_ptr m_fight_times_task_plugin_prt = nullptr; + std::shared_ptr m_fight_series_adjust_plugin_ptr = nullptr; std::shared_ptr m_medicine_plugin = nullptr; std::shared_ptr m_stage_drops_plugin_ptr = nullptr; std::shared_ptr m_dr_grandet_task_plugin_ptr = nullptr; diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs index 359a8e2807..ba7fcce20f 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs @@ -103,10 +103,17 @@ public class FightSettingsUserControlModel : TaskViewModel { "炭", "SK-5" }, }; - /// - /// Gets or private sets the list of series. - /// - public List SeriesList { get; private set; } = Enumerable.Range(1, 6).ToList(); + public Dictionary SeriesList { get; } = new() + { + { "AUTO", 1000 }, + { "6", 6 }, + { "5", 5 }, + { "4", 4 }, + { "3", 6 }, + { "2", 2 }, + { "1", 1 }, + { LocalizationHelper.GetString("NotSelected"), -1 }, + }; public string?[] Stages => [Stage1, Stage2, Stage3]; @@ -465,7 +472,7 @@ public class FightSettingsUserControlModel : TaskViewModel } } - private int _series = ConfigurationHelper.GetValue(ConfigurationKeys.SeriesQuantity, 1); + private int _series = ConfigurationHelper.GetValue(ConfigurationKeys.SeriesQuantity, 1000); /// /// Gets or sets the max number of times. diff --git a/src/MaaWpfGui/Views/UserControl/TaskQueue/FightSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/TaskQueue/FightSettingsUserControl.xaml index b84e8637c9..0970cca5f6 100644 --- a/src/MaaWpfGui/Views/UserControl/TaskQueue/FightSettingsUserControl.xaml +++ b/src/MaaWpfGui/Views/UserControl/TaskQueue/FightSettingsUserControl.xaml @@ -170,7 +170,9 @@ IsHitTestVisible="{c:Binding !FightTaskRunning, Source={x:Static helper:Instances.TaskQueueViewModel}}" ItemsSource="{Binding SeriesList}" - SelectedValue="{Binding Series}" /> + SelectedValue="{Binding Series}" + DisplayMemberPath="Key" + SelectedValuePath="Value" />