diff --git a/docs/3.1-集成文档.md b/docs/3.1-集成文档.md index 521a4ca96a..75682f2f07 100644 --- a/docs/3.1-集成文档.md +++ b/docs/3.1-集成文档.md @@ -114,15 +114,27 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p ```jsonc { "enable": bool, // 是否启用本任务,可选,默认为 true - "mode": int, // 换班工作模式,保留接口,暂时可以不传。不支持运行中设置 + "mode": int, // 换班工作模式,可选,默认 0 + // 0 - 默认换班模式,单设施最优解 + // 10000 - 自定义换班模式,读取用户配置,可参考 3.6-基建排班协议.md + "facility": [ // 要换班的设施(有序),必选。不支持运行中设置 string, // 设施名,"Mfg" | "Trade" | "Power" | "Control" | "Reception" | "Office" | "Dorm" ... ], "drones": string, // 无人机用途,可选项,默认 _NotUse + // mode==10000 时该字段无效(会被忽略) // "_NotUse"、"Money"、"SyntheticJade"、"CombatRecord"、"PureGold"、"OriginStone"、"Chip" - "threshold": float, // 宿舍进驻心情阈值,可选,取值范围 [0, 1.0],默认 0.3 - "replenish": bool // 贸易站“源石碎片”是否自动补货,可选,默认 false + "threshold": float, // 工作心情阈值,可选,取值范围 [0, 1.0],默认 0.3 + // mode==10000 时该字段无效(会被忽略) + "replenish": bool, // 贸易站“源石碎片”是否自动补货,可选,默认 false + + "dorm_notstationed_enabled": bool, // 是否启用宿舍“未进驻”选项,可选,默认 false + "drom_trust_enabled": bool, // 是否将宿舍剩余位置填入信赖未满干员,可选,默认 false + + /* 以下参数仅在 mode=10000 时生效,否则会被忽略 */ + "filename": string, // 自定义配置路径,必选。不支持运行中设置 + "index": int, // 使用配置中的方案需要,必选。不支持运行中设置 } ``` diff --git a/docs/3.6-基建排班协议.md b/docs/3.6-基建排班协议.md index 1dd7251610..f335682290 100644 --- a/docs/3.6-基建排班协议.md +++ b/docs/3.6-基建排班协议.md @@ -28,9 +28,9 @@ "index": 0, // 为第几个该类型房间使用 "rule": "ALL" // 使用规则,保留字段,目前无作用。以后可能拿来支持插拔等操作 }, - "rooms": { // 房间名 + "rooms": { // 房间信息,必选 // 取值范围 "control" / "manufacture" / "trading" / "power" / "meeting" / "hire" / "dormitory" - // 缺少某个则不对该类房间进行换班 + // 缺少某个则不对该设施进行换班 "control": [ { "operators": [ @@ -54,10 +54,10 @@ "operators": [ "Castle-3" ], - "auto": true, // 使用原先的算法,自动填充剩下的位置,可选,默认 false + "autofill": true, // 使用原先的算法,自动填充剩下的位置,可选,默认 false // 若 operators 为空,则该房间完整的使用原先算法进行排班 // 若 operators 不为空,将仅考虑单干员效率,而不考虑整个组合效率 - // 注意可能和后面自定义的干员产生冲突,比如把后面需要的干员拿到这里用了,请谨慎使用,或将 auto 的房间顺序放到最后 + // 注意可能和后面自定义的干员产生冲突,比如把后面需要的干员拿到这里用了,请谨慎使用,或将 autofill 的房间顺序放到最后 "product": "battle_record" // 当前制造产物,可选。 // 若识别到当前设施与作业中设置的产物不符合,界面会弹个红色字样提示,以后可能有更多作用 }, @@ -66,7 +66,7 @@ "多萝西" ], "candidates": [ // 备选干员,可选。这里面的有谁用谁,选满为止 - // 与 auto=true 不兼容,即该数组不为空时,auto 需要为 false + // 与 autofill=true 不兼容,即该数组不为空时,autofill 需要为 false "星源", "白面鸮", "赫默" @@ -75,7 +75,7 @@ ], "meeting": [ { - "auto": true // 这个房间全部 auto + "autofill": true // 这个房间全部 autofill } ] } diff --git a/src/MeoAssistant/AsstInfrastDef.h b/src/MeoAssistant/AsstInfrastDef.h index 18cf902ad8..d3d8e93671 100644 --- a/src/MeoAssistant/AsstInfrastDef.h +++ b/src/MeoAssistant/AsstInfrastDef.h @@ -113,17 +113,12 @@ namespace asst::infrast bool allow_external = false; // 当干员数没满3个的时候,是否允许补充外部干员 }; - enum class WorkMode + struct CustomRoomConfig { - Invalid = -1, - Gentle, // 温和换班模式: - // 会对干员人数不满的设施进行换班,计算单设施内最优解,尽量不破坏原有的干员组合; - // 即若设施内干员是满的,则不对该设施进行换班 - Aggressive, // 激进换班模式: - // 会对每一个设施进行换班,计算单设施内最优解,但不会将其他设施中的干员替换过来; - // 即按工作状态排序,仅选择前面的干员 - Extreme // 偏激换班模式: - // 会对每一个设施进行换班,计算全局的单设施内最优解,为追求更高效率,会将其他设施内的干员也替换过来; - // 即按技能排序,计算所有拥有该设施技能的干员效率,无论他在不在其他地方工作 + std::vector names; + bool autofill = false; + std::string product; + std::vector candidates; }; + using CustomFacilityConfig = std::vector; } // namespace asst::infrast diff --git a/src/MeoAssistant/InfrastAbstractTask.cpp b/src/MeoAssistant/InfrastAbstractTask.cpp index 80be6d0052..16659d08ff 100644 --- a/src/MeoAssistant/InfrastAbstractTask.cpp +++ b/src/MeoAssistant/InfrastAbstractTask.cpp @@ -6,9 +6,11 @@ #include "AsstMsg.h" #include "Controller.h" #include "InfrastFacilityImageAnalyzer.h" +#include "InfrastOperImageAnalyzer.h" #include "Logger.hpp" #include "MatchImageAnalyzer.h" #include "OcrImageAnalyzer.h" +#include "OcrWithPreprocessImageAnalyzer.h" #include "ProcessTask.h" #include "TaskData.h" @@ -18,26 +20,6 @@ asst::InfrastAbstractTask::InfrastAbstractTask(AsstCallback callback, void* call m_retry_times = TaskRetryTimes; } -asst::InfrastAbstractTask& asst::InfrastAbstractTask::set_work_mode(infrast::WorkMode work_mode) noexcept -{ - m_work_mode = work_mode; - switch (work_mode) { - case infrast::WorkMode::Gentle: - m_work_mode_name = "Gentle"; - break; - case infrast::WorkMode::Aggressive: - m_work_mode_name = "Aggressive"; - break; - case infrast::WorkMode::Extreme: - m_work_mode_name = "Extreme"; - break; - default: - m_work_mode_name.clear(); - break; - } - return *this; -} - asst::InfrastAbstractTask& asst::InfrastAbstractTask::set_mood_threshold(double mood_thres) noexcept { m_mood_threshold = mood_thres; @@ -71,6 +53,18 @@ std::string asst::InfrastAbstractTask::facility_name() const return m_facility_name_cache; } +void asst::InfrastAbstractTask::set_custom_config(infrast::CustomFacilityConfig config) noexcept +{ + m_custom_config = std::move(config); + m_is_custom = true; +} + +void asst::InfrastAbstractTask::clear_custom_config() noexcept +{ + m_is_custom = false; + m_custom_config.clear(); +} + bool asst::InfrastAbstractTask::on_run_fails() { LogTraceFunction; @@ -97,6 +91,15 @@ bool asst::InfrastAbstractTask::enter_facility(int index) } m_cur_facility_index = index; + if (is_use_custom_config()) { + if (m_cur_facility_index < m_custom_config.size()) { + m_current_room_custom_config = m_custom_config.at(m_cur_facility_index); + } + else { + Log.warn("tab size is lager than config size", m_cur_facility_index, m_custom_config.size()); + return false; + } + } callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("EnterFacility")); m_ctrler->click(rect); @@ -130,6 +133,15 @@ void asst::InfrastAbstractTask::async_swipe_of_operlist(bool reverse) } } +bool asst::InfrastAbstractTask::is_use_custom_config() +{ + if (!m_is_custom) { + return false; + } + return m_current_room_custom_config.names.empty() && m_current_room_custom_config.candidates.empty() && + m_current_room_custom_config.autofill; +} + void asst::InfrastAbstractTask::await_swipe() { LogTraceFunction; @@ -139,6 +151,63 @@ void asst::InfrastAbstractTask::await_swipe() sleep(extra_delay); } +bool asst::InfrastAbstractTask::swipe_and_select_opers_by_name(std::vector& opers_name) +{ + LogTraceFunction; + + while (!opers_name.empty()) { + if (need_exit()) { + return false; + } + if (select_opers_by_name(opers_name)) { + return false; + } + swipe_of_operlist(); + } + + return opers_name.empty(); +} + +bool asst::InfrastAbstractTask::select_opers_by_name(std::vector& opers_name) +{ + LogTraceFunction; + + if (opers_name.empty()) { + Log.warn("opers_name is empty"); + return false; + } + + const auto image = m_ctrler->get_image(); + InfrastOperImageAnalyzer oper_analyzer(image); + oper_analyzer.set_to_be_calced(InfrastOperImageAnalyzer::ToBeCalced::Smiley & + InfrastOperImageAnalyzer::ToBeCalced::Selected); + if (!oper_analyzer.analyze()) { + Log.warn("No oper"); + return false; + } + OcrWithPreprocessImageAnalyzer name_analyzer; + name_analyzer.set_replace(Task.get("CharsNameOcrReplace")->replace_map); + for (const auto& oper : oper_analyzer.get_result()) { + name_analyzer.set_image(oper.name_img); + if (!name_analyzer.analyze()) { + continue; + } + const std::string& name = name_analyzer.get_result().front().text; + auto iter = std::find(opers_name.begin(), opers_name.end(), name); + if (iter == opers_name.end()) { + continue; + } + if (!oper.selected) { + m_ctrler->click(oper.rect); + } + opers_name.erase(iter); + if (opers_name.empty()) { + break; + } + } + return true; +} + bool asst::InfrastAbstractTask::click_bottom_left_tab() { LogTraceFunction; diff --git a/src/MeoAssistant/InfrastAbstractTask.h b/src/MeoAssistant/InfrastAbstractTask.h index 7682de57e5..5fdf243651 100644 --- a/src/MeoAssistant/InfrastAbstractTask.h +++ b/src/MeoAssistant/InfrastAbstractTask.h @@ -11,7 +11,6 @@ namespace asst InfrastAbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain); virtual ~InfrastAbstractTask() override = default; - InfrastAbstractTask& set_work_mode(infrast::WorkMode work_mode) noexcept; InfrastAbstractTask& set_mood_threshold(double mood_thres) noexcept; virtual json::value basic_info() const override; @@ -19,6 +18,9 @@ namespace asst virtual size_t max_num_of_facilities() const noexcept { return 1ULL; } virtual size_t max_num_of_opers() const noexcept { return 1ULL; } + void set_custom_config(infrast::CustomFacilityConfig config) noexcept; + void clear_custom_config() noexcept; + static constexpr int OperSelectRetryTimes = 3; static constexpr int TaskRetryTimes = 3; @@ -34,6 +36,9 @@ namespace asst void swipe_of_operlist(bool reverse = false); void async_swipe_of_operlist(bool reverse = false); void await_swipe(); + bool is_use_custom_config(); + bool swipe_and_select_opers_by_name(std::vector& opers_name); + bool select_opers_by_name(std::vector& opers_name); virtual bool click_bottom_left_tab(); // 点击进入设施后,左下角的tab(我也不知道这玩意该叫啥) virtual bool click_clear_button(); // 点击干员选择页面的“清空选择”按钮 @@ -42,10 +47,13 @@ namespace asst virtual bool click_confirm_button(); // 点击干员选择页面的“确认”按钮 int m_last_swipe_id = 0; - infrast::WorkMode m_work_mode = infrast::WorkMode::Aggressive; - std::string m_work_mode_name = "Aggressive"; + const std::string m_work_mode_name = + "Aggressive"; // 历史遗留问题,之前是分工作模式的,后来发现其他模式都不好用,就全删了只保留了这一个 double m_mood_threshold = 0; mutable std::string m_facility_name_cache; int m_cur_facility_index = 0; + bool m_is_custom = false; + infrast::CustomFacilityConfig m_custom_config; + infrast::CustomRoomConfig m_current_room_custom_config; }; } diff --git a/src/MeoAssistant/InfrastControlTask.cpp b/src/MeoAssistant/InfrastControlTask.cpp index 09d2fa6c1b..c468c3650b 100644 --- a/src/MeoAssistant/InfrastControlTask.cpp +++ b/src/MeoAssistant/InfrastControlTask.cpp @@ -20,6 +20,17 @@ bool asst::InfrastControlTask::_run() } click_clear_button(); + if (is_use_custom_config()) { + bool name_select_ret = swipe_and_select_opers_by_name(m_current_room_custom_config.names); + if (name_select_ret) { + break; + } + else { + swipe_to_the_left_of_operlist(); + continue; + } + } + if (!opers_detect_with_swipe()) { return false; } diff --git a/src/MeoAssistant/InfrastDormTask.cpp b/src/MeoAssistant/InfrastDormTask.cpp index c8e265689b..668dcfdc2f 100644 --- a/src/MeoAssistant/InfrastDormTask.cpp +++ b/src/MeoAssistant/InfrastDormTask.cpp @@ -11,15 +11,15 @@ #include "ProcessTask.h" #include "TaskData.h" -asst::InfrastDormTask& asst::InfrastDormTask::set_notstationed_enabled(bool notstationed_enabled) noexcept +asst::InfrastDormTask& asst::InfrastDormTask::set_notstationed_enabled(bool dorm_notstationed_enabled) noexcept { - m_notstationed_enabled = notstationed_enabled; + m_dorm_notstationed_enabled = dorm_notstationed_enabled; return *this; } -asst::InfrastDormTask& asst::InfrastDormTask::set_trust_enabled(bool trust_enabled) noexcept +asst::InfrastDormTask& asst::InfrastDormTask::set_trust_enabled(bool drom_trust_enabled) noexcept { - m_trust_enabled = trust_enabled; + m_drom_trust_enabled = drom_trust_enabled; return *this; } @@ -37,8 +37,8 @@ bool asst::InfrastDormTask::_run() return false; } - Log.trace("m_notstationed_enabled:", m_notstationed_enabled); - if (m_notstationed_enabled && !m_if_filter_notstationed_haspressed) { + Log.trace("m_dorm_notstationed_enabled:", m_dorm_notstationed_enabled); + if (m_dorm_notstationed_enabled && !m_if_filter_notstationed_haspressed) { Log.trace("click_filter_menu_not_stationed_button"); click_filter_menu_not_stationed_button(); m_if_filter_notstationed_haspressed = true; @@ -46,12 +46,17 @@ bool asst::InfrastDormTask::_run() click_clear_button(); - opers_choose(); + if (is_use_custom_config()) { + swipe_and_select_opers_by_name(m_current_room_custom_config.names); + } + else { + opers_choose(); + } click_confirm_button(); click_return_button(); - if (m_finished_stage == 3) { // 不蹭信赖或所有干员满信赖 + if (m_next_step == NextStep::AllDone) { // 不蹭信赖或所有干员满信赖 break; } } @@ -91,7 +96,7 @@ bool asst::InfrastDormTask::opers_choose() switch (oper.smiley.type) { case infrast::SmileyType::Rest: // 如果所有心情不满的干员已经放入宿舍,就把信赖不满的干员放入宿舍 - if (m_trust_enabled && m_finished_stage > 0 && oper.selected == false && + if (m_drom_trust_enabled && m_next_step != NextStep::Rest && oper.selected == false && oper.doing != infrast::Doing::Working && oper.doing != infrast::Doing::Resting) { // 获得干员信赖值 OcrWithPreprocessImageAnalyzer trust_analyzer(oper.name_img); @@ -114,7 +119,7 @@ bool asst::InfrastDormTask::opers_choose() num_of_fulltrust++; } if (num_of_fulltrust >= 6) { // 所有干员都满信赖了 - m_finished_stage = 3; + m_next_step = NextStep::AllDone; Log.trace("num_of_fulltrust:", num_of_fulltrust, ", just return"); return true; } @@ -150,8 +155,8 @@ bool asst::InfrastDormTask::opers_choose() // 如果当前页面休息完成的人数超过5个,说明已经已经把所有心情不满的滑过一遍、没有更多的了 else if (++num_of_resting > max_num_of_opers()) { Log.trace("num_of_resting:", num_of_resting, ", dorm finished"); - if (m_trust_enabled) { - Log.trace("m_trust_enabled:", m_trust_enabled); + if (m_drom_trust_enabled) { + Log.trace("m_drom_trust_enabled:", m_drom_trust_enabled); if (!m_if_filter_notstationed_haspressed) { Log.trace("click_filter_menu_not_stationed_button"); click_filter_menu_not_stationed_button(); @@ -159,11 +164,11 @@ bool asst::InfrastDormTask::opers_choose() } Log.trace("click_sort_by_trust_button"); click_sort_by_trust_button(); - m_finished_stage = 1; // 选中未进驻标签并按信赖值排序 + m_next_step = NextStep::RestDone; // 选中未进驻标签并按信赖值排序 } else { - m_finished_stage = 3; - Log.trace("m_trust_enabled:", m_trust_enabled, ", just return"); + m_next_step = NextStep::AllDone; + Log.trace("m_drom_trust_enabled:", m_drom_trust_enabled, ", just return"); return true; } } @@ -183,22 +188,22 @@ bool asst::InfrastDormTask::opers_choose() break; } // 按信赖排序后需要重新识图,中断循环 - if (m_finished_stage == 1) { + if (m_next_step == NextStep::RestDone) { break; } } if (num_of_selected >= max_num_of_opers()) { Log.trace("num_of_selected:", num_of_selected, ", just break"); // 若当前宿舍已满人,则按信赖排序后不需要跳过滑动列表 - if (m_finished_stage == 1) { - m_finished_stage = 2; + if (m_next_step == NextStep::RestDone) { + m_next_step = NextStep::Trust; } break; } // 若当前宿舍未满人,则按信赖排序后需要跳过一次滑动列表 - if (m_finished_stage == 1) { - m_finished_stage = 2; + if (m_next_step == NextStep::RestDone) { + m_next_step = NextStep::Trust; } else { swipe_of_operlist(); diff --git a/src/MeoAssistant/InfrastDormTask.h b/src/MeoAssistant/InfrastDormTask.h index aabfce4f5f..61b67f8e89 100644 --- a/src/MeoAssistant/InfrastDormTask.h +++ b/src/MeoAssistant/InfrastDormTask.h @@ -11,8 +11,8 @@ namespace asst virtual size_t max_num_of_opers() const noexcept override { return 5ULL; } - InfrastDormTask& set_notstationed_enabled(bool notstationed_enabled) noexcept; - InfrastDormTask& set_trust_enabled(bool m_trust_enabled) noexcept; + InfrastDormTask& set_notstationed_enabled(bool dorm_notstationed_enabled) noexcept; + InfrastDormTask& set_trust_enabled(bool m_drom_trust_enabled) noexcept; private: virtual bool _run() override; @@ -20,19 +20,20 @@ namespace asst bool opers_choose(); - bool m_notstationed_enabled = false; // 设置是否启用未进驻筛选 - bool m_trust_enabled = true; // 设置是否启用蹭信赖 + bool m_dorm_notstationed_enabled = false; // 设置是否启用未进驻筛选 + bool m_drom_trust_enabled = true; // 设置是否启用蹭信赖 int m_cur_dorm_index = 0; int m_max_num_of_dorm = 4; - /* - * m_finished_stage - * 0:心情恢复阶段 - * 1:心情恢复完成 - * 2:蹭信赖阶段 - * 3:全部任务完成 - */ - int m_finished_stage = 0; + + enum class NextStep + { + Rest, + RestDone, + Trust, + AllDone, + }; + NextStep m_next_step = NextStep::Rest; bool m_if_filter_notstationed_haspressed = false; }; } diff --git a/src/MeoAssistant/InfrastOfficeTask.cpp b/src/MeoAssistant/InfrastOfficeTask.cpp index 41229e4e0b..51e8d2b8ca 100644 --- a/src/MeoAssistant/InfrastOfficeTask.cpp +++ b/src/MeoAssistant/InfrastOfficeTask.cpp @@ -22,40 +22,23 @@ bool asst::InfrastOfficeTask::_run() if (!opers_detect_with_swipe()) { return false; } - swipe_to_the_left_of_operlist(); - - auto find_iter = - ranges::find_if(m_all_available_opers, [&](const infrast::Oper& info) -> bool { return info.selected; }); - - bool need_shift = true; - if (find_iter != m_all_available_opers.end()) { - switch (m_work_mode) { - case infrast::WorkMode::Gentle: - // 如果之前有干员在,那就不换人,直接退出 - m_all_available_opers.erase(find_iter); - need_shift = false; - break; - case infrast::WorkMode::Aggressive: - need_shift = true; - // TODO,这里有个bug,全部干员中的selected,和当前的,不一定是同一个页面 - // 不过目前没影响,反正滑动到最前面了,selected的一定是在最前面 - // m_ctrler->click(find_iter->rect); - // sleep(300); - break; - case infrast::WorkMode::Extreme: // TODO - break; - default: + if (is_use_custom_config()) { + bool name_select_ret = swipe_and_select_opers_by_name(m_current_room_custom_config.names); + if (name_select_ret) { break; } - } - if (need_shift) { - optimal_calc(); - if (!opers_choose()) { - m_all_available_opers.clear(); + else { swipe_to_the_left_of_operlist(); continue; } } + + optimal_calc(); + if (!opers_choose()) { + m_all_available_opers.clear(); + swipe_to_the_left_of_operlist(); + continue; + } break; } click_confirm_button(); diff --git a/src/MeoAssistant/InfrastPowerTask.cpp b/src/MeoAssistant/InfrastPowerTask.cpp index 742302b609..afb6da6903 100644 --- a/src/MeoAssistant/InfrastPowerTask.cpp +++ b/src/MeoAssistant/InfrastPowerTask.cpp @@ -26,6 +26,17 @@ bool asst::InfrastPowerTask::_run() } for (int j = 0; j <= OperSelectRetryTimes; ++j) { + if (is_use_custom_config()) { + bool name_select_ret = swipe_and_select_opers_by_name(m_current_room_custom_config.names); + if (name_select_ret) { + break; + } + else { + swipe_to_the_left_of_operlist(); + continue; + } + } + if (m_all_available_opers.empty()) { if (!opers_detect_with_swipe()) { return false; @@ -35,36 +46,11 @@ bool asst::InfrastPowerTask::_run() else { opers_detect(); } - - auto find_iter = ranges::find_if(m_all_available_opers, std::mem_fn(&infrast::Oper::selected)); - bool need_shift = true; - if (find_iter != m_all_available_opers.end()) { - switch (m_work_mode) { - case infrast::WorkMode::Gentle: - // 如果之前有干员在,那就不换人,直接退出 - m_all_available_opers.erase(find_iter); - need_shift = false; - break; - case infrast::WorkMode::Aggressive: - need_shift = true; - // TODO,这里有个bug,全部干员中的selected,和当前的,不一定是同一个页面 - // 不过目前没影响,反正滑动到最前面了,selected的一定是在最前面 - // m_ctrler->click(find_iter->rect); - // sleep(300); - break; - case infrast::WorkMode::Extreme: // TODO - break; - default: - break; - } - } - if (need_shift) { - optimal_calc(); - if (!opers_choose()) { - m_all_available_opers.clear(); - swipe_to_the_left_of_operlist(); - continue; - } + optimal_calc(); + if (!opers_choose()) { + m_all_available_opers.clear(); + swipe_to_the_left_of_operlist(); + continue; } break; } diff --git a/src/MeoAssistant/InfrastProductionTask.cpp b/src/MeoAssistant/InfrastProductionTask.cpp index 22b5bb592c..5fd581a0dc 100644 --- a/src/MeoAssistant/InfrastProductionTask.cpp +++ b/src/MeoAssistant/InfrastProductionTask.cpp @@ -60,6 +60,15 @@ bool asst::InfrastProductionTask::shift_facility_list() } if (m_cur_facility_index != 0) { callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("EnterFacility")); + if (is_use_custom_config()) { + if (m_cur_facility_index < m_custom_config.size()) { + m_current_room_custom_config = m_custom_config.at(m_cur_facility_index); + } + else { + Log.warn("tab size is lager than config size", m_cur_facility_index, m_custom_config.size()); + break; + } + } } m_ctrler->click(tab); @@ -69,22 +78,17 @@ bool asst::InfrastProductionTask::shift_facility_list() const auto image = m_ctrler->get_image(); add_analyzer.set_image(image); if (!add_analyzer.analyze()) { - Log.info("no add button, just continue"); + Log.error("no add button, just continue"); continue; } - auto& rect = add_analyzer.get_result().rect; - Rect add_button = rect; + Rect add_button = add_analyzer.get_result().rect; auto& rect_move = add_task_ptr->rect_move; if (!rect_move.empty()) { - add_button.x += rect_move.x; - add_button.y += rect_move.y; - add_button.width = rect_move.width; - add_button.height = rect_move.height; + add_button = add_button.move(rect_move); } /* 识别当前正在造什么 */ MatchImageAnalyzer product_analyzer(image); - auto& all_products = InfrastData.get_facility_info(facility_name()).products; std::string cur_product = all_products.at(0); double max_score = 0; @@ -118,6 +122,17 @@ bool asst::InfrastProductionTask::shift_facility_list() } click_clear_button(); + if (is_use_custom_config()) { + bool name_select_ret = swipe_and_select_opers_by_name(m_current_room_custom_config.names); + if (name_select_ret) { + break; + } + else { + swipe_to_the_left_of_operlist(2); + continue; + } + } + if (m_all_available_opers.empty()) { if (!opers_detect_with_swipe()) { return false; @@ -456,11 +471,8 @@ bool asst::InfrastProductionTask::opers_choose() return false; } const auto image = m_ctrler->get_image(); - InfrastOperImageAnalyzer oper_analyzer(image); - oper_analyzer.set_facility(facility_name()); - if (!oper_analyzer.analyze()) { return false; } @@ -615,4 +627,4 @@ bool asst::InfrastProductionTask::facility_list_detect() } return true; -} \ No newline at end of file +} diff --git a/src/MeoAssistant/InfrastTask.cpp b/src/MeoAssistant/InfrastTask.cpp index d8c0399af7..66253df2b9 100644 --- a/src/MeoAssistant/InfrastTask.cpp +++ b/src/MeoAssistant/InfrastTask.cpp @@ -35,6 +35,9 @@ asst::InfrastTask::InfrastTask(const AsstCallback& callback, void* callback_arg) bool asst::InfrastTask::set_params(const json::value& params) { + int mode = params.get("mode", 0); + bool is_custom = static_cast(mode) == Mode::Custom; + if (!m_running) { auto facility_opt = params.find("facility"); if (!facility_opt) { @@ -86,28 +89,105 @@ bool asst::InfrastTask::set_params(const json::value& params) } } - std::string drones = params.get("drones", "_NotUse"); - m_mfg_task_ptr->set_uses_of_drone(drones); - m_trade_task_ptr->set_uses_of_drone(drones); + if (!is_custom) { + std::string drones = params.get("drones", "_NotUse"); + m_mfg_task_ptr->set_uses_of_drone(drones); + m_trade_task_ptr->set_uses_of_drone(drones); - double threshold = params.get("threshold", 0.3); - m_info_task_ptr->set_mood_threshold(threshold); - m_mfg_task_ptr->set_mood_threshold(threshold); - m_trade_task_ptr->set_mood_threshold(threshold); - m_power_task_ptr->set_mood_threshold(threshold); - m_control_task_ptr->set_mood_threshold(threshold); - m_reception_task_ptr->set_mood_threshold(threshold); - m_office_task_ptr->set_mood_threshold(threshold); - m_dorm_task_ptr->set_mood_threshold(threshold); + double threshold = params.get("threshold", 0.3); + m_info_task_ptr->set_mood_threshold(threshold); + m_mfg_task_ptr->set_mood_threshold(threshold); + m_trade_task_ptr->set_mood_threshold(threshold); + m_power_task_ptr->set_mood_threshold(threshold); + m_control_task_ptr->set_mood_threshold(threshold); + m_reception_task_ptr->set_mood_threshold(threshold); + m_office_task_ptr->set_mood_threshold(threshold); + m_dorm_task_ptr->set_mood_threshold(threshold); + } - bool notstationed_enabled = params.get("notstationed_enabled", false); - m_dorm_task_ptr->set_notstationed_enabled(notstationed_enabled); + bool dorm_notstationed_enabled = params.get("dorm_notstationed_enabled", false); + m_dorm_task_ptr->set_notstationed_enabled(dorm_notstationed_enabled); - bool trust_enabled = params.get("trust_enabled", true); - m_dorm_task_ptr->set_trust_enabled(trust_enabled); + bool drom_trust_enabled = params.get("drom_trust_enabled", true); + m_dorm_task_ptr->set_trust_enabled(drom_trust_enabled); bool replenish = params.get("replenish", false); m_replenish_task_ptr->set_enable(replenish); + if (is_custom && !m_running) { + std::string filename = params.at("filename").as_string(); + int index = params.at("index").as_integer(); + + return parse_and_set_custom_config(utils::path(filename), index); + } + + return true; +} + +bool asst::InfrastTask::parse_and_set_custom_config(const std::filesystem::path& path, int index) +{ + LogTraceFunction; + + auto custom_json_opt = json::open(path); + if (!custom_json_opt) { + Log.error("custom infrast file not exists", path); + return false; + } + auto& custom_json = custom_json_opt.value(); + Log.trace(__FUNCTION__, "| custom json:", custom_json.to_string()); + + auto& all_plans = custom_json.at("plans").as_array(); + if (index < 0 || index >= all_plans.size()) { + Log.error("index is out of range, plans size:", all_plans.size(), ", index:", index); + return false; + } + + for (const auto& [facility, facility_info] : custom_json.at("rooms").as_object()) { + infrast::CustomFacilityConfig facility_config; + + for (const auto& room_info : facility_info.as_array()) { + infrast::CustomRoomConfig room_config; + room_config.autofill = room_info.get("autofill", false); + room_config.product = room_info.get("product", std::string()); + if (auto opers_opt = room_info.find("operators")) { + for (const auto& oper_name : opers_opt.value()) { + room_config.names.emplace_back(oper_name.as_string()); + } + } + if (auto candidates_opt = room_info.find("candidates")) { + for (const auto& candidate_name : candidates_opt.value()) { + room_config.candidates.emplace_back(candidate_name.as_string()); + } + } + facility_config.emplace_back(std::move(room_config)); + } + + if (facility == "control") { + m_control_task_ptr->set_custom_config(facility_config); + } + else if (facility == "manufacture") { + m_mfg_task_ptr->set_custom_config(facility_config); + } + else if (facility == "trading") { + m_trade_task_ptr->set_custom_config(facility_config); + } + else if (facility == "power") { + m_power_task_ptr->set_custom_config(facility_config); + } + else if (facility == "meeting") { + m_reception_task_ptr->set_custom_config(facility_config); + } + else if (facility == "hire") { + m_office_task_ptr->set_custom_config(facility_config); + } + else if (facility == "dormitory") { + m_dorm_task_ptr->set_custom_config(facility_config); + } + else { + Log.error(__FUNCTION__, "unknown facility", facility); + return false; + } + } + return true; } diff --git a/src/MeoAssistant/InfrastTask.h b/src/MeoAssistant/InfrastTask.h index 20b1e47ae1..bc63d89099 100644 --- a/src/MeoAssistant/InfrastTask.h +++ b/src/MeoAssistant/InfrastTask.h @@ -16,7 +16,12 @@ namespace asst class InfrastTask final : public PackageTask { - public: + enum class Mode + { + Default = 0, + Custom = 10000, + }; + public: InfrastTask(const AsstCallback& callback, void* callback_arg); virtual ~InfrastTask() override = default; @@ -26,6 +31,8 @@ namespace asst static constexpr const char* TaskType = "Infrast"; private: + bool parse_and_set_custom_config(const std::filesystem::path& path, int index); + std::shared_ptr m_infrast_begin_task_ptr = nullptr; std::shared_ptr m_info_task_ptr = nullptr; std::shared_ptr m_mfg_task_ptr = nullptr; diff --git a/src/MeoAsstGui/Helper/AsstProxy.cs b/src/MeoAsstGui/Helper/AsstProxy.cs index 0992a3f14f..b1f4f5126f 100644 --- a/src/MeoAsstGui/Helper/AsstProxy.cs +++ b/src/MeoAsstGui/Helper/AsstProxy.cs @@ -1242,10 +1242,10 @@ namespace MeoAsstGui /// /// 宿舍进驻心情阈值。 /// 宿舍是否使用未进驻筛选标签 - /// 宿舍是否使用蹭信赖功能 + /// 宿舍是否使用蹭信赖功能 /// 制造站搓玉是否补货 /// 是否成功。 - public bool AsstAppendInfrast(string[] order, string uses_of_drones, double dorm_threshold, bool dorm_filter_not_stationed_enabled, bool dorm_trust_enabled, bool originium_shard_auto_replenishment) + public bool AsstAppendInfrast(string[] order, string uses_of_drones, double dorm_threshold, bool dorm_filter_not_stationed_enabled, bool dorm_drom_trust_enabled, bool originium_shard_auto_replenishment) { var task_params = new JObject(); @@ -1253,8 +1253,8 @@ namespace MeoAsstGui task_params["facility"] = new JArray(order); task_params["drones"] = uses_of_drones; task_params["threshold"] = dorm_threshold; - task_params["notstationed_enabled"] = dorm_filter_not_stationed_enabled; - task_params["trust_enabled"] = dorm_trust_enabled; + task_params["dorm_notstationed_enabled"] = dorm_filter_not_stationed_enabled; + task_params["drom_trust_enabled"] = dorm_drom_trust_enabled; task_params["replenish"] = originium_shard_auto_replenishment; TaskId id = AsstAppendTaskWithEncoding("Infrast", task_params); _latestTaskId[TaskType.Infrast] = id;