diff --git a/3rdparty/include/zlib/decompress.hpp b/3rdparty/include/zlib/decompress.hpp index 03cb216b6e..552fd658c2 100644 --- a/3rdparty/include/zlib/decompress.hpp +++ b/3rdparty/include/zlib/decompress.hpp @@ -20,9 +20,7 @@ namespace gzip {} template - void decompress(OutputType& output, - const uchar* data, - std::size_t size) const + void decompress(OutputType& output, const char* data, std::size_t size) const { z_stream inflate_s; @@ -68,7 +66,8 @@ namespace gzip std::size_t resize_to = size_uncompressed + 2 * size; if (resize_to > max_) { inflateEnd(&inflate_s); - throw std::runtime_error("size of output string will use more memory then intended when decompressing"); + throw std::runtime_error( + "size of output string will use more memory then intended when decompressing"); } output.resize(resize_to); inflate_s.avail_out = static_cast(2 * size); @@ -77,7 +76,7 @@ namespace gzip if (ret != Z_STREAM_END && ret != Z_OK && ret != Z_BUF_ERROR) { std::string error_msg = inflate_s.msg; inflateEnd(&inflate_s); - //throw std::runtime_error(error_msg); + // throw std::runtime_error(error_msg); output.clear(); return; } @@ -89,10 +88,10 @@ namespace gzip } }; - inline std::vector decompress(const uchar* data, std::size_t size) + inline std::string decompress(const char* data, std::size_t size) { Decompressor decomp; - std::vector output; + std::string output; decomp.decompress(output, data, size); return output; } diff --git a/src/MeoAssistant/AbstractImageAnalyzer.cpp b/src/MeoAssistant/AbstractImageAnalyzer.cpp index 3e9abf52a3..d25f5e3b9f 100644 --- a/src/MeoAssistant/AbstractImageAnalyzer.cpp +++ b/src/MeoAssistant/AbstractImageAnalyzer.cpp @@ -68,10 +68,7 @@ asst::Rect asst::AbstractImageAnalyzer::empty_rect_to_full(const Rect& rect, con bool asst::AbstractImageAnalyzer::save_img() { std::string stem = utils::get_format_time(); - stem = utils::string_replace_all_batch(stem, { - { ":", "-" }, - { " ", "_" }, - }); + stem = utils::string_replace_all(stem, { { ":", "-" }, { " ", "_" } }); std::filesystem::create_directory("debug"); bool ret = cv::imwrite("debug/" + stem + "_raw.png", m_image); diff --git a/src/MeoAssistant/AbstractTask.cpp b/src/MeoAssistant/AbstractTask.cpp index 89042e9433..8a3c1abad0 100644 --- a/src/MeoAssistant/AbstractTask.cpp +++ b/src/MeoAssistant/AbstractTask.cpp @@ -191,7 +191,7 @@ void asst::AbstractTask::click_return_button() void asst::AbstractTask::save_image() { std::string stem = utils::get_format_time(); - stem = utils::string_replace_all_batch(stem, { { ":", "-" }, { " ", "_" } }); + stem = utils::string_replace_all(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 74e28db78a..0eaaf4c9ff 100644 --- a/src/MeoAssistant/AbstractTask.h +++ b/src/MeoAssistant/AbstractTask.h @@ -55,7 +55,7 @@ namespace asst int get_task_id() const noexcept { return m_task_id; } virtual json::value basic_info() const; - constexpr static int RetryTimesDefault = 20; + static constexpr int RetryTimesDefault = 20; protected: virtual bool _run() = 0; diff --git a/src/MeoAssistant/AsstHttp.hpp b/src/MeoAssistant/AsstHttp.hpp index 2d6946728d..84ab58c24f 100644 --- a/src/MeoAssistant/AsstHttp.hpp +++ b/src/MeoAssistant/AsstHttp.hpp @@ -22,17 +22,15 @@ namespace asst::http bool _analyze_status_line(std::string_view status_line) { size_t _word_count = 0; - for (const std::string_view& word : views::split(status_line, ' ') | views::transform([](auto str_range) { - return utils::view_cast(str_range); - })) { + for (const auto& word : utils::string_split(status_line, " ")) { ++_word_count; if (_word_count == 1) { static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; - if (!accepted_protocol_version.contains(utils::view_cast(word))) { - m_last_error = "unsupport protocol version"; + if (!accepted_protocol_version.contains(word)) { + m_last_error = "unsupported protocol version`" + std::string(word) + "`"; return false; } - m_protocol_version = utils::view_cast(word); + m_protocol_version = word; } else if (_word_count == 2) { if (word.length() != 3) { @@ -75,32 +73,25 @@ namespace asst::http requires std::is_constructible_v Response(Args&&... args) : std::string(std::forward(args)...) { + std::string_view this_view = *this; bool _is_status_line = true; - // 这里的 \r\n 处理很奇怪,因为 views::split 好像不支持 string,只能 char - for (const auto& line : views::split(*this, '\n')) { - std::string_view line_view; - if (utils::view_cast(line).ends_with('\r')) { - line_view = utils::view_cast(line | views::take(line.size() - 1)); - } - else { - line_view = utils::view_cast(line); - } + for (const auto& line : utils::string_split(this_view, "\r\n")) { // status if (_is_status_line) { - if (!_analyze_status_line(line_view)) { + if (!_analyze_status_line(line)) { return; } _is_status_line = false; } // headers - else if (!line_view.empty()) { - if (!_analyze_headers_line(line_view)) { + else if (!line.empty()) { + if (!_analyze_headers_line(line)) { return; } } // data else { - m_data = std::string_view(line.begin(), this->end()); + m_data = std::string_view(line.begin(), this_view.end()); return; } } diff --git a/src/MeoAssistant/AsstTypes.h b/src/MeoAssistant/AsstTypes.h index 90bc47c885..9497047332 100644 --- a/src/MeoAssistant/AsstTypes.h +++ b/src/MeoAssistant/AsstTypes.h @@ -22,10 +22,10 @@ namespace asst { constexpr double DoubleDiff = 1e-12; - constexpr static int WindowWidthDefault = 1280; - constexpr static int WindowHeightDefault = 720; + static constexpr int WindowWidthDefault = 1280; + static constexpr int WindowHeightDefault = 720; - constexpr static double TemplThresholdDefault = 0.8; + static constexpr double TemplThresholdDefault = 0.8; struct Point { diff --git a/src/MeoAssistant/AsstUtils.hpp b/src/MeoAssistant/AsstUtils.hpp index b4417dc756..6c3ab5afef 100644 --- a/src/MeoAssistant/AsstUtils.hpp +++ b/src/MeoAssistant/AsstUtils.hpp @@ -22,79 +22,255 @@ #include #endif +// delete instantiation of template with message, when static_assert(false, Message) does not work +#define ASST_STATIC_ASSERT_FALSE(Message, ...) static_assert(::asst::utils::always_false<__VA_ARGS__>, Message); + namespace asst::utils { -// delete instantiation of template with message, when static_assert(false, Message) does not work -#define ASST_STATIC_ASSERT_FALSE(Message, ...) \ - static_assert(::asst::utils::integral_constant_at_template_instantiation::value, Message) - template - struct integral_constant_at_template_instantiation : std::integral_constant - {}; + template constexpr bool always_false = false; template requires ranges::range && ranges::range - dst_t view_cast(const src_t& src) + dst_t view_cast(src_t&& src) { return dst_t(src.begin(), src.end()); } - inline void _string_replace_all(std::string& str, const std::string_view& old_value, - const std::string_view& new_value) + template + using pair_of_string_view = std::pair, std::basic_string_view>; + + template + inline void _string_replace_all(std::basic_string& str, std::basic_string_view old_value, + std::basic_string_view new_value) { - for (std::string::size_type pos(0); pos != std::string::npos; pos += new_value.length()) { - if ((pos = str.find(old_value, pos)) != std::string::npos) + for (typename std::basic_string::size_type pos(0); pos != str.npos; pos += new_value.length()) { + if ((pos = str.find(old_value, pos)) != str.npos) str.replace(pos, old_value.length(), new_value); else break; } } - inline std::string string_replace_all(const std::string& src, const std::string_view& old_value, - const std::string_view& new_value) + template + requires std::convertible_to> && + std::convertible_to> + inline void _string_replace_all(std::basic_string& str, old_value_t&& old_value, new_value_t&& new_value) { - std::string str = src; - _string_replace_all(str, old_value, new_value); + _string_replace_all(str, { old_value }, { new_value }); + } + + template + inline void _string_replace_all(std::basic_string& str, const pair_of_string_view& replace_pair) + { + _string_replace_all(str, replace_pair.first, replace_pair.second); + } + + template + requires std::convertible_to> && + std::convertible_to> + inline std::basic_string string_replace_all(const std::basic_string& src, old_value_t&& old_value, + new_value_t&& new_value) + { + std::basic_string str = src; + _string_replace_all(str, { old_value }, { new_value }); return str; } - inline std::string string_replace_all_batch( - const std::string& src, std::initializer_list>&& replace_pairs) + template + inline std::basic_string string_replace_all(const std::basic_string& src, + const pair_of_string_view& replace_pair) { - std::string str = src; + std::basic_string str = src; + _string_replace_all(str, replace_pair); + return str; + } + + template + inline std::basic_string string_replace_all( + const std::basic_string& src, std::initializer_list>&& replace_pairs) + { + std::basic_string str = src; for (const auto& [old_value, new_value] : replace_pairs) { _string_replace_all(str, old_value, new_value); } return str; } - template - inline std::string string_replace_all_batch(const std::string& src, const map_t& replace_pairs) - requires std::derived_from && - std::derived_from + template + requires std::derived_from> && + std::derived_from> + [[deprecated]] inline std::basic_string string_replace_all(const std::basic_string& src, + const map_t& replace_pairs) { - std::string str = src; + std::basic_string str = src; for (const auto& [old_value, new_value] : replace_pairs) { _string_replace_all(str, old_value, new_value); } return str; } - inline std::vector string_split(const std::string& str, const std::string& delimiter) + // 延迟求值的 string_split,分隔符可以为字符或字符串 + template + class string_split_view : public ranges::view_interface> { - std::string::size_type pos1 = 0; - std::string::size_type pos2 = str.find(delimiter); - std::vector result; + private: + using base_string_view = std::basic_string_view; + using base_string = std::basic_string; + using string_iter = typename base_string_view::const_iterator; + base_string_view _rng {}; + base_string_view _pat {}; + base_string_view _nxt {}; - while (std::string::npos != pos2) { - result.emplace_back(str.substr(pos1, pos2 - pos1)); + class _iterator + { + private: + string_split_view* _pre = nullptr; + string_iter _cur = {}; + base_string_view _nxt = {}; + bool _trailing_empty = false; - pos1 = pos2 + delimiter.size(); - pos2 = str.find(delimiter, pos1); + public: + using iterator_concept = std::forward_iterator_tag; + using iterator_category = std::input_iterator_tag; + using value_type = base_string_view; + using difference_type = typename base_string_view::difference_type; + + _iterator() = default; + + constexpr _iterator(string_split_view& prev, string_iter curr, base_string_view next) noexcept + : _pre { std::addressof(prev) }, _cur { std::move(curr) }, _nxt { std::move(next) } + {} + + [[nodiscard]] constexpr string_iter base() const noexcept { return _cur; } + + [[nodiscard]] constexpr value_type operator*() const noexcept { return { _cur, _nxt.cbegin() }; } + + constexpr _iterator& operator++() + { + const auto _end = _pre->_rng.cend(); + + if (_cur = _nxt.cbegin(); _cur == _end) { + _trailing_empty = false; + return *this; + } + + if (_cur = _nxt.cend(); _cur == _end) { + _trailing_empty = true; + _nxt = { _cur, _cur }; + return *this; + } + + if (size_t _len = _pre->_pat.length(); !_len) { + auto _beg = _cur + 1; + _nxt = { std::move(_beg), std::move(_beg) }; + } + else if (const auto _pos = base_string_view(_cur, _end).find(_pre->_pat); + _pos == base_string_view::npos) { + _nxt = { std::move(_end), std::move(_end) }; + } + else { + auto _beg = _cur + _pos; + _nxt = { std::move(_beg), _beg + _pre->_pat.length() }; + } + + return *this; + } + + constexpr _iterator operator++(int) + { + auto _tmp = *this; + ++*this; + return _tmp; + } + + friend constexpr bool operator==(const _iterator& _lhs, const _iterator& _rhs) noexcept + { + return _lhs._cur == _rhs._cur && _lhs._trailing_empty == _rhs._trailing_empty; + } + }; + + public: + string_split_view() = default; + + template + requires std::convertible_to + constexpr string_split_view(rng_t&& rang, pat_t&& patt) noexcept + : _rng(std::forward(rang)), _pat(std::forward(patt)) + {} + + template + constexpr string_split_view(rng_t&& rang, const char_t& elem) noexcept + : _rng(std::forward(rang)), _pat(&elem, 1) + {} + + [[nodiscard]] constexpr const base_string_view& base() const noexcept { return _rng; } + [[nodiscard]] constexpr base_string_view&& base() noexcept { return std::move(_rng); } + + [[nodiscard]] constexpr auto begin() + { + const auto _beg = _rng.cbegin(), _end = _rng.cend(); + + if (_nxt.empty()) { + if (size_t _len = _pat.length(); !_len) { + auto _cur = _beg + 1; + _nxt = { std::move(_cur), std::move(_cur) }; + } + else if (const auto _pos = _rng.find(_pat); _pos == base_string_view::npos) { + _nxt = { std::move(_end), std::move(_end) }; + } + else { + auto _cur = _beg + _pos; + _nxt = { std::move(_cur), _cur + _pat.length() }; + } + } + return _iterator { *this, _beg, _nxt }; } - if (pos1 != str.length()) result.emplace_back(str.substr(pos1)); - return result; - } + [[nodiscard]] constexpr auto end() { return _iterator { *this, _rng.cend(), {} }; } + }; + + template + string_split_view(str_t, pat_t) -> string_split_view; + + template + string_split_view(str_t*, pat_t) -> string_split_view::type>; + + struct _string_split_fn + { + template + [[nodiscard]] constexpr auto operator()(str_t&& _str, pat_t&& _pat) const + noexcept(noexcept(string_split_view(std::forward(_str), std::forward(_pat)))) + requires requires { string_split_view(static_cast(_str), static_cast(_pat)); } + { + return string_split_view(std::forward(_str), std::forward(_pat)); + } + }; + + inline constexpr _string_split_fn string_split; + + // // 以低内存开销拆分一个字符串;注意当 src 析构后,返回值将失效 + // template + // requires std::convertible_to> && + // std::convertible_to> + // inline std::vector> string_split(const str_t& src, delimiter_t delimiter, + // size_t split_count = -1) + // { + // std::basic_string_view delimiter_view = delimiter; + // std::basic_string_view str = src; + // typename std::basic_string::size_type pos1 = 0; + // typename std::basic_string::size_type pos2 = str.find(delimiter_view); + // std::vector> result; + + // while (split_count-- && pos2 != str.npos) { + // result.emplace_back(str.substr(pos1, pos2 - pos1)); + + // pos1 = pos2 + delimiter_view.length(); + // pos2 = str.find(delimiter_view, pos1); + // } + // if (pos1 != str.length()) result.emplace_back(str.substr(pos1)); + + // return result; + // } inline std::string get_format_time() { @@ -235,15 +411,14 @@ namespace asst::utils ifs.close(); std::string str = iss.str(); - using uchar = unsigned char; - constexpr static uchar Bom_0 = 0xEF; - constexpr static uchar Bom_1 = 0xBB; - constexpr static uchar Bom_2 = 0xBF; + static constexpr char _Bom[] = { + static_cast(0xEF), + static_cast(0xBB), + static_cast(0xBF), + }; - if (str.size() >= 3 && static_cast(str.at(0)) == Bom_0 && static_cast(str.at(1)) == Bom_1 && - static_cast(str.at(2)) == Bom_2) { + if (str.starts_with(_Bom)) { str.assign(str.begin() + 3, str.end()); - return str; } return str; } @@ -301,8 +476,8 @@ namespace asst::utils CloseHandle(pipe_child_write); #else - constexpr static int PIPE_READ = 0; - constexpr static int PIPE_WRITE = 1; + static constexpr int PIPE_READ = 0; + static constexpr int PIPE_WRITE = 1; int pipe_in[2] = { 0 }; int pipe_out[2] = { 0 }; int pipe_in_ret = pipe(pipe_in); diff --git a/src/MeoAssistant/Controller.cpp b/src/MeoAssistant/Controller.cpp index 449f931700..ab7bb3b804 100644 --- a/src/MeoAssistant/Controller.cpp +++ b/src/MeoAssistant/Controller.cpp @@ -80,7 +80,7 @@ asst::Controller::Controller(AsstCallback callback, void* callback_arg) m_support_socket = false; #endif - m_pipe_buffer = std::make_unique(PipeBuffSize); + m_pipe_buffer = std::make_unique(PipeBuffSize); if (!m_pipe_buffer) { throw "controller pipe buffer allocated failed"; } @@ -222,14 +222,13 @@ void asst::Controller::pipe_working_proc() } } -std::optional> asst::Controller::call_command(const std::string& cmd, int64_t timeout, - bool recv_by_socket) +std::optional asst::Controller::call_command(const std::string& cmd, int64_t timeout, bool recv_by_socket) { using namespace std::chrono_literals; using namespace std::chrono; // LogTraceScope(std::string(__FUNCTION__) + " | `" + cmd + "`"); - std::vector pipe_data; + std::string pipe_data; auto start_time = steady_clock::now(); auto check_timeout = [&]() -> bool { @@ -331,8 +330,7 @@ std::optional> asst::Controller::call_command(const std::stri auto duration = duration_cast(steady_clock::now() - start_time).count(); if (!pipe_data.empty() && pipe_data.size() < 4096) { - Log.trace("Call `", cmd, "` ret", exit_ret, ", output:", std::string(pipe_data.cbegin(), pipe_data.cend()), - ", cost", duration, "ms"); + Log.trace("Call `", cmd, "` ret", exit_ret, ", output:", pipe_data, ", cost", duration, "ms"); } else { Log.trace("Call `", cmd, "` ret", exit_ret, ", output size:", pipe_data.size(), ", cost", duration, "ms"); @@ -356,7 +354,7 @@ std::optional> asst::Controller::call_command(const std::stri { "cmd", cmd }, } }, }; - constexpr static int ReconnectTimes = 20; + static constexpr int ReconnectTimes = 20; for (int i = 0; i < ReconnectTimes; ++i) { if (need_exit()) { break; @@ -368,9 +366,7 @@ std::optional> asst::Controller::call_command(const std::stri auto reconnect_ret = call_command(m_adb.connect, 60LL * 1000); bool is_reconnect_success = false; if (reconnect_ret) { - auto& reconnect_val = reconnect_ret.value(); - std::string reconnect_str(std::make_move_iterator(reconnect_val.begin()), - std::make_move_iterator(reconnect_val.end())); + auto& reconnect_str = reconnect_ret.value(); is_reconnect_success = reconnect_str.find("error") == std::string::npos; } if (is_reconnect_success) { @@ -401,14 +397,15 @@ std::optional> asst::Controller::call_command(const std::stri return std::nullopt; } -void asst::Controller::convert_lf(std::vector& data) +// 返回值代表是否找到 "\r\n",函数本身会将所有 "\r\n" 替换为 "\n" +bool asst::Controller::convert_lf(std::string& data) { LogTraceFunction; if (data.empty() || data.size() < 2) { - return; + return false; } - auto pred = [](const std::vector::iterator& cur) -> bool { return *cur == '\r' && *(cur + 1) == '\n'; }; + auto pred = [](const std::string::iterator& cur) -> bool { return *cur == '\r' && *(cur + 1) == '\n'; }; // find the first of "\r\n" auto first_iter = data.end(); for (auto iter = data.begin(); iter != data.end() - 1; ++iter) { @@ -418,7 +415,7 @@ void asst::Controller::convert_lf(std::vector& data) } } if (first_iter == data.end()) { - return; + return false; } // move forward all non-crlf elements auto end_r1_iter = data.end() - 1; @@ -432,6 +429,7 @@ void asst::Controller::convert_lf(std::vector& data) *next_iter = *end_r1_iter; ++next_iter; data.erase(next_iter, data.end()); + return true; } asst::Point asst::Controller::rand_point_in_rect(const Rect& rect) @@ -565,7 +563,7 @@ bool asst::Controller::screencap() // return true; // } - DecodeFunc decode_raw = [&](std::vector& data) -> bool { + DecodeFunc decode_raw = [&](std::string_view data) -> bool { if (data.empty()) { return false; } @@ -574,11 +572,11 @@ bool asst::Controller::screencap() return false; } size_t header_size = data.size() - std_size; - bool is_all_zero = std::all_of(data.data() + header_size, data.data() + std_size, std::logical_not {}); - if (is_all_zero) { + auto img_data = data.substr(header_size); + if (ranges::all_of(img_data, std::logical_not {})) { return false; } - cv::Mat temp(m_height, m_width, CV_8UC4, data.data() + header_size); + cv::Mat temp(m_height, m_width, CV_8UC4, const_cast(img_data.data())); if (temp.empty()) { return false; } @@ -588,33 +586,12 @@ bool asst::Controller::screencap() return true; }; - DecodeFunc decode_raw_with_gzip = [&](std::vector& data) -> bool { - auto unzip_data = gzip::decompress(data.data(), data.size()); - if (unzip_data.empty()) { - return false; - } - size_t std_size = 4ULL * m_width * m_height; - if (unzip_data.size() < std_size) { - return false; - } - size_t header_size = unzip_data.size() - std_size; - bool is_all_zero = - std::all_of(unzip_data.data() + header_size, unzip_data.data() + std_size, std::logical_not {}); - if (is_all_zero) { - return false; - } - cv::Mat temp(m_height, m_width, CV_8UC4, unzip_data.data() + header_size); - if (temp.empty()) { - return false; - } - cv::cvtColor(temp, temp, cv::COLOR_RGB2BGR); - std::unique_lock image_lock(m_image_mutex); - m_cache_image = temp; - return true; + DecodeFunc decode_raw_with_gzip = [&](std::string_view data) -> bool { + return decode_raw(gzip::decompress(data.data(), data.size())); }; - DecodeFunc decode_encode = [&](std::vector& data) -> bool { - cv::Mat temp = cv::imdecode(data, cv::IMREAD_COLOR); + DecodeFunc decode_encode = [&](std::string_view data) -> bool { + cv::Mat temp = cv::imdecode({ data.data(), int(data.size()) }, cv::IMREAD_COLOR); if (temp.empty()) { return false; } @@ -693,23 +670,28 @@ bool asst::Controller::screencap() bool asst::Controller::screencap(const std::string& cmd, const DecodeFunc& decode_func, bool by_socket) { - if ((!m_support_socket || !m_server_started) && by_socket) { + if ((!m_support_socket || !m_server_started) && by_socket) [[unlikely]] { return false; } auto ret = call_command(cmd, 20000, by_socket); - if (!ret || ret.value().empty()) { + if (!ret || ret.value().empty()) [[unlikely]] { Log.error("data is empty!"); return false; } - auto data = std::move(ret).value(); + auto& data = ret.value(); + bool tried_conversion = false; if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::CRLF) { - convert_lf(data); + tried_conversion = true; + if (!convert_lf(data)) [[unlikely]] { // 没找到 "\r\n" + Log.info("screencap_end_of_line is set to CRLF but no `\\r\\n` found, set it to LF"); + m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::LF; + } } - if (decode_func(data)) { + if (decode_func(data)) [[likely]] { if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) { Log.info("screencap_end_of_line is LF"); m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::LF; @@ -719,21 +701,30 @@ bool asst::Controller::screencap(const std::string& cmd, const DecodeFunc& decod else { Log.info("data is not empty, but image is empty"); - if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet || - m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::LF) { + if (!tried_conversion) { Log.info("try to cvt lf"); - convert_lf(data); + if (!convert_lf(data)) { // 没找到 "\r\n",data 没有变化,不必重试 + Log.error("skip retry decoding and decode failed!"); + return false; + } if (decode_func(data)) { + if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) { + Log.info("screencap_end_of_line is CRLF"); + } + else { + Log.info("screencap_end_of_line is changed to CRLF"); + } m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::CRLF; - Log.info("screencap_end_of_line is CRLF"); return true; } else { Log.error("convert lf and retry decode failed!"); } } - m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::UnknownYet; + else { // 已经转换过行尾,再次转换 data 不会变化,不必重试 + Log.error("skip retry decoding and decode failed!"); + } return false; } } @@ -802,8 +793,8 @@ int asst::Controller::click_without_scale(const Point& p, bool block) if (p.x < 0 || p.x >= m_width || p.y < 0 || p.y >= m_height) { Log.error("click point out of range"); } - std::string cur_cmd = utils::string_replace_all_batch( - m_adb.click, { { "[x]", std::to_string(p.x) }, { "[y]", std::to_string(p.y) } }); + std::string cur_cmd = + utils::string_replace_all(m_adb.click, { { "[x]", std::to_string(p.x) }, { "[y]", std::to_string(p.y) } }); int id = push_cmd(cur_cmd); if (block) { wait(id); @@ -848,20 +839,20 @@ int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int y1 = std::clamp(y1, 0, m_height - 1); } - std::string cur_cmd = utils::string_replace_all_batch( - m_adb.swipe, { - { "[x1]", std::to_string(x1) }, - { "[y1]", std::to_string(y1) }, - { "[x2]", std::to_string(x2) }, - { "[y2]", std::to_string(y2) }, - { "[duration]", duration <= 0 ? "" : std::to_string(duration) }, - }); + std::string cur_cmd = + utils::string_replace_all(m_adb.swipe, { + { "[x1]", std::to_string(x1) }, + { "[y1]", std::to_string(y1) }, + { "[x2]", std::to_string(x2) }, + { "[y2]", std::to_string(y2) }, + { "[duration]", duration <= 0 ? "" : std::to_string(duration) }, + }); int id = 0; // 额外的滑动:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来 const auto& opt = Configer.get_options(); if (extra_swipe && opt.adb_extra_swipe_duration > 0) { - std::string extra_cmd = utils::string_replace_all_batch( + std::string extra_cmd = utils::string_replace_all( m_adb.swipe, { { "[x1]", std::to_string(x2) }, { "[y1]", std::to_string(y2) }, @@ -925,20 +916,20 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a return false; } - const auto adb_cfg = std::move(adb_ret.value()); + const auto& adb_cfg = adb_ret.value(); std::string display_id; std::string nc_address = "10.0.2.2"; uint16_t nc_port = 0; // 里面的值每次执行命令后可能更新,所以要用 lambda 拿最新的 auto cmd_replace = [&](const std::string& cfg_cmd) -> std::string { - return utils::string_replace_all_batch(cfg_cmd, { - { "[Adb]", adb_path }, - { "[AdbSerial]", address }, - { "[DisplayId]", display_id }, - { "[NcPort]", std::to_string(nc_port) }, - { "[NcAddress]", nc_address }, - }); + return utils::string_replace_all(cfg_cmd, { + { "[Adb]", adb_path }, + { "[AdbSerial]", address }, + { "[DisplayId]", display_id }, + { "[NcPort]", std::to_string(nc_port) }, + { "[NcAddress]", nc_address }, + }); }; /* connect */ @@ -948,9 +939,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a // 端口即使错误,命令仍然会返回0,TODO 对connect_result进行判断 bool is_connect_success = false; if (connect_ret) { - auto& connect_val = connect_ret.value(); - std::string connect_str(std::make_move_iterator(connect_val.begin()), - std::make_move_iterator(connect_val.end())); + auto& connect_str = connect_ret.value(); is_connect_success = connect_str.find("error") == std::string::npos; } if (!is_connect_success) { @@ -975,8 +964,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a return false; } - auto& uuid_result = uuid_ret.value(); - std::string uuid_str(std::make_move_iterator(uuid_result.begin()), std::make_move_iterator(uuid_result.end())); + auto& uuid_str = uuid_ret.value(); std::erase(uuid_str, ' '); m_uuid = std::move(uuid_str); @@ -995,10 +983,8 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a return false; } - auto& display_id_result = display_id_ret.value(); - convert_lf(display_id_result); - std::string display_id_pipe_str(std::make_move_iterator(display_id_result.begin()), - std::make_move_iterator(display_id_result.end())); + auto& display_id_pipe_str = display_id_ret.value(); + convert_lf(display_id_pipe_str); auto last = display_id_pipe_str.rfind(':'); if (last == std::string::npos) { return false; @@ -1021,9 +1007,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a return false; } - auto& display_result = display_ret.value(); - std::string display_pipe_str(std::make_move_iterator(display_result.begin()), - std::make_move_iterator(display_result.end())); + auto& display_pipe_str = display_ret.value(); int size_value1 = 0; int size_value2 = 0; #ifdef _MSC_VER @@ -1118,9 +1102,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a // https://github.com/ArknightsAutoHelper/ArknightsAutoHelper/blob/master/automator/connector/ADBConnector.py#L436 auto nc_address_ret = call_command(cmd_replace(adb_cfg.nc_address)); if (nc_address_ret) { - auto& nc_result = nc_address_ret.value(); - std::string nc_result_str(std::make_move_iterator(nc_result.begin()), - std::make_move_iterator(nc_result.end())); + auto& nc_result_str = nc_address_ret.value(); if (auto pos = nc_result_str.find(' '); pos != std::string::npos) { nc_address = nc_result_str.substr(0, pos); } @@ -1185,7 +1167,7 @@ cv::Mat asst::Controller::get_image(bool raw) } // 有些模拟器adb偶尔会莫名其妙截图失败,多试几次 - constexpr static int MaxTryCount = 20; + static constexpr int MaxTryCount = 20; bool success = false; for (int i = 0; i < MaxTryCount && m_inited; ++i) { if (need_exit()) { diff --git a/src/MeoAssistant/Controller.h b/src/MeoAssistant/Controller.h index fe4fabd5ea..fcf0199943 100644 --- a/src/MeoAssistant/Controller.h +++ b/src/MeoAssistant/Controller.h @@ -52,7 +52,7 @@ namespace asst int click_without_scale(const Point& p, bool block = true); int click_without_scale(const Rect& rect, bool block = true); - constexpr static int SwipeExtraDelayDefault = 1000; + static constexpr int SwipeExtraDelayDefault = 1000; int swipe(const Point& p1, const Point& p2, int duration = 0, bool block = true, int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false); int swipe(const Rect& r1, const Rect& r2, int duration = 0, bool block = true, @@ -74,14 +74,14 @@ namespace asst private: bool need_exit() const; void pipe_working_proc(); - std::optional> call_command(const std::string& cmd, int64_t timeout = 20000, - bool recv_by_socket = false); + std::optional call_command(const std::string& cmd, int64_t timeout = 20000, + bool recv_by_socket = false); int push_cmd(const std::string& cmd); std::optional try_to_init_socket(const std::string& local_address, unsigned short try_port, unsigned short try_times = 10U); - using DecodeFunc = std::function&)>; + using DecodeFunc = std::function; bool screencap(); bool screencap(const std::string& cmd, const DecodeFunc& decode_func, bool by_nc = false); void clear_lf_info(); @@ -92,9 +92,9 @@ namespace asst void random_delay() const; void clear_info() noexcept; - // 转换 data 中所有的 crlf 为 lf:有些模拟器自带的 adb,exec-out 输出的 lf 会被替换成 crlf, + // 转换 data 中的 CRLF 为 LF:有些模拟器自带的 adb,exec-out 输出的 \n 会被替换成 \r\n, // 导致解码错误,所以这里转一下回来(点名批评 mumu 和雷电) - static void convert_lf(std::vector& data); + static bool convert_lf(std::string& data); bool* m_exit_flag = nullptr; AsstCallback m_callback; @@ -102,9 +102,9 @@ namespace asst std::minstd_rand m_rand_engine; - constexpr static int PipeBuffSize = 4 * 1024 * 1024; // 管道缓冲区大小 - constexpr static int SocketBuffSize = 4 * 1024 * 1024; // socket 缓冲区大小 - std::unique_ptr m_pipe_buffer = nullptr; + static constexpr int PipeBuffSize = 4 * 1024 * 1024; // 管道缓冲区大小 + static constexpr int SocketBuffSize = 4 * 1024 * 1024; // socket 缓冲区大小 + std::unique_ptr m_pipe_buffer = nullptr; std::mutex m_pipe_mutex; std::unique_ptr m_socket_buffer = nullptr; std::mutex m_socket_mutex; @@ -124,8 +124,8 @@ namespace asst ASST_AUTO_DEDUCED_ZERO_INIT_END #else - constexpr static int PIPE_READ = 0; - constexpr static int PIPE_WRITE = 1; + static constexpr int PIPE_READ = 0; + static constexpr int PIPE_WRITE = 1; int m_pipe_in[2] = { 0 }; int m_pipe_out[2] = { 0 }; int m_child = 0; diff --git a/src/MeoAssistant/DepotImageAnalyzer.h b/src/MeoAssistant/DepotImageAnalyzer.h index 2fd873ab1a..942b170f92 100644 --- a/src/MeoAssistant/DepotImageAnalyzer.h +++ b/src/MeoAssistant/DepotImageAnalyzer.h @@ -13,7 +13,7 @@ namespace asst class DepotImageAnalyzer final : public AbstractImageAnalyzer { public: - constexpr static size_t NPos = ~0ULL; + static constexpr size_t NPos = ~0ULL; public: using AbstractImageAnalyzer::AbstractImageAnalyzer; diff --git a/src/MeoAssistant/HashImageAnalyzer.cpp b/src/MeoAssistant/HashImageAnalyzer.cpp index 57a4a8b022..a6f146dc08 100644 --- a/src/MeoAssistant/HashImageAnalyzer.cpp +++ b/src/MeoAssistant/HashImageAnalyzer.cpp @@ -90,7 +90,7 @@ const std::vector& asst::HashImageAnalyzer::get_hash() const noexce std::string asst::HashImageAnalyzer::s_hash(const cv::Mat& img) { - constexpr static int HashKernelSize = 16; + static constexpr int HashKernelSize = 16; cv::Mat resized; cv::resize(img, resized, cv::Size(HashKernelSize, HashKernelSize)); if (img.channels() == 3) { @@ -155,7 +155,7 @@ cv::Mat asst::HashImageAnalyzer::bound_bin(const cv::Mat& bin) int asst::HashImageAnalyzer::hamming(std::string hash1, std::string hash2) { - constexpr static int HammingFlags = 64; + static constexpr int HammingFlags = 64; hash1.insert(hash1.begin(), HammingFlags - hash1.size(), '0'); hash2.insert(hash2.begin(), HammingFlags - hash2.size(), '0'); diff --git a/src/MeoAssistant/InfrastAbstractTask.h b/src/MeoAssistant/InfrastAbstractTask.h index 5462ec9d97..7682de57e5 100644 --- a/src/MeoAssistant/InfrastAbstractTask.h +++ b/src/MeoAssistant/InfrastAbstractTask.h @@ -19,8 +19,8 @@ namespace asst virtual size_t max_num_of_facilities() const noexcept { return 1ULL; } virtual size_t max_num_of_opers() const noexcept { return 1ULL; } - constexpr static int OperSelectRetryTimes = 3; - constexpr static int TaskRetryTimes = 3; + static constexpr int OperSelectRetryTimes = 3; + static constexpr int TaskRetryTimes = 3; protected: virtual bool on_run_fails() override; diff --git a/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.h b/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.h index 1f718f4f57..2eb214034f 100644 --- a/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.h +++ b/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.h @@ -11,7 +11,7 @@ namespace asst InfrastClueVacancyImageAnalyzer(const cv::Mat image, const Rect& roi) = delete; virtual bool analyze() override; - constexpr static int MaxNumOfClue = 7; + static constexpr int MaxNumOfClue = 7; void set_to_be_analyzed(std::vector to_be_analyzed) noexcept { diff --git a/src/MeoAssistant/InfrastOperImageAnalyzer.h b/src/MeoAssistant/InfrastOperImageAnalyzer.h index 8b34c94a08..ad9c7b0fae 100644 --- a/src/MeoAssistant/InfrastOperImageAnalyzer.h +++ b/src/MeoAssistant/InfrastOperImageAnalyzer.h @@ -35,7 +35,7 @@ namespace asst void set_facility(std::string facility) noexcept { m_facility = std::move(facility); } void set_to_be_calced(int to_be_calced) noexcept { m_to_be_calced = to_be_calced; } - constexpr static int MaxNumOfSkills = 2; // 单个干员最多有几个基建技能 + static constexpr int MaxNumOfSkills = 2; // 单个干员最多有几个基建技能 private: // 该分析器不支持外部设置ROI diff --git a/src/MeoAssistant/OcrPack.cpp b/src/MeoAssistant/OcrPack.cpp index a383f25360..76ce04ab8a 100644 --- a/src/MeoAssistant/OcrPack.cpp +++ b/src/MeoAssistant/OcrPack.cpp @@ -12,7 +12,7 @@ asst::OcrPack::OcrPack() { Log.info("hardware_concurrency:", std::thread::hardware_concurrency()); for (size_t i = 0; i != MaxBoxSize; ++i) { - constexpr static size_t MaxTextSize = 1024; + static constexpr size_t MaxTextSize = 1024; *(m_strs_buffer + i) = new char[MaxTextSize]; // memset(*(m_strs_buffer + i), 0, MaxTextSize); } diff --git a/src/MeoAssistant/OcrPack.h b/src/MeoAssistant/OcrPack.h index 19b8b78f77..ae37d3c805 100644 --- a/src/MeoAssistant/OcrPack.h +++ b/src/MeoAssistant/OcrPack.h @@ -15,7 +15,7 @@ namespace asst { class OcrPack final : public SingletonHolder, public AbstractResource { - constexpr static size_t MaxBoxSize = 128; + static constexpr size_t MaxBoxSize = 128; public: virtual ~OcrPack() override; diff --git a/src/MeoAssistant/RecruitConfiger.h b/src/MeoAssistant/RecruitConfiger.h index f17e386e20..6847865993 100644 --- a/src/MeoAssistant/RecruitConfiger.h +++ b/src/MeoAssistant/RecruitConfiger.h @@ -87,7 +87,7 @@ namespace asst { public: virtual ~RecruitConfiger() override = default; - constexpr static int CorrectNumberOfTags = 5; + static constexpr int CorrectNumberOfTags = 5; const std::unordered_set& get_all_tags() const noexcept { return m_all_tags; } const std::vector& get_all_opers() const noexcept { return m_all_opers; } diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 8ebe13c3f1..2e568b7231 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -129,7 +129,7 @@ asst::http::Response asst::ReportDataTask::escape_and_request(const std::string& { LogTraceFunction; - std::string body_escape = utils::string_replace_all_batch(m_body, { { "\"", "\\\"" } }); + std::string body_escape = utils::string_replace_all(m_body, { { "\"", "\\\"" } }); #ifdef _WIN32 std::string body_escapes = utils::utf8_to_unicode_escape(body_escape); @@ -138,7 +138,7 @@ asst::http::Response asst::ReportDataTask::escape_and_request(const std::string& #endif std::string cmd_line = - utils::string_replace_all_batch(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); + utils::string_replace_all(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); Log.info("request:\n", cmd_line); http::Response response = utils::callcmd(cmd_line); diff --git a/src/MeoAssistant/Resource.cpp b/src/MeoAssistant/Resource.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/MeoAssistant/StageDropsImageAnalyzer.cpp b/src/MeoAssistant/StageDropsImageAnalyzer.cpp index a0faf0a045..14d4347030 100644 --- a/src/MeoAssistant/StageDropsImageAnalyzer.cpp +++ b/src/MeoAssistant/StageDropsImageAnalyzer.cpp @@ -20,7 +20,7 @@ bool asst::StageDropsImageAnalyzer::analyze() #ifdef ASST_DEBUG std::string stem = utils::get_format_time(); - stem = utils::string_replace_all_batch(stem, { { ":", "-" }, { " ", "_" } }); + stem = utils::string_replace_all(stem, { { ":", "-" }, { " ", "_" } }); std::filesystem::create_directory("debug"); cv::imwrite("debug/" + stem + "_raw.png", m_image); #endif diff --git a/src/MeoAssistant/Version.h b/src/MeoAssistant/Version.h index c24e3b7c70..83cf23b5d2 100644 --- a/src/MeoAssistant/Version.h +++ b/src/MeoAssistant/Version.h @@ -2,7 +2,7 @@ namespace asst { - constexpr static const char* Version = + static constexpr const char* Version = #ifdef MAA_VERSION MAA_VERSION; #else