Reapply "feat:实现自适应调整连战次数 (#12555)"

This reverts commit 7359653317.

移除不相关的文件修改

---------

Co-authored-by: uye <99072975+ABA2396@users.noreply.github.com>
This commit is contained in:
Yoake
2025-05-06 16:56:37 +08:00
committed by status102
parent 7359653317
commit 979f6699cc
11 changed files with 184 additions and 8 deletions

View File

@@ -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.5next 在 FightSeriesAdjustPlugin 插件中被动态修改",
"algorithm": "JustReturn",
"action": "ClickRect",
"specificRect": [0, 200, 300, 400],

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

View File

@@ -248,6 +248,7 @@
<ClInclude Include="LDExtras.h" />
<ClInclude Include="Task\Experiment\CombatRecordRecognitionTask.h" />
<ClInclude Include="Task\Experiment\SingleStepBattleProcessTask.h" />
<ClInclude Include="Task\Fight\FightSeriesAdjustPlugin.h" />
<ClInclude Include="Task\Fight\FightTimesTaskPlugin.h" />
<ClInclude Include="Task\Fight\MedicineCounterTaskPlugin.h" />
<ClInclude Include="Task\Fight\SanityBeforeStageTaskPlugin.h" />
@@ -446,6 +447,7 @@
<ClCompile Include="LDExtras.cpp" />
<ClCompile Include="Task\Experiment\CombatRecordRecognitionTask.cpp" />
<ClCompile Include="Task\Experiment\SingleStepBattleProcessTask.cpp" />
<ClCompile Include="Task\Fight\FightSeriesAdjustPlugin.cpp" />
<ClCompile Include="Task\Fight\FightTimesTaskPlugin.cpp" />
<ClCompile Include="Task\Fight\MedicineCounterTaskPlugin.cpp" />
<ClCompile Include="Task\Fight\SanityBeforeStageTaskPlugin.cpp" />

View File

@@ -1328,6 +1328,9 @@
<ClInclude Include="Task\Roguelike\RoguelikeInputSeedTaskPlugin.h">
<Filter>Source\Task\Roguelike</Filter>
</ClInclude>
<ClInclude Include="Task\Fight\FightSeriesAdjustPlugin.h">
<Filter>Source\Task\Fight</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Vision\VisionHelper.cpp">
@@ -1842,6 +1845,9 @@
<ClCompile Include="Task\Roguelike\RoguelikeInputSeedTaskPlugin.cpp">
<Filter>Source\Task\Roguelike</Filter>
</ClCompile>
<ClCompile Include="Task\Fight\FightSeriesAdjustPlugin.cpp">
<Filter>Source\Task\Fight</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Natvis Include="meojson.natvis" />

View File

@@ -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<std::pair<int, int>> 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<int> 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<int>(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;
}

View File

@@ -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<std::string> original_close_stone_page_next = { "Fight@StageSNReturnFlag", "Fight@Stop" };
std::vector<std::string> modified_close_stone_page_next = { "Fight@StartButton1",
"Fight@StageSNReturnFlag",
"Fight@Stop" };
int get_exceeded_num() const;
};
}

View File

@@ -38,3 +38,4 @@ bool asst::FightTimesTaskPlugin::_run()
inited = true;
return true;
}

View File

@@ -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<FightTimesTaskPlugin>();
m_fight_times_task_plugin_prt->set_retry_times(3);
m_medicine_plugin = m_fight_task_ptr->register_plugin<MedicineCounterTaskPlugin>();
m_fight_series_adjust_plugin_ptr = m_fight_task_ptr->register_plugin<FightSeriesAdjustPlugin>();
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", "");

View File

@@ -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<StageNavigationTask> m_stage_navigation_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_fight_task_ptr = nullptr;
std::shared_ptr<FightTimesTaskPlugin> m_fight_times_task_plugin_prt = nullptr;
std::shared_ptr<FightSeriesAdjustPlugin> m_fight_series_adjust_plugin_ptr = nullptr;
std::shared_ptr<MedicineCounterTaskPlugin> m_medicine_plugin = nullptr;
std::shared_ptr<StageDropsTaskPlugin> m_stage_drops_plugin_ptr = nullptr;
std::shared_ptr<DrGrandetTaskPlugin> m_dr_grandet_task_plugin_ptr = nullptr;

View File

@@ -103,10 +103,17 @@ public class FightSettingsUserControlModel : TaskViewModel
{ "炭", "SK-5" },
};
/// <summary>
/// Gets or private sets the list of series.
/// </summary>
public List<int> SeriesList { get; private set; } = Enumerable.Range(1, 6).ToList();
public Dictionary<string, int> 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);
/// <summary>
/// Gets or sets the max number of times.

View File

@@ -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" />
</StackPanel>
</Grid>
<Grid Grid.Row="3">