diff --git a/resource/tasks.json b/resource/tasks.json index 98692c2370..39950a8d88 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -6775,6 +6775,7 @@ ] }, "Roguelike1TraderRandomShopping": { + "Doc": "该任务注册了 RoguelikeShoppingTaskPlugin,若是点完了仍在当前界面,说明没啥要买的,直接离开商店(next 里的 Roguelike1StageTraderLeave)", "action": "ClickSelf", "templThreshold": 0.7, "cache": false, @@ -6787,7 +6788,8 @@ "next": [ "Roguelike1TraderRandomShoppingConfirm", "Roguelike1TraderRandomShoppingCancel", - "Roguelike1TraderRandomShopping" + "Roguelike1StageTraderLeave", + "Roguelike1StageTraderLeaveConfirm" ], "maskRange": [ 1, @@ -6831,10 +6833,17 @@ 221, 136 ], + "rectMove": [ + -40, + -100, + 20, + 60 + ], "rearDelay": 2000, "Doc": "当网络卡的时候才会发生点了确认,但是还可以点取消的情况", "next": [ - "Roguelike1TraderShoppingConfirmedFlag" + "Roguelike1TraderShoppingConfirmedFlag", + "Roguelike1ChooseOperFlag" ] }, "Roguelike1TraderShoppingConfirmedFlag": { @@ -6848,19 +6857,15 @@ 204 ] }, - "Roguelike1TraderShoppingCancel": { - "template": "Roguelike1StageTraderInvestCancel.png", + "Roguelike1TraderShoppingOver": { + "template": "Roguelike1StageTraderLeave.png", "action": "ClickSelf", "cache": false, "roi": [ - 350, - 350, - 500, - 250 - ], - "rearDelay": 2000, - "next": [ - "Roguelike1TraderShoppingConfirmedFlag" + 1046, + 443, + 234, + 204 ] }, "Roguelike1TraderRandomShoppingConfirm": { diff --git a/src/MeoAssistant/AbstractTask.cpp b/src/MeoAssistant/AbstractTask.cpp index 7bb4afe0b5..d0a722582c 100644 --- a/src/MeoAssistant/AbstractTask.cpp +++ b/src/MeoAssistant/AbstractTask.cpp @@ -18,174 +18,182 @@ using namespace asst; AbstractTask::AbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain) - : m_callback(std::move(callback)), - m_callback_arg(callback_arg), - m_task_chain(std::move(task_chain)) + : m_callback(std::move(callback)), + m_callback_arg(callback_arg), + m_task_chain(std::move(task_chain)) {} bool asst::AbstractTask::run() { - if (!m_enable) { - Log.info("task disabled, pass", basic_info().to_string()); - return true; - } - callback(AsstMsg::SubTaskStart, basic_info()); - for (m_cur_retry = 0; m_cur_retry <= m_retry_times; ++m_cur_retry) { - if (_run()) { - callback(AsstMsg::SubTaskCompleted, basic_info()); - return true; - } - if (need_exit()) { - return false; - } - int delay = Resrc.cfg().get_options().task_delay; - sleep(delay); + if (!m_enable) { + Log.info("task disabled, pass", basic_info().to_string()); + return true; + } + callback(AsstMsg::SubTaskStart, basic_info()); + for (m_cur_retry = 0; m_cur_retry <= m_retry_times; ++m_cur_retry) { + if (_run()) { + callback(AsstMsg::SubTaskCompleted, basic_info()); + return true; + } + if (need_exit()) { + return false; + } + int delay = Resrc.cfg().get_options().task_delay; + sleep(delay); - if (!on_run_fails()) { - callback(AsstMsg::SubTaskError, basic_info()); - return false; - } - } - callback(AsstMsg::SubTaskError, basic_info()); - return false; + if (!on_run_fails()) { + callback(AsstMsg::SubTaskError, basic_info()); + return false; + } + } + callback(AsstMsg::SubTaskError, basic_info()); + return false; } AbstractTask& asst::AbstractTask::set_exit_flag(bool* exit_flag) noexcept { - m_exit_flag = exit_flag; - return *this; + m_exit_flag = exit_flag; + return *this; } AbstractTask& asst::AbstractTask::set_retry_times(int times) noexcept { - m_retry_times = times; - return *this; + m_retry_times = times; + return *this; } AbstractTask& asst::AbstractTask::set_ctrler(std::shared_ptr ctrler) noexcept { - m_ctrler = std::move(ctrler); - return *this; + m_ctrler = std::move(ctrler); + return *this; } AbstractTask& asst::AbstractTask::set_status(std::shared_ptr status) noexcept { - m_status = std::move(status); - return *this; + m_status = std::move(status); + return *this; } AbstractTask& asst::AbstractTask::set_enable(bool enable) noexcept { - m_enable = enable; - return *this; + m_enable = enable; + return *this; } AbstractTask& asst::AbstractTask::set_ignore_error(bool ignore) noexcept { - m_ignore_error = ignore; - return *this; + m_ignore_error = ignore; + return *this; } AbstractTask& asst::AbstractTask::set_task_id(int task_id) noexcept { - m_task_id = task_id; - return *this; + m_task_id = task_id; + return *this; } void asst::AbstractTask::clear_plugin() noexcept { - m_plugins.clear(); + m_plugins.clear(); } json::value asst::AbstractTask::basic_info() const { - if (m_basic_info_cache.empty()) { - std::string class_name = typeid(*this).name(); - std::string task_name; - // typeid.name() 结果可能和编译器有关,所以这里使用正则尽可能保证结果正确。 - // 但还是不能完全保证,如果不行的话建议 override - std::regex regex("[a-zA-Z]+Task"); - std::smatch match_obj; - if (std::regex_search(class_name, match_obj, regex)) { - task_name = match_obj[0].str(); - } - else { - task_name = class_name; - } + if (m_basic_info_cache.empty()) { + std::string class_name = typeid(*this).name(); + std::string task_name; + // typeid.name() 结果可能和编译器有关,所以这里使用正则尽可能保证结果正确。 + // 但还是不能完全保证,如果不行的话建议 override + std::regex regex("[a-zA-Z]+Task"); + std::smatch match_obj; + if (std::regex_search(class_name, match_obj, regex)) { + task_name = match_obj[0].str(); + } + else { + task_name = class_name; + } - m_basic_info_cache = json::object{ - { "taskchain", m_task_chain }, - { "taskid", m_task_id }, - { "class", class_name }, - { "subtask", task_name }, - { "details", json::object() } - //{ "CurRetryTimes", m_cur_retry }, - //{ "MaxRetryTimes", m_retry_times } - }; - } - return m_basic_info_cache; + m_basic_info_cache = json::object{ + { "taskchain", m_task_chain }, + { "taskid", m_task_id }, + { "class", class_name }, + { "subtask", task_name }, + { "details", json::object() } + //{ "CurRetryTimes", m_cur_retry }, + //{ "MaxRetryTimes", m_retry_times } + }; + } + return m_basic_info_cache; } json::value asst::AbstractTask::basic_info_with_what(std::string what) const { - json::value info = basic_info(); - info["what"] = std::move(what); - return info; + json::value info = basic_info(); + info["what"] = std::move(what); + return info; } bool AbstractTask::sleep(unsigned millisecond) { - if (need_exit()) { - return false; - } - if (millisecond == 0) { - std::this_thread::yield(); - return true; - } - auto start = std::chrono::steady_clock::now(); - Log.trace("ready to sleep", millisecond); - auto millisecond_ms = std::chrono::milliseconds(millisecond); - auto interval = millisecond_ms / 5; + if (need_exit()) { + return false; + } + if (millisecond == 0) { + std::this_thread::yield(); + return true; + } + auto start = std::chrono::steady_clock::now(); + Log.trace("ready to sleep", millisecond); + auto millisecond_ms = std::chrono::milliseconds(millisecond); + auto interval = millisecond_ms / 5; - while (!need_exit()) { - std::this_thread::sleep_for(interval); - if (std::chrono::steady_clock::now() - start > millisecond_ms) { - break; - } - } - Log.trace("end of sleep", millisecond); + while (!need_exit()) { + std::this_thread::sleep_for(interval); + if (std::chrono::steady_clock::now() - start > millisecond_ms) { + break; + } + } + Log.trace("end of sleep", millisecond); - return !need_exit(); + return !need_exit(); } bool asst::AbstractTask::need_exit() const { - return m_exit_flag != nullptr && *m_exit_flag; + return m_exit_flag != nullptr && *m_exit_flag; } void asst::AbstractTask::callback(AsstMsg msg, const json::value& detail) { - for (const TaskPluginPtr& plugin : m_plugins) { - plugin->set_exit_flag(m_exit_flag); - plugin->set_ctrler(m_ctrler); - plugin->set_task_id(m_task_id); - plugin->set_status(m_status); - plugin->set_task_ptr(this); + for (const TaskPluginPtr& plugin : m_plugins) { + plugin->set_exit_flag(m_exit_flag); + plugin->set_ctrler(m_ctrler); + plugin->set_task_id(m_task_id); + plugin->set_status(m_status); + plugin->set_task_ptr(this); - if (!plugin->verify(msg, detail)) { - continue; - } + if (!plugin->verify(msg, detail)) { + continue; + } - plugin->run(); + plugin->run(); - if (plugin->block()) { - break; - } - } - m_callback(msg, detail, m_callback_arg); + if (plugin->block()) { + break; + } + } + m_callback(msg, detail, m_callback_arg); } void asst::AbstractTask::click_return_button() { - ProcessTask(*this, { "Return" }).run(); + ProcessTask(*this, { "Return" }).run(); +} + +void asst::AbstractTask::save_image() +{ + std::string stem = utils::get_format_time(); + stem = utils::string_replace_all_batch(stem, { {":", "-"}, {" ", "_"} }); + std::filesystem::create_directory("debug"); + cv::imwrite("debug/" + stem + "_raw.png", m_ctrler->get_image()); } diff --git a/src/MeoAssistant/AbstractTask.h b/src/MeoAssistant/AbstractTask.h index 4d821b7452..61394bf4bd 100644 --- a/src/MeoAssistant/AbstractTask.h +++ b/src/MeoAssistant/AbstractTask.h @@ -63,6 +63,7 @@ namespace asst virtual bool on_run_fails() { return true; } virtual void callback(AsstMsg msg, const json::value& detail); virtual void click_return_button(); + void save_image(); json::value basic_info_with_what(std::string what) const; bool sleep(unsigned millisecond); diff --git a/src/MeoAssistant/ProcessTask.cpp b/src/MeoAssistant/ProcessTask.cpp index 4d310c2613..86020c1701 100644 --- a/src/MeoAssistant/ProcessTask.cpp +++ b/src/MeoAssistant/ProcessTask.cpp @@ -126,10 +126,7 @@ bool ProcessTask::_run() const auto& res_move = m_cur_task_ptr->rect_move; if (!res_move.empty()) { - rect.x += res_move.x; - rect.y += res_move.y; - rect.width = res_move.width; - rect.height = res_move.height; + rect = rect.move(res_move); } int& exec_times = m_exec_times[cur_name]; diff --git a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp index d7907d94ce..f80d1074c4 100644 --- a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp @@ -683,7 +683,7 @@ std::pair asst::RoguelikeBattleTaskPlugin::calc_best_direction base_direction = -base_direction; } - int64_t elite = m_status->get_number("Roguelike-" + oper.name).value_or(0); + int64_t elite = m_status->get_number(RuntimeStatus::RoguelikeCharElitePrefix + oper.name).value_or(0); // 按朝右算,后面根据方向做转换 BattleAttackRange right_attack_range = Resrc.battle_data().get_range(oper.name, elite); diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index b6c6a15f81..33155cb8c5 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -131,5 +131,6 @@ bool asst::RoguelikeRecruitTaskPlugin::check_core_char() void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo& oper) { m_ctrler->click(oper.rect); - m_status->set_number("Roguelike-" + oper.name, oper.elite); + m_status->set_number(RuntimeStatus::RoguelikeCharElitePrefix + oper.name, oper.elite); + m_status->set_number(RuntimeStatus::RoguelikeCharLevelPrefix + oper.name, oper.level); } diff --git a/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp b/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp index 8ff2575d7f..99eada2515 100644 --- a/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp @@ -35,6 +35,7 @@ bool asst::RoguelikeShoppingTaskPlugin::_run() const auto& result = analyzer.get_result(); const auto& order_goods_list = Resrc.roguelike_shopping().get_goods(); + bool bought = false; for (const auto& goods : order_goods_list) { if (need_exit()) { return false; @@ -52,18 +53,18 @@ bool asst::RoguelikeShoppingTaskPlugin::_run() if (find_it == result.cend()) { continue; } + // 这里仅点一下收藏品,原本的 ProcessTask 还会再点一下,但它是由 rect_move 的,保证不会点出去 + // 即 ProcessTask 多点的那一下会点到不影响的地方 + // 然后继续走 next 里确认 or 取消等等的逻辑 Log.info("Ready to buy", goods.name); m_ctrler->click(find_it->rect); - bool confirmed = ProcessTask(*this, { "Roguelike1TraderShoppingConfirm", "Roguelike1ChooseOperFlag" }) - .set_times_limit("Roguelike1TraderRandomShopping", 0) - .set_times_limit("Roguelike1StageTraderLeave", 0) - .set_times_limit("Roguelike1ExitThenAbandon", 0) - .set_retry_times(5) - .run(); + bought = true; + break; + } - if (!confirmed) { - return false; - } + if (!bought) { + // 如果什么都没买,即使有商品,说明也是不需要买的,这里强制离开商店,后面让 ProcessTask 继续跑 + return ProcessTask(*this, { "Roguelike1TraderShoppingOver" }).run(); } return true; diff --git a/src/MeoAssistant/RuntimeStatus.h b/src/MeoAssistant/RuntimeStatus.h index 6e9df92c4c..ffc01d45a9 100644 --- a/src/MeoAssistant/RuntimeStatus.h +++ b/src/MeoAssistant/RuntimeStatus.h @@ -32,6 +32,11 @@ namespace asst RuntimeStatus& operator=(const RuntimeStatus& rhs) = delete; RuntimeStatus& operator=(RuntimeStatus&& rhs) noexcept = delete; + public: + static inline const std::string RoguelikeCharElitePrefix = "RoguelikeElite-"; + static inline const std::string RoguelikeCharLevelPrefix = "RoguelikeLevel-"; + static inline const std::string RoguelikeCharRarityPrefix = "RoguelikeRarity-"; + private: std::unordered_map m_number;