diff --git a/resource/tasks.json b/resource/tasks.json index fc915230f2..00b78f2ca5 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -2223,6 +2223,10 @@ ".*耀阳.*", "“耀阳”" ], + [ + "玛恩.+", + "玛恩纳" + ], [ ".*默德克萨斯", "缄默德克萨斯" diff --git a/src/MaaCore/Task/Infrast/InfrastAbstractTask.cpp b/src/MaaCore/Task/Infrast/InfrastAbstractTask.cpp index c050a298dc..4eb03b9363 100644 --- a/src/MaaCore/Task/Infrast/InfrastAbstractTask.cpp +++ b/src/MaaCore/Task/Infrast/InfrastAbstractTask.cpp @@ -141,6 +141,7 @@ bool asst::InfrastAbstractTask::swipe_and_select_custom_opers(bool is_dorm_order LogTraceFunction; auto& room_config = current_room_config(); + auto origin_room_config = room_config; { json::value cb_info = basic_info_with_what("CustomInfrastRoomOperators"); auto& details = cb_info["details"]; @@ -219,7 +220,87 @@ bool asst::InfrastAbstractTask::swipe_and_select_custom_opers(bool is_dorm_order order_opers_selection(opers_order); } - return room_config.names.empty(); + if (!room_config.names.empty()) { + return false; + } + + if (!is_dorm_order) { + if (swipe_times) swipe_to_the_left_of_operlist(swipe_times + 1); + swipe_times = 0; + if (!select_opers_review(origin_room_config)) { + // 复核失败,说明current_room_config与OCR识别是不符的,current_room_config是无效信息,还原到用户原来的配置,重选 + current_room_config() = std::move(origin_room_config); + return false; + } + } + + return true; +} + +/// @brief 复核干员选择是否符合期望。如果是自定义的,会检查自定义的人选全了没。 +/// @brief 调用该函数前,需保证停留在干员选择页面第一页,且已选干员排在最前面。 +/// @param origin_room_config 期望的配置 +/// @param num_of_opers_expect 期望选中的人数,空置则按names.size()判断 +/// @return 是否符合期望 +bool asst::InfrastAbstractTask::select_opers_review(infrast::CustomRoomConfig const& origin_room_config, size_t num_of_opers_expect) +{ + LogTraceFunction; + // save_img("debug/"); + auto room_config = origin_room_config; + + const auto image = ctrler()->get_image(); + InfrastOperImageAnalyzer oper_analyzer(image); + oper_analyzer.set_to_be_calced(InfrastOperImageAnalyzer::ToBeCalced::Selected); + if (!oper_analyzer.analyze()) { + Log.warn("No oper"); + return false; + } + oper_analyzer.sort_by_loc(); + const auto& oper_analyzer_res = oper_analyzer.get_result(); + size_t selected_count = ranges::count_if(oper_analyzer_res, [](const infrast::Oper& info) { return info.selected; }); + Log.info("selected_count,config.names.size,num_of_opers_expect = ", selected_count, ",", room_config.names.size(), ",", num_of_opers_expect); + + if (selected_count < num_of_opers_expect) { + Log.warn("select opers review fail: 选中干员数与期望不符"); + return false; + } + if (selected_count < room_config.names.size()) { + Log.warn("select opers review fail: 存在自定义干员未选中"); + return false; + } + + const auto& ocr_replace = Task.get("CharsNameOcrReplace")->replace_map; + for (const auto& oper : oper_analyzer_res) { + OcrWithPreprocessImageAnalyzer name_analyzer; + name_analyzer.set_replace(ocr_replace); + name_analyzer.set_image(oper.name_img); + name_analyzer.set_expansion(0); + if (!name_analyzer.analyze()) { + continue; + } + if (!oper.selected) { + break; + } + + const std::string& name = name_analyzer.get_result().front().text; + if (auto iter = ranges::find(room_config.names, name); iter != room_config.names.end()) { + Log.info(name, "在\"operators\"中,且已选中"); + room_config.names.erase(iter); + } else { // 备选干员或自动选择,只要不选工作中的干员即可 + if (oper.doing == infrast::Doing::Working) { + Log.warn("select opers review fail: 非自定义情况下,选了正在工作的干员"); + return false; + } + } + } + + if (room_config.names.size()) { + Log.warn("select opers review fail: 存在自定义干员未选中"); + return false; + } + + Log.info("select opers review passed"); + return true; } bool asst::InfrastAbstractTask::select_custom_opers(std::vector& partial_result) diff --git a/src/MaaCore/Task/Infrast/InfrastAbstractTask.h b/src/MaaCore/Task/Infrast/InfrastAbstractTask.h index 9f79300033..43c9667904 100644 --- a/src/MaaCore/Task/Infrast/InfrastAbstractTask.h +++ b/src/MaaCore/Task/Infrast/InfrastAbstractTask.h @@ -39,6 +39,7 @@ namespace asst infrast::CustomRoomConfig& current_room_config(); bool swipe_and_select_custom_opers(bool is_dorm_order = false); bool select_custom_opers(std::vector& partial_result); + bool select_opers_review(infrast::CustomRoomConfig const& origin_room_config, size_t num_of_opers_expect = 0); // 复核干员选择是否符合期望 void order_opers_selection(const std::vector& names); virtual void click_return_button() override; diff --git a/src/MaaCore/Task/Infrast/InfrastDormTask.cpp b/src/MaaCore/Task/Infrast/InfrastDormTask.cpp index 0dd65a1d64..0e764e6ec8 100644 --- a/src/MaaCore/Task/Infrast/InfrastDormTask.cpp +++ b/src/MaaCore/Task/Infrast/InfrastDormTask.cpp @@ -41,6 +41,7 @@ bool asst::InfrastDormTask::_run() return false; } + auto origin_room_config = current_room_config(); if (is_use_custom_opers()) { swipe_and_select_custom_opers(true); } @@ -56,7 +57,15 @@ bool asst::InfrastDormTask::_run() } if (!m_is_custom || current_room_config().autofill) { - opers_choose(); + if (!opers_choose(origin_room_config)) { + return false; + } + } + else { + if (!select_opers_review(origin_room_config)) { + current_room_config() = std::move(origin_room_config); + return false; + } } click_confirm_button(); @@ -69,11 +78,12 @@ bool asst::InfrastDormTask::_run() return true; } -bool asst::InfrastDormTask::opers_choose() +bool asst::InfrastDormTask::opers_choose(asst::infrast::CustomRoomConfig const& origin_room_config) { size_t num_of_selected = m_is_custom ? current_room_config().selected : 0; size_t num_of_fulltrust = 0; bool to_fill = false; + int swipe_times = 0; while (num_of_selected < max_num_of_opers()) { if (need_exit()) { @@ -217,6 +227,7 @@ bool asst::InfrastDormTask::opers_choose() // 如果是之前设置的to_fill,走不到这里,一定是当次设置的 if (to_fill) { swipe_of_operlist(); + ++swipe_times; break; } } @@ -235,8 +246,18 @@ bool asst::InfrastDormTask::opers_choose() } else { swipe_of_operlist(); + ++swipe_times; } } + + if (swipe_times) swipe_to_the_left_of_operlist(swipe_times + 1); + swipe_times = 0; + ProcessTask(*this, { "InfrastOperListTabMoodDoubleClick" }).run(); + if (!select_opers_review(origin_room_config, num_of_selected)) { + current_room_config() = origin_room_config; + return false; + } + return true; } diff --git a/src/MaaCore/Task/Infrast/InfrastDormTask.h b/src/MaaCore/Task/Infrast/InfrastDormTask.h index c0e6287c63..f36e911d33 100644 --- a/src/MaaCore/Task/Infrast/InfrastDormTask.h +++ b/src/MaaCore/Task/Infrast/InfrastDormTask.h @@ -18,7 +18,7 @@ namespace asst virtual bool _run() override; // virtual bool click_confirm_button() override; - bool opers_choose(); + bool opers_choose(asst::infrast::CustomRoomConfig const& origin_room_config); bool click_order_by_mood(); bool m_dorm_notstationed_enabled = false; // 设置是否启用未进驻筛选 diff --git a/src/MaaCore/Task/Infrast/InfrastProductionTask.cpp b/src/MaaCore/Task/Infrast/InfrastProductionTask.cpp index 55fd3cb1de..69872b2395 100644 --- a/src/MaaCore/Task/Infrast/InfrastProductionTask.cpp +++ b/src/MaaCore/Task/Infrast/InfrastProductionTask.cpp @@ -96,6 +96,15 @@ bool asst::InfrastProductionTask::shift_facility_list() } } + if (m_is_custom && current_room_config().skip) { + Log.info("skip this room"); + continue; + } + // 最近总是出现设施没选中,导致干员放错房间,多点一次,观察一段时间。最好是改为图像识别是几号。 + sleep(tab_task_ptr->pre_delay); + ctrler()->click(tab); + sleep(tab_task_ptr->post_delay); + sleep(tab_task_ptr->pre_delay); ctrler()->click(tab); sleep(tab_task_ptr->post_delay); @@ -147,11 +156,6 @@ bool asst::InfrastProductionTask::shift_facility_list() use_drone(); } - if (m_is_custom && current_room_config().skip) { - Log.info("skip this room"); - continue; - } - /* 进入干员选择页面 */ ctrler()->click(add_button); sleep(add_task_ptr->post_delay); @@ -522,6 +526,7 @@ bool asst::InfrastProductionTask::opers_choose() std::dynamic_pointer_cast(Task.get("InfrastOperFaceHash"))->dist_threshold; int count = 0; + int swipe_times = 0; while (true) { if (need_exit()) { @@ -624,9 +629,13 @@ bool asst::InfrastProductionTask::opers_choose() // 因为识别完了还要点击,所以这里不能异步滑动 swipe_of_operlist(); + ++swipe_times; } - return true; + if (swipe_times) swipe_to_the_left_of_operlist(swipe_times + 1); + swipe_times = 0; + ProcessTask(*this, { "InfrastOperListTabSkillUnClicked", "Stop" }).run(); // 点下排序,让已选干员排到最前面 + return select_opers_review(current_room_config(), count); } bool asst::InfrastProductionTask::use_drone()