refactor.重构基建类,添加可用干员人数不足的回调

This commit is contained in:
MistEO
2022-01-10 00:09:46 +08:00
parent 52eb57940b
commit 9967aaa9e2
24 changed files with 117 additions and 118 deletions

View File

@@ -334,3 +334,14 @@ Todo
"index": 0 // 设施序号
}
```
- `NotEnoughStaff`
设施内可用干员人数不足
```jsonc
// 对应的 details 字段举例
{
"facility": "Mfg", // 设施名
"index": 0 // 设施序号
}
```

View File

@@ -73,6 +73,13 @@ json::value asst::AbstractTask::basic_info() const
};
}
json::value asst::AbstractTask::basic_info_with_what(std::string what) const
{
json::value info = basic_info();
info["what"] = std::move(what);
return info;
}
bool AbstractTask::sleep(unsigned millisecond)
{
if (need_exit()) {

View File

@@ -53,12 +53,12 @@ namespace asst
virtual bool _run() = 0;
virtual bool on_run_fails() { return true; }
virtual void callback(AsstMsg msg, const json::value& detail);
virtual void click_return_button();
json::value basic_info_with_what(std::string what) const;
bool sleep(unsigned millisecond);
bool save_image(const cv::Mat image, const std::string& dir);
bool need_exit() const;
bool save_image(const cv::Mat image, const std::string& dir);
AsstCallback m_callback;
void* m_callback_arg = nullptr;

View File

@@ -339,7 +339,6 @@ bool Assistant::append_debug()
constexpr static const char* DebugTaskChain = "Debug";
auto shift_task_ptr = std::make_shared<InfrastControlTask>(task_callback, (void*)this, DebugTaskChain);
shift_task_ptr->set_work_mode(infrast::WorkMode::Aggressive);
shift_task_ptr->set_facility("Control");
shift_task_ptr->set_product("MoodAddition");
m_tasks_queue.emplace(shift_task_ptr);
}

View File

@@ -1,5 +1,7 @@
#include "InfrastAbstractTask.h"
#include <regex>
#include "AsstMsg.h"
#include "Controller.h"
#include "InfrastFacilityImageAnalyzer.h"
@@ -9,20 +11,13 @@
#include "Resource.h"
#include "ProcessTask.h"
int asst::InfrastAbstractTask::m_face_hash_thres = 0;
int asst::InfrastAbstractTask::m_name_hash_thres = 0;
asst::InfrastAbstractTask::InfrastAbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain)
: AbstractTask(callback, callback_arg, std::move(task_chain))
{
if (m_face_hash_thres == 0) {
m_face_hash_thres = static_cast<int>(std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastOperFaceHash"))->templ_threshold);
}
if (m_name_hash_thres == 0) {
m_name_hash_thres = static_cast<int>(std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastOperNameHash"))->templ_threshold);
}
m_face_hash_thres = static_cast<int>(std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastOperFaceHash"))->templ_threshold);
m_name_hash_thres = static_cast<int>(std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastOperNameHash"))->templ_threshold);
}
asst::InfrastAbstractTask& asst::InfrastAbstractTask::set_work_mode(infrast::WorkMode work_mode) noexcept
@@ -51,39 +46,56 @@ asst::InfrastAbstractTask& asst::InfrastAbstractTask::set_mood_threshold(double
return *this;
}
json::value asst::InfrastAbstractTask::basic_info() const
{
json::value info = AbstractTask::basic_info();
info["details"]["facility"] = facility_name();
info["details"]["index"] = m_cur_facility_index;
return info;
}
std::string asst::InfrastAbstractTask::facility_name() const
{
// typeid.name() 结果可能和编译器有关,所以这里使用正则尽可能保证结果正确。
// 但还是不能完全保证,如果不行的话建议 override
static std::regex regex("Infrast(.*)Task");
std::smatch match_obj;
std::string class_name = typeid(*this).name();
if (std::regex_search(class_name, match_obj, regex)) {
return match_obj[1].str();
}
else {
return class_name;
}
}
bool asst::InfrastAbstractTask::on_run_fails()
{
LogTraceFunction;
ProcessTask return_task(*this, { "InfrastBegin" });
return return_task.run();
}
bool asst::InfrastAbstractTask::enter_facility(const std::string& facility, int index)
bool asst::InfrastAbstractTask::enter_facility(int index)
{
json::value info = basic_info();
info["what"] = "EnterFacility";
info["details"] = json::object{
{ "facility", facility },
{ "index", index }
};
callback(AsstMsg::SubTaskExtraInfo, info);
const auto image = Ctrler.get_image();
InfrastFacilityImageAnalyzer analyzer(image);
analyzer.set_to_be_analyzed({ facility });
analyzer.set_to_be_analyzed({ facility_name() });
if (!analyzer.analyze()) {
Log.trace("result is empty");
return false;
}
Rect rect = analyzer.get_rect(facility, index);
Rect rect = analyzer.get_rect(facility_name(), index);
if (rect.empty()) {
Log.trace("facility index is out of range");
return false;
}
m_cur_facility_index = index;
callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("EnterFacility"));
Ctrler.click(rect);
const auto enter_task_ptr = Task.get("InfrastEnterFacility");

View File

@@ -12,22 +12,27 @@ namespace asst
InfrastAbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain);
virtual ~InfrastAbstractTask() = default;
virtual InfrastAbstractTask& set_work_mode(infrast::WorkMode work_mode) noexcept;
virtual InfrastAbstractTask& set_mood_threshold(double mood_thres) noexcept;
InfrastAbstractTask& set_work_mode(infrast::WorkMode work_mode) noexcept;
InfrastAbstractTask& set_mood_threshold(double mood_thres) noexcept;
virtual json::value basic_info() const override;
virtual std::string facility_name() const;
virtual size_t max_num_of_facility() const noexcept { return 1ULL; }
virtual size_t max_num_of_opers() const noexcept { return 1ULL; }
constexpr static int OperSelectRetryTimes = 3;
protected:
virtual bool on_run_fails() override;
virtual bool enter_facility(const std::string& facility, int index = 0);
virtual bool enter_oper_list_page(); // 从刚点进基建的界面,到干员列表页
bool enter_facility(int index = 0);
bool enter_oper_list_page(); // 从刚点进设施的界面,到干员列表页
virtual void swipe_to_the_left_of_operlist(int loop_times = 1); // 滑动到干员列表的最左侧
virtual void swipe_to_the_left_of_main_ui(); // 滑动基建的主界面到最左侧
virtual void swipe_to_the_right_of_main_ui(); // 滑动基建的主界面到最右侧
virtual void swipe_of_operlist(bool reverse = false);
virtual void async_swipe_of_operlist(bool reverse = false);
virtual void await_swipe();
void swipe_to_the_left_of_operlist(int loop_times = 1); // 滑动到干员列表的最左侧
void swipe_to_the_left_of_main_ui(); // 滑动基建的主界面到最左侧
void swipe_to_the_right_of_main_ui(); // 滑动基建的主界面到最右侧
void swipe_of_operlist(bool reverse = false);
void async_swipe_of_operlist(bool reverse = false);
void await_swipe();
virtual bool click_bottomleft_tab(); // 点击进入设施后左下角的tab我也不知道这玩意该叫啥
virtual bool click_clear_button(); // 点击干员选择页面的“清空选择”按钮
@@ -37,8 +42,9 @@ namespace asst
infrast::WorkMode m_work_mode = infrast::WorkMode::Gentle;
std::string m_work_mode_name = "Gentle";
double m_mood_threshold = 0;
int m_cur_facility_index = 0;
static int m_face_hash_thres;
static int m_name_hash_thres;
int m_face_hash_thres = 0;
int m_name_hash_thres = 0;
};
}

View File

@@ -1,17 +1,13 @@
#include "InfrastControlTask.h"
const std::string asst::InfrastControlTask::FacilityName = "Control";
bool asst::InfrastControlTask::_run()
{
set_facility(FacilityName);
m_all_available_opers.clear();
// 控制中枢只能造这一个
set_product("MoodAddition");
// 进不去说明设施数量不够
if (!enter_facility(FacilityName, 0)) {
if (!enter_facility()) {
return false;
}
if (!enter_oper_list_page()) {

View File

@@ -9,8 +9,7 @@ namespace asst
using InfrastProductionTask::InfrastProductionTask;
virtual ~InfrastControlTask() = default;
const static std::string FacilityName;
const static int MaxNumOfOpers = 5;
virtual size_t max_num_of_opers() const noexcept override { return 5ULL; }
private:
virtual bool _run() override;
};

View File

@@ -7,16 +7,14 @@
#include "OcrImageAnalyzer.h"
#include "Resource.h"
const std::string asst::InfrastDormTask::FacilityName = "Dorm";
bool asst::InfrastDormTask::_run()
{
for (; m_cur_dorm_index < m_max_num_of_dorm; ++m_cur_dorm_index) {
for (; m_cur_facility_index < m_max_num_of_dorm; ++m_cur_facility_index) {
if (need_exit()) {
return false;
}
// 进不去说明设施数量不够
if (!enter_facility(FacilityName, m_cur_dorm_index)) {
if (!enter_facility(m_cur_facility_index)) {
break;
}
if (!enter_oper_list_page()) {
@@ -39,7 +37,7 @@ bool asst::InfrastDormTask::_run()
bool asst::InfrastDormTask::opers_choose()
{
int num_of_selected = 0;
while (num_of_selected < MaxNumOfOpers) {
while (num_of_selected < max_num_of_opers()) {
if (need_exit()) {
return false;
}
@@ -59,14 +57,14 @@ bool asst::InfrastDormTask::opers_choose()
if (need_exit()) {
return false;
}
if (num_of_selected >= MaxNumOfOpers) {
if (num_of_selected >= max_num_of_opers()) {
Log.trace("num_of_selected:", num_of_selected, ", just break");
break;
}
switch (oper.smiley.type) {
case infrast::SmileyType::Rest:
// 如果当前页面休息完成的人数超过5个说明已经已经把所有心情不满的滑过一遍、没有更多的了
if (++num_of_resting > MaxNumOfOpers) {
if (++num_of_resting > max_num_of_opers()) {
Log.trace("num_of_resting:", num_of_resting, ", dorm finished");
m_all_finished = true;
return true;
@@ -77,7 +75,7 @@ bool asst::InfrastDormTask::opers_choose()
// 干员没有被选择的情况下,且不在工作,就进驻宿舍
if (oper.selected == false && oper.doing != infrast::Doing::Working) {
Ctrler.click(oper.rect);
if (++num_of_selected >= MaxNumOfOpers) {
if (++num_of_selected >= max_num_of_opers()) {
Log.trace("num_of_selected:", num_of_selected, ", just break");
break;
}
@@ -87,7 +85,7 @@ bool asst::InfrastDormTask::opers_choose()
break;
}
}
if (num_of_selected >= MaxNumOfOpers) {
if (num_of_selected >= max_num_of_opers()) {
Log.trace("num_of_selected:", num_of_selected, ", just break");
break;
}

View File

@@ -9,8 +9,7 @@ namespace asst
using InfrastAbstractTask::InfrastAbstractTask;
virtual ~InfrastDormTask() = default;
const static std::string FacilityName;
const static int MaxNumOfOpers = 5;
virtual size_t max_num_of_opers() const noexcept override { return 5ULL; }
private:
virtual bool _run() override;

View File

@@ -4,15 +4,12 @@
#include "MatchImageAnalyzer.h"
#include "Resource.h"
const std::string asst::InfrastMfgTask::FacilityName = "Mfg";
bool asst::InfrastMfgTask::_run()
{
set_facility(FacilityName);
m_all_available_opers.clear();
swipe_to_the_left_of_main_ui();
enter_facility(FacilityName, 0);
enter_facility(0);
click_bottomleft_tab();
if (!shift_facility_list()) {

View File

@@ -9,7 +9,8 @@ namespace asst
using InfrastProductionTask::InfrastProductionTask;
virtual ~InfrastMfgTask() = default;
static const std::string FacilityName;
virtual size_t max_num_of_facility() const noexcept override { return 5ULL; }
virtual size_t max_num_of_opers() const noexcept override { return 3ULL; }
protected:
virtual bool _run() override;

View File

@@ -2,18 +2,15 @@
#include "Controller.h"
const std::string asst::InfrastOfficeTask::FacilityName = "Office";
bool asst::InfrastOfficeTask::_run()
{
set_facility(FacilityName);
m_all_available_opers.clear();
// 办公室只能造这一个
set_product("HR");
swipe_to_the_right_of_main_ui();
enter_facility(FacilityName, 0);
enter_facility();
click_bottomleft_tab();
for (int i = 0; i <= OperSelectRetryTimes; ++i) {

View File

@@ -9,9 +9,6 @@ namespace asst
using InfrastProductionTask::InfrastProductionTask;
virtual ~InfrastOfficeTask() = default;
const static std::string FacilityName;
const static int MaxNumOfOpers = 1;
protected:
virtual bool _run() override;
};

View File

@@ -2,24 +2,21 @@
#include "Controller.h"
const std::string asst::InfrastPowerTask::FacilityName = "Power";
bool asst::InfrastPowerTask::_run()
{
set_facility(FacilityName);
m_all_available_opers.clear();
// 发电站只能造这一个
set_product("Drone");
for (int i = 0; i != MaxNumOfFacility; ++i) {
for (int i = 0; i != max_num_of_facility(); ++i) {
if (need_exit()) {
return false;
}
swipe_to_the_left_of_main_ui();
// 进不去说明设施数量不够
if (!enter_facility(FacilityName, i)) {
if (!enter_facility(i)) {
break;
}
if (!enter_oper_list_page()) {

View File

@@ -9,9 +9,7 @@ namespace asst
using InfrastProductionTask::InfrastProductionTask;
virtual ~InfrastPowerTask() = default;
const static std::string FacilityName;
const static int MaxNumOfOpers = 1;
const static int MaxNumOfFacility = 3;
virtual size_t max_num_of_facility() const noexcept override { return 3ULL; }
protected:
virtual bool _run() override;

View File

@@ -20,12 +20,6 @@ asst::InfrastProductionTask& asst::InfrastProductionTask::set_uses_of_drone(std:
return *this;
}
asst::InfrastProductionTask& asst::InfrastProductionTask::set_facility(std::string facility_name) noexcept
{
m_facility = std::move(facility_name);
return *this;
}
asst::InfrastProductionTask& asst::InfrastProductionTask::set_product(std::string product_name) noexcept
{
m_product = std::move(product_name);
@@ -42,30 +36,25 @@ bool asst::InfrastProductionTask::shift_facility_list()
return false;
}
const auto tab_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastFacilityListTab" + m_facility));
Task.get("InfrastFacilityListTab" + facility_name()));
MatchImageAnalyzer add_analyzer;
const auto add_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastAddOperator" + m_facility + m_work_mode_name));
Task.get("InfrastAddOperator" + facility_name() + m_work_mode_name));
add_analyzer.set_task_info(*add_task_ptr);
const auto locked_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastOperLocked" + m_facility));
Task.get("InfrastOperLocked" + facility_name()));
MultiMatchImageAnalyzer locked_analyzer;
locked_analyzer.set_task_info(*locked_task_ptr);
int index = 0;
for (const Rect& tab : m_facility_list_tabs) {
m_cur_facility_index = index;
if (need_exit()) {
return false;
}
if (index != 0) {
json::value info = basic_info();
info["what"] = "EnterFacility";
info["details"] = json::object{
{ "facility", m_facility },
{ "index", index }
};
callback(AsstMsg::SubTaskExtraInfo, info);
callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("EnterFacility"));
}
++index;
@@ -92,7 +81,7 @@ bool asst::InfrastProductionTask::shift_facility_list()
/* 识别当前正在造什么 */
MatchImageAnalyzer product_analyzer(image);
auto& all_products = Resrc.infrast().get_facility_info(m_facility).products;
auto& all_products = Resrc.infrast().get_facility_info(facility_name()).products;
std::string cur_product = all_products.at(0);
double max_score = 0;
for (const std::string& product : all_products) {
@@ -198,7 +187,7 @@ size_t asst::InfrastProductionTask::opers_detect()
const auto image = Ctrler.get_image();
InfrastOperImageAnalyzer oper_analyzer(image);
oper_analyzer.set_facility(m_facility);
oper_analyzer.set_facility(facility_name());
if (!oper_analyzer.analyze()) {
return 0;
@@ -219,7 +208,7 @@ size_t asst::InfrastProductionTask::opers_detect()
}
auto find_iter = std::find_if(
m_all_available_opers.cbegin(), m_all_available_opers.cend(),
[&cur_oper](const infrast::Oper& oper) -> bool {
[&](const infrast::Oper& oper) -> bool {
// 有可能是同一个干员比一下hash
int dist = utils::hamming(cur_oper.face_hash, oper.face_hash);
Log.debug("opers_detect hash dist |", dist);
@@ -237,7 +226,7 @@ size_t asst::InfrastProductionTask::opers_detect()
bool asst::InfrastProductionTask::optimal_calc()
{
LogTraceFunction;
auto& facility_info = Resrc.infrast().get_facility_info(m_facility);
auto& facility_info = Resrc.infrast().get_facility_info(facility_name());
int cur_max_num_of_opers = facility_info.max_num_of_opers - m_cur_num_of_lokced_opers;
std::vector<infrast::SkillsComb> all_avaliable_combs;
@@ -309,7 +298,7 @@ bool asst::InfrastProductionTask::optimal_calc()
}
// 遍历所有组合,找到效率最高的
auto& all_group = Resrc.infrast().get_skills_group(m_facility);
auto& all_group = Resrc.infrast().get_skills_group(facility_name());
for (const infrast::SkillsGroup& group : all_group) {
Log.trace(group.desc);
auto cur_available_opers = all_avaliable_combs;
@@ -462,7 +451,7 @@ bool asst::InfrastProductionTask::opers_choose()
bool has_error = false;
int count = 0;
auto& facility_info = Resrc.infrast().get_facility_info(m_facility);
auto& facility_info = Resrc.infrast().get_facility_info(facility_name());
int cur_max_num_of_opers = facility_info.max_num_of_opers - m_cur_num_of_lokced_opers;
while (true) {
@@ -472,7 +461,7 @@ bool asst::InfrastProductionTask::opers_choose()
const auto image = Ctrler.get_image();
InfrastOperImageAnalyzer oper_analyzer(image);
oper_analyzer.set_facility(m_facility);
oper_analyzer.set_facility(facility_name());
if (!oper_analyzer.analyze()) {
return false;
@@ -566,7 +555,7 @@ bool asst::InfrastProductionTask::opers_choose()
break;
}
else { // 这种情况可能是萌新,可用干员人数不足以填满当前设施
// TODO!!!
callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("NotEnoughStaff"));
break;
}
}
@@ -580,7 +569,7 @@ bool asst::InfrastProductionTask::opers_choose()
bool asst::InfrastProductionTask::use_drone()
{
std::string task_name = "DroneAssist" + m_facility;
std::string task_name = "DroneAssist" + facility_name();
ProcessTask task_temp(*this, { task_name });
return task_temp.run();
}
@@ -623,7 +612,7 @@ bool asst::InfrastProductionTask::facility_list_detect()
MultiMatchImageAnalyzer mm_analyzer(image);
const auto task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
Task.get("InfrastFacilityListTab" + m_facility));
Task.get("InfrastFacilityListTab" + facility_name()));
mm_analyzer.set_task_info(*task_ptr);
if (!mm_analyzer.analyze()) {

View File

@@ -21,7 +21,6 @@ namespace asst
// 为了方便调试把这两个个接口拿到public来了
protected:
#endif
InfrastProductionTask& set_facility(std::string facility_name) noexcept;
InfrastProductionTask& set_product(std::string product_name) noexcept;
protected:
@@ -36,7 +35,6 @@ namespace asst
infrast::SkillsComb efficient_regex_calc(
std::unordered_set<infrast::Skill> skills) const;
std::string m_facility;
std::string m_product;
std::string m_uses_of_drones;
int m_cur_num_of_lokced_opers = 0;

View File

@@ -8,15 +8,12 @@
#include "ProcessTask.h"
#include "Resource.h"
const std::string asst::InfrastReceptionTask::FacilityName = "Reception";
bool asst::InfrastReceptionTask::_run()
{
set_facility(FacilityName);
m_all_available_opers.clear();
swipe_to_the_right_of_main_ui();
enter_facility(FacilityName, 0);
enter_facility();
click_bottomleft_tab();
close_end_of_clue_exchange();
@@ -146,7 +143,7 @@ bool asst::InfrastReceptionTask::shift()
const auto image = Ctrler.get_image();
MatchImageAnalyzer add_analyzer(image);
const auto raw_task_ptr = Task.get("InfrastAddOperator" + m_facility + m_work_mode_name);
const auto raw_task_ptr = Task.get("InfrastAddOperator" + facility_name() + m_work_mode_name);
switch (raw_task_ptr->algorithm) {
case AlgorithmType::JustReturn:
if (raw_task_ptr->action == ProcessTaskAction::ClickRect) {

View File

@@ -9,8 +9,6 @@ namespace asst
using InfrastProductionTask::InfrastProductionTask;
virtual ~InfrastReceptionTask() = default;
const static std::string FacilityName;
protected:
virtual bool _run() override;

View File

@@ -1,14 +1,11 @@
#include "InfrastTradeTask.h"
const std::string asst::InfrastTradeTask::FacilityName = "Trade";
bool asst::InfrastTradeTask::_run()
{
set_facility(FacilityName);
m_all_available_opers.clear();
swipe_to_the_left_of_main_ui();
enter_facility(FacilityName, 0);
enter_facility(0);
click_bottomleft_tab();
if (!shift_facility_list()) {

View File

@@ -9,7 +9,8 @@ namespace asst
using InfrastProductionTask::InfrastProductionTask;
virtual ~InfrastTradeTask() = default;
static const std::string FacilityName;
virtual size_t max_num_of_facility() const noexcept override { return 5ULL; }
virtual size_t max_num_of_opers() const noexcept override { return 3ULL; }
protected:
virtual bool _run() override;

View File

@@ -89,8 +89,7 @@ void asst::StageDropsTaskPlugin::drop_info_callback()
drops_details["stats"] = json::array(std::move(statistics_vec));
json::value info = basic_info();
info["what"] = "StageDrops";
json::value info = basic_info_with_what("StageDrops");
info["details"] = drops_details;
callback(AsstMsg::SubTaskExtraInfo, info);

View File

@@ -360,6 +360,12 @@ namespace MeoAsstGui
mainModel.AddLog("选择 Tags\n" + selected_log);
}
break;
case "NotEnoughStaff":
{
mainModel.AddLog("可用干员不足", "darkred");
}
break;
}
}