perf: 优化肉鸽投资操作速度

This commit is contained in:
status102
2024-02-03 10:12:36 +08:00
parent 0e98780abf
commit 2a9bbe6831
14 changed files with 220 additions and 5 deletions

View File

@@ -12727,24 +12727,62 @@
]
},
"Roguelike@StageTraderInvestConfirm": {
"action": "ClickSelf",
"doc": "绑定 RoguelikeInvestTaskPlugin 插件进行投资,本任务仅作为进入投资系统时的初始化确认",
"roi": [
852,
422,
278,
144
],
"postDelay": 500,
"exceededNext": [
"RoguelikeControlTaskPlugin-ExitThenStop"
],
"next": [
"Roguelike@StageTraderInvestSystemError",
"Roguelike@StageTraderInvestSystemFull",
"Roguelike@StageTraderInvestConfirm",
"Roguelike@StageTraderInvestCancel"
]
},
"Roguelike@StageTraderInvest-Arrow": {
"doc": "商店投资界面的箭头99 >> 100",
"roi": [
750,
320,
100,
100
]
},
"Roguelike@StageTraderInvest-Confirm": {
"algorithm": "JustReturn",
"action": "ClickRect",
"specificRect": [
850,
470,
300,
45
]
},
"Roguelike@StageTraderInvest-Count": {
"doc": "商店投资界面的余额显示99 >> 100",
"algorithm": "OcrDetect",
"isAscii": true,
"roi": [
570,
335,
150,
60
]
},
"Roguelike@StageTraderInvest-Count-Error": {
"doc": "商店投资界面系统出错时余额显示",
"algorithm": "OcrDetect",
"isAscii": true,
"roi": [
635,
205,
70,
40
]
},
"Roguelike@StageTraderInvestSystem": {
"templThreshold": 0.75,
"action": "ClickSelf",

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -96,6 +96,7 @@
<ClInclude Include="Task\Roguelike\RoguelikeFoldartalUseTaskPlugin.h" />
<ClInclude Include="Task\Roguelike\RoguelikeConfig.h" />
<ClInclude Include="Task\Roguelike\RoguelikeDifficultySelectionTaskPlugin.h" />
<ClInclude Include="Task\Roguelike\RoguelikeInvestTaskPlugin.h" />
<ClInclude Include="Task\Roguelike\RoguelikeLastRewardTaskPlugin.h" />
<ClInclude Include="Task\Roguelike\RoguelikeSettlementTaskPlugin.h" />
<ClInclude Include="Task\Roguelike\RoguelikeStrategyChangeTaskPlugin.h" />
@@ -273,6 +274,7 @@
<ClCompile Include="Task\Roguelike\RoguelikeFoldartalUseTaskPlugin.cpp" />
<ClCompile Include="Task\Roguelike\RoguelikeConfig.cpp" />
<ClCompile Include="Task\Roguelike\RoguelikeDifficultySelectionTaskPlugin.cpp" />
<ClCompile Include="Task\Roguelike\RoguelikeInvestTaskPlugin.cpp" />
<ClCompile Include="Task\Roguelike\RoguelikeLastRewardTaskPlugin.cpp" />
<ClCompile Include="Task\Roguelike\RoguelikeSettlementTaskPlugin.cpp" />
<ClCompile Include="Task\Roguelike\RoguelikeStrategyChangeTaskPlugin.cpp" />

View File

@@ -693,6 +693,9 @@
<ClInclude Include="Config\TaskData\TaskDataTypes.h">
<Filter>Source\Resource\TaskData</Filter>
</ClInclude>
<ClInclude Include="Task\Roguelike\RoguelikeInvestTaskPlugin.h">
<Filter>Source\Task\Roguelike</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Vision\VisionHelper.cpp">
@@ -1154,5 +1157,8 @@
<ClCompile Include="Task\Infrast\InfrastTrainingTask.cpp">
<Filter>Source\Task\Infrast</Filter>
</ClCompile>
<ClCompile Include="Task\Roguelike\RoguelikeInvestTaskPlugin.cpp">
<Filter>Source\Task\Roguelike</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -22,6 +22,7 @@
#include "Task/Roguelike/RoguelikeSkillSelectionTaskPlugin.h"
#include "Task/Roguelike/RoguelikeStageEncounterTaskPlugin.h"
#include "Task/Roguelike/RoguelikeStrategyChangeTaskPlugin.h"
#include "Task/Roguelike/RoguelikeInvestTaskPlugin.h"
#include "Utils/Logger.hpp"
@@ -40,6 +41,7 @@ asst::RoguelikeTask::RoguelikeTask(const AsstCallback& callback, Assistant* inst
m_roguelike_task_ptr->register_plugin<RoguelikeSettlementTaskPlugin>(m_roguelike_config_ptr);
m_debug_plugin_ptr = m_roguelike_task_ptr->register_plugin<RoguelikeDebugTaskPlugin>(m_roguelike_config_ptr);
m_roguelike_task_ptr->register_plugin<RoguelikeShoppingTaskPlugin>(m_roguelike_config_ptr)->set_retry_times(0);
m_roguelike_task_ptr->register_plugin<RoguelikeInvestTaskPlugin>(m_roguelike_config_ptr);
m_custom_start_plugin_ptr =
m_roguelike_task_ptr->register_plugin<RoguelikeCustomStartTaskPlugin>(m_roguelike_config_ptr);
@@ -96,6 +98,8 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
// 是否凹指定干员开局直升
m_roguelike_config_ptr->set_start_with_elite_two(params.get("start_with_elite_two", false));
m_roguelike_config_ptr->set_only_start_with_elite_two(params.get("only_start_with_elite_two", false));
m_roguelike_config_ptr->set_invest_maximum(params.get("investments_count", INT_MAX));
m_roguelike_config_ptr->set_invest_stop_when_full(params.get("stop_when_investment_full", false));
// 设置层数选点策略,相关逻辑在 RoguelikeStrategyChangeTaskPlugin
{
@@ -144,7 +148,6 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
params.get("investment_enabled", true) ? INT_MAX : 0);
m_roguelike_task_ptr->set_times_limit("StageTraderRefreshWithDice",
params.get("refresh_trader_with_dice", false) ? INT_MAX : 0);
m_roguelike_task_ptr->set_times_limit("StageTraderInvestConfirm", params.get("investments_count", INT_MAX));
if (params.get("stop_when_investment_full", false)) {
constexpr int InvestLimit = 999;

View File

@@ -55,6 +55,10 @@ namespace asst
bool get_start_with_elite_two() const { return m_start_with_elite_two; }
void set_only_start_with_elite_two(bool value) { m_only_start_with_elite_two = value; }
bool get_only_start_with_elite_two() const { return m_only_start_with_elite_two; }
void set_invest_maximum(int value) { m_invest_maximum = value; }
int get_invest_maximum() const { return m_invest_maximum; }
void set_invest_stop_when_full(bool value) { m_invest_stop_when_full = value; }
bool get_invest_stop_when_full() const { return m_invest_stop_when_full; }
private:
std::string m_theme; // 主题
@@ -62,6 +66,8 @@ namespace asst
int m_difficulty = 0; // 难度
bool m_start_with_elite_two = false; // 在刷开局模式下凹开局干员精二直升
bool m_only_start_with_elite_two = false; // 只凹开局干员精二直升且不进行作战
int m_invest_maximum = 0; // 投资次数上限
bool m_invest_stop_when_full = false; // 存款满了就停止
/* 以下为每次重置 */
public:

View File

@@ -0,0 +1,129 @@
#include "RoguelikeInvestTaskPlugin.h"
#include "Config/TaskData.h"
#include "Controller/Controller.h"
#include "Task/ProcessTask.h"
#include "Utils/Logger.hpp"
#include "Vision/RegionOCRer.h"
bool asst::RoguelikeInvestTaskPlugin::verify(AsstMsg msg, const json::value& details) const
{
if (msg != AsstMsg::SubTaskStart || details.get("subtask", std::string()) != "ProcessTask") {
return false;
}
const auto task_name = details.get("details", "task", "");
if (task_name.ends_with("Roguelike@StageTraderInvestConfirm")) {
return m_invest_count < m_config->get_invest_maximum();
}
else {
return false;
}
}
bool asst::RoguelikeInvestTaskPlugin::_run()
{
LogTraceFunction;
auto image = ctrler()->get_image();
// 进入投资页面成功
// 999 >> 1000
// 取消 | 确认投资
int count = 0; // 当次已投资的个数
int retry = 0; // 重试次数
const auto ocr_current_count = [](const auto& img, const auto& task_name) -> std::optional<int> {
RegionOCRer ocr(img);
ocr.set_task_info(task_name);
if (!ocr.analyze()) {
Log.error(__FUNCTION__, "unable to analyze current investment count.");
return std::nullopt;
};
int count = 0;
if (!utils::chars_to_number(ocr.get_result().text, count)) {
Log.error(__FUNCTION__, "unable to convert current investment count<", ocr.get_result().text,
"> to number.");
return std::nullopt;
}
return count;
};
// 当前的存款
auto deposit = ocr_current_count(image, "Roguelike@StageTraderInvest-Count");
// 可用投资次数
int count_limit = m_config->get_invest_maximum() - m_invest_count;
// 投资确认按钮
const auto& click_rect = Task.get("Roguelike@StageTraderInvest-Confirm")->specific_rect;
Log.info(__FUNCTION__, "开始投资, 存款", deposit.value_or(-1), ", 可投资次数", count_limit);
while (!need_exit() && deposit && *deposit < 999 && count_limit > 0 && retry < 3) {
int times = std::min(15, count_limit - count);
while (!need_exit() && times > 0) {
ctrler()->click(click_rect);
sleep(100);
times--;
}
image = ctrler()->get_image();
if (!is_investment_available(image)) { // 检查是否处于可投资状态
break; // 投资系统错误 / 没钱了
}
else if (auto ocr = ocr_current_count(image, "Roguelike@StageTraderInvest-Count"); ocr) {
// 可继续投资 / 到达投资上限999
if (*ocr == *deposit || *ocr > 999 || *ocr < 1) {
retry++; // 可能是出错了,重试三次放弃
}
else {
count += *ocr - *deposit;
deposit = *ocr;
retry = 0;
}
}
else {
Log.error(__FUNCTION__, "未知状态");
return true;
}
}
if (auto ocr = ocr_current_count(ctrler()->get_image(), "Roguelike@StageTrader-InvestCount"); ocr) {
// 可继续投资 / 到达投资上限999
count += *ocr - deposit.value_or(0);
deposit = *ocr;
}
const auto total = count + m_invest_count;
auto info = basic_info_with_what("RoguelikeInvestment");
info["details"]["count"] = count;
info["details"]["total"] = total;
info["details"]["deposit"] = deposit ? *deposit : -1;
callback(AsstMsg::SubTaskExtraInfo, info);
Log.info(__FUNCTION__, "本轮投资结束, 投资", count, ", 共投资", total, "; 系统余额", deposit ? *deposit : -1);
m_invest_count = total;
if (count_limit - count <= 0) {
Log.info(__FUNCTION__, "投资达到设置上限,", m_config->get_invest_maximum());
stop_roguelike();
m_task_ptr->set_enable(false);
return true;
}
if (deposit.value_or(0) == 999 && m_config->get_invest_stop_when_full()) {
Log.info(__FUNCTION__, "存款已满");
stop_roguelike();
m_task_ptr->set_enable(false);
}
return true;
}
bool asst::RoguelikeInvestTaskPlugin::is_investment_available(const cv::Mat& image) const
{
auto task = ProcessTask(*this, { "Roguelike@StageTraderInvest-Arrow", "Roguelike@StageTraderInvestSystemError" });
task.set_reusable_image(image).set_retry_times(3);
task.set_times_limit("Roguelike@StageTraderInvestCancel", 0);
return task.run() && task.get_last_task_name() == "Roguelike@StageTraderInvest-Arrow";
}
void asst::RoguelikeInvestTaskPlugin::stop_roguelike()
{
dynamic_cast<ProcessTask*>(m_task_ptr)->set_times_limit("Roguelike@StageTraderInvestConfirm", 0);
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "AbstractRoguelikeTaskPlugin.h"
namespace asst
{
// 肉鸽投资插件
class RoguelikeInvestTaskPlugin : public AbstractRoguelikeTaskPlugin
{
public:
using AbstractRoguelikeTaskPlugin::AbstractRoguelikeTaskPlugin;
virtual ~RoguelikeInvestTaskPlugin() override = default;
virtual bool verify(AsstMsg msg, const json::value& details) const override;
private:
virtual bool _run() override;
bool is_investment_available(const cv::Mat& image) const;
void stop_roguelike();
int m_invest_count = 0;
};
} // namespace asst

View File

@@ -1175,6 +1175,11 @@ namespace MaaWpfGui.Main
break;
}
case "RoguelikeInvestment":
Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeInvestment"), subTaskDetails["count"], subTaskDetails["total"], subTaskDetails["deposit"]), UiLogColor.Info);
break;
case "RoguelikeSettlement":
// 肉鸽结算
bool roguelikeGamePass = (bool)subTaskDetails["game_pass"];

View File

@@ -634,6 +634,7 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla
<system:String x:Key="EmergencyDps">Node: Emergency Operation</system:String>
<system:String x:Key="DreadfulFoe">Node: Dreadful Foe</system:String>
<system:String x:Key="RoguelikeEvent">Event:</system:String>
<system:String x:Key="RoguelikeInvestment">Invested {1}(+{0}), deposit: {2}</system:String>
<system:String x:Key="RoguelikeSettlement">Roguelike Settlement: {0}\nExplore: {1} Floor {2} Step\nCombat: {3} / {4} Emergency / {5} BOSS\nRecruit: {6}\nCollectibles: {7}\nDifficulty: {8}\nScore: {9}\nExp: {10}, Skill: {11}</system:String>
<system:String x:Key="CurTimes">Current times</system:String>
<system:String x:Key="NoDrop">Nothing</system:String>

View File

@@ -634,6 +634,7 @@ Bilibili: ログイン インターフェイスに表示されるアカウント
<system:String x:Key="EmergencyDps">ステージ: 緊急作戦</system:String>
<system:String x:Key="DreadfulFoe">ステージ: 悪路凶敵</system:String>
<system:String x:Key="RoguelikeEvent">イベント:</system:String>
<system:String x:Key="RoguelikeInvestment">投資済み: {1}(+{0})、デポジット: {2}</system:String>
<system:String x:Key="RoguelikeSettlement">ローグライク決済: {0}\n探検する: {1} 床 {2} ステップ\n戦闘: {3} / {4} 緊急 / {5} BOSS\nリクルート: {6}\nコレクション: {7}\n困難: {8}\nスコア: {9}\n経験値: {10}, スキル: {11}</system:String>
<system:String x:Key="CurTimes">現在の回数</system:String>
<system:String x:Key="NoDrop">ドロップなし</system:String>

View File

@@ -634,6 +634,7 @@ Bilibili: 로그인 인터페이스에 표시되는 계정 이름(예: 장산)
<system:String x:Key="EmergencyDps">레벨: 긴급 작전</system:String>
<system:String x:Key="DreadfulFoe">레벨: 험난한 길</system:String>
<system:String x:Key="RoguelikeEvent">이벤트:</system:String>
<system:String x:Key="RoguelikeInvestment">투자: {1}(+{0}), 예금: {2}</system:String>
<system:String x:Key="RoguelikeSettlement">로그라이크 종착점: {0}\n클리어 : {1} 구역 {2} 노드\n전투 횟수: {3} 일반 / {4} 정예 / {5} 리더\n모집 횟수 : {6} 회\n수집: {7}\n난이도: {8}\n점수: {9}\n경험치: {10}, 스킬: {11}</system:String>
<system:String x:Key="CurTimes">현재 횟수</system:String>
<system:String x:Key="NoDrop">없음</system:String>

View File

@@ -634,6 +634,7 @@
<system:String x:Key="EmergencyDps">关卡: 紧急作战</system:String>
<system:String x:Key="DreadfulFoe">关卡: 险路恶敌</system:String>
<system:String x:Key="RoguelikeEvent">事件:</system:String>
<system:String x:Key="RoguelikeInvestment">已投资 {1}(+{0}), 存款: {2}</system:String>
<system:String x:Key="RoguelikeSettlement">肉鸽结算: {0}\n探索: {1} 层 {2} 步\n战斗: {3}/{4} 紧急/{5} BOSS\n招募: {6} 收藏品: {7}\n难度: {8} 得分: {9}\nExp: {10} Skill: {11}</system:String>
<system:String x:Key="CurTimes">当前次数</system:String>
<system:String x:Key="NoDrop">无</system:String>

View File

@@ -632,6 +632,7 @@
<system:String x:Key="EmergencyDps">關卡: 緊急作戰</system:String>
<system:String x:Key="DreadfulFoe">關卡: 險路惡敵</system:String>
<system:String x:Key="RoguelikeEvent">事件:</system:String>
<system:String x:Key="RoguelikeInvestment">已投資 {1}(+{0}), 存款: {2}</system:String>
<system:String x:Key="RoguelikeSettlement">肉鴿結算: {0}\n探索: {1} 层 {2} 步\n戰鬥: {3}/{4} 緊急/{5} BOSS\n招募: {6} 收藏品: {7}\n難度: {8} 得分: {9}\nExp: {10} Skill: {11}</system:String>
<system:String x:Key="CurTimes">目前次數</system:String>
<system:String x:Key="NoDrop">無</system:String>