mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-07 05:10:30 +08:00
Compare commits
3 Commits
feat/OperD
...
feat/Copil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a30f9a7dd | ||
|
|
61345d8126 | ||
|
|
07e01367e7 |
@@ -3685,11 +3685,13 @@
|
||||
"next": ["EndOfPlot"]
|
||||
},
|
||||
"BattleAvatarDialog": {
|
||||
"doc": "战斗中带头像对话框, 类似于 SkipThePreBattlePlot(可见于画中人关卡) 的, 但是缺少 跳过 按钮",
|
||||
"doc": "战斗中带头像对话框, 类似于 SkipThePreBattlePlot(可见于画中人关卡, 17章主线TR28) 的, 但是缺少 跳过 按钮",
|
||||
"action": "ClickSelf",
|
||||
"roi": [70, 30, 120, 30],
|
||||
"maxTimes": 5,
|
||||
"next": ["BattleAvatarDialog", "Stop"],
|
||||
"rectMove": [125, 20, 200, 60]
|
||||
"rectMove": [125, 20, 200, 60],
|
||||
"specialParams": [98]
|
||||
},
|
||||
"EndOfPlot": {
|
||||
"roi": [520, 0, 243, 206],
|
||||
@@ -4384,19 +4386,6 @@
|
||||
"text": [],
|
||||
"roi": [5, 230, 37, 23]
|
||||
},
|
||||
"OperDetailElite": {
|
||||
"template": ["OperDetail-Elite2.png", "OperDetail-Elite1.png", "OperDetail-Elite0.png"],
|
||||
"roi": [860, 240, 120, 80]
|
||||
},
|
||||
"OperDetailLevel": {
|
||||
"baseTask": "NumberOcrReplace",
|
||||
"roi": [885, 115, 90, 55]
|
||||
},
|
||||
"OperDetailSkillLevel-Base": {
|
||||
"baseTask": "NumberOcrReplace",
|
||||
"doc": "4星以上才有专精",
|
||||
"roi": [1214, 355, 16, 22]
|
||||
},
|
||||
"OperParadoxBegin": {
|
||||
"algorithm": "JustReturn",
|
||||
"next": ["OperOpenInformationMenu"],
|
||||
@@ -4774,8 +4763,8 @@
|
||||
"Doc": "20260109 YJWL更新后暂停按钮向右移动约8像素, 且暂停后亮度上限245 (不知道以前是不是也有这个问题)",
|
||||
"template": "empty.png",
|
||||
"roi": [1178, 33, 53, 39],
|
||||
"specialParams_Doc": "亮度阈值;点的数量",
|
||||
"specialParams": [235, 200]
|
||||
"specialParams_Doc": "亮度阈值; 暂停时阈值; 运行时阈值",
|
||||
"specialParams": [235, 200, 450]
|
||||
},
|
||||
"BattleSpeedButton": {
|
||||
"template": "empty.png",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB |
@@ -16,8 +16,8 @@
|
||||
#include "Vision/Battle/BattlefieldClassifier.h"
|
||||
#include "Vision/Battle/BattlefieldMatcher.h"
|
||||
#include "Vision/Matcher.h"
|
||||
#include "Vision/Miscellaneous/OperNameAnalyzer.h"
|
||||
#include "Vision/MultiMatcher.h"
|
||||
#include "Vision/Oper/OperNameAnalyzer.h"
|
||||
#include "Vision/RegionOCRer.h"
|
||||
#include <ranges>
|
||||
|
||||
@@ -601,7 +601,7 @@ bool asst::BattleHelper::check_pause_button(const cv::Mat& reusable)
|
||||
|
||||
BattlefieldMatcher battle_flag_analyzer_2(image);
|
||||
auto battle_result_opt = battle_flag_analyzer_2.analyze();
|
||||
ret &= battle_result_opt && battle_result_opt->pause_button;
|
||||
ret &= battle_result_opt && battle_result_opt->pause_button != BattlefieldMatcher::PauseStatus::Unknown;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -621,14 +621,39 @@ bool asst::BattleHelper::check_skip_plot_button(const cv::Mat& reusable)
|
||||
bool asst::BattleHelper::check_avatar_dialog(const cv::Mat& reusable)
|
||||
{
|
||||
cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable;
|
||||
|
||||
const static auto& task = Task.get("BattleAvatarDialog");
|
||||
const static double threshold = task->special_params[0] / 100.0;
|
||||
Matcher battle_plot_analyzer(image);
|
||||
battle_plot_analyzer.set_task_info("BattleAvatarDialog");
|
||||
battle_plot_analyzer.set_task_info(task);
|
||||
bool ret = battle_plot_analyzer.analyze().has_value();
|
||||
if (ret) {
|
||||
ProcessTask(this_task(), { "BattleAvatarDialog" }).run();
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
return ret;
|
||||
|
||||
ProcessTask(this_task(), { "BattleAvatarDialog" }).run();
|
||||
const auto match_rect = battle_plot_analyzer.get_result().rect.move(task->rect_move);
|
||||
|
||||
cv::Mat image2 = m_inst_helper.ctrler()->get_image();
|
||||
int retry = 100;
|
||||
while (!m_inst_helper.need_exit() && retry > 0) {
|
||||
Matcher matcher(image2);
|
||||
matcher.set_templ(make_roi(image, match_rect));
|
||||
matcher.set_roi(match_rect);
|
||||
matcher.set_threshold(threshold);
|
||||
matcher.set_method(MatchMethod::Ccoeff);
|
||||
if (matcher.analyze()) {
|
||||
LogInfo << __FUNCTION__ << "still in dialog, but not detected change, maybe need deploy or skill";
|
||||
break;
|
||||
}
|
||||
--retry;
|
||||
ret = ProcessTask(this_task(), { "BattleAvatarDialog" }).run();
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
image = image2;
|
||||
image2 = m_inst_helper.ctrler()->get_image();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::BattleHelper::check_in_speedup(const cv::Mat& reusable)
|
||||
@@ -646,7 +671,7 @@ bool asst::BattleHelper::check_in_battle(const cv::Mat& reusable, bool weak)
|
||||
BattlefieldMatcher analyzer(image);
|
||||
auto result = analyzer.analyze();
|
||||
m_in_battle = result.has_value();
|
||||
if (m_in_battle && !result->pause_button) {
|
||||
if (m_in_battle && result->pause_button == BattlefieldMatcher::PauseStatus::Unknown) {
|
||||
if (check_skip_plot_button(image)) {
|
||||
if (m_in_speedup && !check_in_speedup()) {
|
||||
speed_up(); // 跳过剧情会退出2倍速
|
||||
@@ -655,13 +680,13 @@ bool asst::BattleHelper::check_in_battle(const cv::Mat& reusable, bool weak)
|
||||
else if (check_avatar_dialog(image)) {
|
||||
if (m_in_speedup && !check_in_speedup()) {
|
||||
speed_up(); // 跳过剧情会退出2倍速
|
||||
m_inst_helper.sleep(Config.get_options().task_delay);
|
||||
int times = 0;
|
||||
while (times < 20 && !m_inst_helper.need_exit() && !check_in_speedup()) {
|
||||
speed_up(); // 跳过剧情会退出2倍速
|
||||
m_inst_helper.sleep(Config.get_options().task_delay);
|
||||
times++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_in_battle && result->pause_button == BattlefieldMatcher::PauseStatus::Pausing) {
|
||||
if (check_avatar_dialog(image)) {
|
||||
if (m_in_speedup && !check_in_speedup()) {
|
||||
speed_up(); // 跳过剧情会退出2倍速
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ bool asst::CombatRecordRecognitionTask::analyze_deployment()
|
||||
|
||||
oper_analyzer.set_image(frame);
|
||||
auto oper_result_opt = oper_analyzer.analyze();
|
||||
bool analyzed = oper_result_opt && oper_result_opt->pause_button;
|
||||
bool analyzed = oper_result_opt && oper_result_opt->pause_button != BattlefieldMatcher::PauseStatus::Unknown;
|
||||
if (analyzed) {
|
||||
m_battle_start_frame = i;
|
||||
deployment = std::move(oper_result_opt->deployment);
|
||||
@@ -390,7 +390,7 @@ bool asst::CombatRecordRecognitionTask::slice_video()
|
||||
pre_distance = distance;
|
||||
}
|
||||
|
||||
bool oper_is_clicked = !result_opt->speed_button || !result_opt->pause_button;
|
||||
bool oper_is_clicked = !result_opt->speed_button || result_opt->pause_button == BattlefieldMatcher::PauseStatus::Unknown;
|
||||
bool oper_auto_retreat =
|
||||
in_segment && continuity && !m_clips.empty() && cur_opers.size() != m_clips.back().deployment.size();
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include "Task/ProcessTask.h"
|
||||
#include "Utils/Logger.hpp"
|
||||
#include "Vision/Matcher.h"
|
||||
#include "Vision/Miscellaneous/OperNameAnalyzer.h"
|
||||
#include "Vision/Miscellaneous/PipelineAnalyzer.h"
|
||||
#include "Vision/MultiMatcher.h"
|
||||
#include "Vision/Oper/OperNameAnalyzer.h"
|
||||
#include "Vision/RegionOCRer.h"
|
||||
|
||||
asst::BattleFormationTask::BattleFormationTask(
|
||||
|
||||
@@ -462,6 +462,9 @@ bool asst::BattleProcessTask::wait_condition(const Action& action)
|
||||
const std::string& name = get_name_from_group(action.name);
|
||||
update_image_if_empty();
|
||||
while (!need_exit()) {
|
||||
if (!check_in_battle(image)) {
|
||||
return false;
|
||||
}
|
||||
if (!update_deployment(false, image)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "Controller/Controller.h"
|
||||
#include "Task/ProcessTask.h"
|
||||
#include "Utils/Logger.hpp"
|
||||
#include "Vision/Oper/OperBoxImageAnalyzer.h"
|
||||
#include "Vision/Miscellaneous/OperBoxImageAnalyzer.h"
|
||||
#include "Vision/TemplDetOCRer.h"
|
||||
|
||||
bool asst::OperBoxRecognitionTask::_run()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "Common/AsstBattleDef.h"
|
||||
#include "Task/AbstractTask.h"
|
||||
#include "Vision/Oper/OperBoxImageAnalyzer.h"
|
||||
#include "Vision/Miscellaneous/OperBoxImageAnalyzer.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "Task/AbstractTask.h"
|
||||
|
||||
#include "Common/AsstBattleDef.h"
|
||||
#include "Vision/Oper/OperBoxImageAnalyzer.h"
|
||||
#include "Vision/Miscellaneous/OperBoxImageAnalyzer.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
#include "OperDetailPage.h"
|
||||
|
||||
#include "Config/TaskData.h"
|
||||
#include "Controller/Controller.h"
|
||||
#include "MaaUtils/NoWarningCV.hpp"
|
||||
#include "Task/ProcessTask.h"
|
||||
#include "Utils/DebugImageHelper.hpp"
|
||||
#include "Utils/Logger.hpp"
|
||||
#include "Vision/Matcher.h"
|
||||
#include "Vision/MultiMatcher.h"
|
||||
#include "Vision/RegionOCRer.h"
|
||||
|
||||
asst::OperDetailPage::OperDetailPage(
|
||||
const AsstCallback& callback,
|
||||
Assistant* inst,
|
||||
std::string_view task_chain) :
|
||||
InstHelper(inst),
|
||||
m_callback(callback),
|
||||
m_task_chain(task_chain)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<int> asst::OperDetailPage::analyze_elite(const cv::Mat& image)
|
||||
{
|
||||
const static auto& elite_task = Task.get("OperDetailElite");
|
||||
Matcher matcher(image);
|
||||
matcher.set_task_info(elite_task);
|
||||
if (!matcher.analyze()) {
|
||||
LogError << __FUNCTION__ << "analyze elite failed";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int elite = 0;
|
||||
auto length = matcher.get_result().templ_name.size();
|
||||
auto elite_str = matcher.get_result().templ_name.substr(length - 1);
|
||||
|
||||
if (elite_str.empty() || !utils::chars_to_number(elite_str, elite)) {
|
||||
LogError << __FUNCTION__ << "convert elite failed, template:" << matcher.get_result().templ_name
|
||||
<< ", str:" << elite_str;
|
||||
return std::nullopt;
|
||||
}
|
||||
return elite;
|
||||
}
|
||||
|
||||
std::optional<int> asst::OperDetailPage::analyze_level(const cv::Mat& image)
|
||||
{
|
||||
const static auto& level_task = Task.get("OperDetailLevel");
|
||||
RegionOCRer ocrer(image);
|
||||
ocrer.set_task_info(level_task);
|
||||
if (!ocrer.analyze()) {
|
||||
LogError << __FUNCTION__ << "ocr oper level failed, str:" << ocrer.get_result().text;
|
||||
return std::nullopt;
|
||||
}
|
||||
int level = 0;
|
||||
if (!utils::chars_to_number(ocrer.get_result().text, level)) {
|
||||
LogError << __FUNCTION__ << "convert oper level failed, str:" << ocrer.get_result().text;
|
||||
return std::nullopt;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
std::optional<int> asst::OperDetailPage::analyze_skill_level(const cv::Mat& image)
|
||||
{
|
||||
const static auto& level_base = Task.get("OperDetailSkillLevel-Base");
|
||||
RegionOCRer ocrer(image);
|
||||
ocrer.set_task_info(level_base);
|
||||
if (!ocrer.analyze()) {
|
||||
LogError << __FUNCTION__ << "ocr skill level base failed, str:" << ocrer.get_result().text;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int base_level = 0;
|
||||
if (!utils::chars_to_number(ocrer.get_result().text, base_level)) {
|
||||
LogError << __FUNCTION__ << "convert skill level base failed, str:" << ocrer.get_result().text;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return base_level;
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "Common/AsstMsg.h"
|
||||
#include "Common/AsstTypes.h"
|
||||
#include "InstHelper.h"
|
||||
#include "MaaUtils/NoWarningCV.hpp"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class OperDetailPage : private InstHelper
|
||||
{
|
||||
public:
|
||||
struct SkillResult
|
||||
{
|
||||
Rect rect;
|
||||
int level = -1;
|
||||
};
|
||||
|
||||
public:
|
||||
OperDetailPage(const AsstCallback& callback, Assistant* inst, std::string_view task_chain);
|
||||
virtual ~OperDetailPage() = default;
|
||||
|
||||
private:
|
||||
// 用于创建 ProcessTask
|
||||
AsstCallback m_callback = nullptr;
|
||||
std::string_view m_task_chain;
|
||||
|
||||
public:
|
||||
std::optional<int> analyze_elite(const cv::Mat& image);
|
||||
std::optional<int> analyze_level(const cv::Mat& image);
|
||||
std::optional<int> analyze_skill_level(const cv::Mat& image);
|
||||
};
|
||||
} // namespace asst
|
||||
@@ -37,7 +37,7 @@ BattlefieldMatcher::ResultOpt BattlefieldMatcher::analyze() const
|
||||
|
||||
if (m_object_of_interest.flag) {
|
||||
result.pause_button = pause_button_analyze();
|
||||
if (!result.pause_button && !hp_flag_analyze() && !kills_flag_analyze() && !cost_symbol_analyze()) {
|
||||
if (result.pause_button == PauseStatus::Unknown && !hp_flag_analyze() && !kills_flag_analyze() && !cost_symbol_analyze()) {
|
||||
// flag 表明当前画面是在战斗场景的,不在的就没必要识别了
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -440,7 +440,7 @@ bool asst::BattlefieldMatcher::hit_costs_cache() const
|
||||
return mark > threshold;
|
||||
}
|
||||
|
||||
bool BattlefieldMatcher::pause_button_analyze() const
|
||||
asst::BattlefieldMatcher::PauseStatus BattlefieldMatcher::pause_button_analyze() const
|
||||
{
|
||||
auto task_ptr = Task.get("BattleHasStarted");
|
||||
cv::Mat roi = m_image(make_rect<cv::Rect>(task_ptr->roi));
|
||||
@@ -450,14 +450,22 @@ bool BattlefieldMatcher::pause_button_analyze() const
|
||||
const int value_threshold = task_ptr->special_params[0];
|
||||
cv::threshold(roi_gray, bin, value_threshold, 255, cv::THRESH_BINARY);
|
||||
int count = cv::countNonZero(bin);
|
||||
const int count_threshold = task_ptr->special_params[1];
|
||||
Log.trace(__FUNCTION__, "count", count, "threshold", count_threshold);
|
||||
const int threshold_base = task_ptr->special_params[1];
|
||||
const int threshold_high = task_ptr->special_params[2];
|
||||
Log.trace(__FUNCTION__, "count", count, "threshold", threshold_base, ",", threshold_high);
|
||||
|
||||
PauseStatus status = PauseStatus::Unknown;
|
||||
if (count >= threshold_high) {
|
||||
status = PauseStatus::Running;
|
||||
}
|
||||
else if (count >= threshold_base) {
|
||||
status = PauseStatus::Pausing;
|
||||
}
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw, make_rect<cv::Rect>(task_ptr->roi), cv::Scalar(0, 0, 255), 2);
|
||||
cv::putText(
|
||||
m_image_draw,
|
||||
std::to_string(count) + "/" + std::to_string(count_threshold),
|
||||
std::to_string(count) + "/" + std::to_string(threshold_base) + "," + std::to_string(threshold_high),
|
||||
cv::Point(task_ptr->roi.x, task_ptr->roi.y + task_ptr->roi.height + 10),
|
||||
cv::FONT_HERSHEY_PLAIN,
|
||||
1.2,
|
||||
@@ -465,7 +473,7 @@ bool BattlefieldMatcher::pause_button_analyze() const
|
||||
2);
|
||||
#endif
|
||||
|
||||
return count > count_threshold;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool BattlefieldMatcher::in_detail_analyze() const
|
||||
|
||||
@@ -26,6 +26,13 @@ public:
|
||||
HitCache = 2, // 图像命中缓存, 不进行识别
|
||||
};
|
||||
|
||||
enum PauseStatus
|
||||
{
|
||||
Unknown = 0, // 没有找到暂停按钮
|
||||
Pausing = 1, // 暂停中
|
||||
Running = 2, // 运行中
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MatchResult
|
||||
{
|
||||
@@ -42,7 +49,7 @@ public:
|
||||
|
||||
// bool in_detail = false;
|
||||
bool speed_button = false;
|
||||
bool pause_button = false;
|
||||
asst::BattlefieldMatcher::PauseStatus pause_button = PauseStatus::Unknown;
|
||||
};
|
||||
|
||||
using ResultOpt = std::optional<Result>;
|
||||
@@ -59,7 +66,7 @@ public:
|
||||
protected:
|
||||
bool hp_flag_analyze() const;
|
||||
bool kills_flag_analyze() const;
|
||||
bool pause_button_analyze() const;
|
||||
asst::BattlefieldMatcher::PauseStatus pause_button_analyze() const;
|
||||
|
||||
std::vector<battle::DeploymentOper> deployment_analyze() const; // 识别干员
|
||||
battle::Role oper_role_analyze(const Rect& roi) const;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include "Utils/Logger.hpp"
|
||||
#include "Vision/BestMatcher.h"
|
||||
#include "Vision/Matcher.h"
|
||||
#include "Vision/Miscellaneous/OperNameAnalyzer.h"
|
||||
#include "Vision/MultiMatcher.h"
|
||||
#include "Vision/Oper/OperNameAnalyzer.h"
|
||||
#include "Vision/RegionOCRer.h"
|
||||
#include "Vision/TemplDetOCRer.h"
|
||||
|
||||
Reference in New Issue
Block a user