feat: report recruitment tags accordingly to prevent duplicate report

This commit is contained in:
Horror Proton
2022-08-21 21:31:14 +08:00
parent 484b68c65b
commit 1c99a0d8f9
3 changed files with 88 additions and 19 deletions

View File

@@ -2,6 +2,7 @@
#include "Resource.h"
#include "OcrImageAnalyzer.h"
#include "MultiMatchImageAnalyzer.h"
#include "Controller.h"
#include "ProcessTask.h"
#include "RecruitImageAnalyzer.h"
@@ -182,19 +183,27 @@ bool asst::AutoRecruitTask::_run()
if (!recruit_begin()) return false;
{
const auto image = m_ctrler->get_image();
// initialize_dirty_slot_info(image);
m_dirty_slots = { 0, 1, 2, 3 };
if (!hire_all(image)) return false;
}
static constexpr int slot_retry_limit = 3;
// m_cur_times means how many times has the confirm button been pressed, NOT expedited plans used
while (m_cur_times != m_max_times) {
if (m_force_discard_flag) { return false; }
if (m_slot_fail >= slot_retry_limit) { return false; }
auto start_rect = try_get_start_button(m_ctrler->get_image());
if (start_rect) {
if (need_exit()) return false;
if (recruit_one(start_rect.value())) {
if (recruit_one(start_rect.value()))
++m_cur_times;
} else ++m_slot_fail;
else
++m_slot_fail;
if (m_slot_fail >= slot_retry_limit) { return false; }
} else {
if (!check_recruit_home_page()) return false;
Log.info("There is no available start button.");
@@ -204,7 +213,9 @@ bool asst::AutoRecruitTask::_run()
if (m_use_expedited) {
if (need_exit()) return false;
Log.info("ready to use expedited plan");
if (!recruit_now()) {
if (recruit_now()) {
hire_all();
} else {
// there is a small chance that confirm button were clicked twice and got stuck into the bottom-right slot
// ref: issues/1491
if (check_recruit_home_page()) { m_force_discard_flag = true; } // ran out of expedited plan?
@@ -216,19 +227,25 @@ bool asst::AutoRecruitTask::_run()
return true;
}
std::optional<asst::Rect> asst::AutoRecruitTask::try_get_start_button(const cv::Mat& image)
std::vector<asst::TextRect> asst::AutoRecruitTask::start_recruit_analyze(const cv::Mat& image)
{
OcrImageAnalyzer start_analyzer;
start_analyzer.set_task_info("StartRecruit");
start_analyzer.set_image(image);
if (!start_analyzer.analyze()) return std::nullopt;
start_analyzer.sort_result_horizontal();
if (!start_analyzer.analyze()) return {};
return start_analyzer.get_result();
}
std::optional<asst::Rect> asst::AutoRecruitTask::try_get_start_button(const cv::Mat& image)
{
const auto result = start_recruit_analyze(image);
if (result.empty()) return std::nullopt;
auto iter =
ranges::find_if(std::as_const(start_analyzer.get_result()),
ranges::find_if(result,
[&](const TextRect& r) -> bool {
return !m_force_skipped.contains(slot_index_from_rect(r.rect));
});
if (iter == start_analyzer.get_result().cend()) return std::nullopt;
if (iter == result.cend()) return std::nullopt;
Log.info("Found slot index", slot_index_from_rect(iter->rect), ".");
return iter->rect;
}
@@ -247,11 +264,11 @@ bool asst::AutoRecruitTask::recruit_one(const Rect& button)
m_ctrler->click(button);
sleep(delay);
auto calc_result = recruit_calc_task();
auto calc_result = recruit_calc_task(slot_index_from_rect(button));
sleep(delay);
if (!calc_result.success) {
// recognition failed, perhaps open the slot again would not help
// recognition failed, perhaps opening the slot again would not help
{
json::value info = basic_info();
info["what"] = "RecruitError";
@@ -295,7 +312,7 @@ bool asst::AutoRecruitTask::recruit_one(const Rect& button)
}
// set recruit timer and tags only
asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc_task()
asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc_task(slot_index index)
{
LogTraceFunction;
@@ -342,7 +359,7 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
callback(AsstMsg::SubTaskExtraInfo, cb_info);
}
// robot tags
// robot tags
const std::vector<std::string> RobotTags = { "支援机械" };
if (auto robot_iter = ranges::find_first_of(RobotTags, tag_names);
robot_iter != RobotTags.cend()) [[unlikely]] {
@@ -430,7 +447,11 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
}
if (!is_calc_only_task()) {
async_upload_result(info["details"]);
// report if the slot is clean
if (!m_dirty_slots.contains(index)) {
async_upload_result(info["details"]);
m_dirty_slots.emplace(index); // mark as dirty
} else Log.info("will not report, dirty slots are", m_dirty_slots);
}
if (need_exit()) return {};
@@ -456,6 +477,9 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc
++refresh_count;
// mark the slot clean after refreshed
m_dirty_slots.erase(index);
{
json::value cb_info = basic_info();
cb_info["what"] = "RecruitTagsRefreshed";
@@ -602,10 +626,46 @@ bool asst::AutoRecruitTask::refresh()
return refresh_task.run();
}
bool asst::AutoRecruitTask::hire_all(const cv::Mat& image)
{
LogTraceFunction;
// mark slots with *Hire* button clean (regardless of whether hiring will success)
{
MultiMatchImageAnalyzer hire_searcher(image);
hire_searcher.set_task_info("RecruitFinish");
hire_searcher.analyze();
for (const MatchRect& r : hire_searcher.get_result()) {
Log.info("Mark", slot_index_from_rect(r.rect), "clean");
m_dirty_slots.erase(slot_index_from_rect(r.rect));
}
if (hire_searcher.get_result().empty()) return true;
}
// hire all
return ProcessTask{ *this, { "RecruitFinish" }}.run();
}
/// search for blue *Hire* buttons in the recruit home page, mark those slot clean and do hiring
bool asst::AutoRecruitTask::hire_all()
{
return hire_all(m_ctrler->get_image());
}
/// search for *RecruitNow* buttons before recruit and mark them as dirty
[[maybe_unused]] bool asst::AutoRecruitTask::initialize_dirty_slot_info(const cv::Mat& image)
{
m_dirty_slots.clear();
const auto result = start_recruit_analyze(image);
for (const TextRect& r: result) {
m_dirty_slots.emplace(slot_index_from_rect(r.rect));
}
Log.info("Dirty slots are", m_dirty_slots);
return true;
}
void asst::AutoRecruitTask::async_upload_result(const json::value& details)
{
LogTraceFunction;
return;
if (m_upload_to_penguin) {
auto upload_future = std::async(
std::launch::async,