mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-19 02:23:01 +08:00
Merge pull request #1741 from MaaAssistantArknights/perf/uchar
perf: 整理并优化
This commit is contained in:
@@ -80,7 +80,7 @@ asst::Controller::Controller(AsstCallback callback, void* callback_arg)
|
||||
m_support_socket = false;
|
||||
#endif
|
||||
|
||||
m_pipe_buffer = std::make_unique<uchar[]>(PipeBuffSize);
|
||||
m_pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
|
||||
if (!m_pipe_buffer) {
|
||||
throw "controller pipe buffer allocated failed";
|
||||
}
|
||||
@@ -222,14 +222,13 @@ void asst::Controller::pipe_working_proc()
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::vector<uchar>> asst::Controller::call_command(const std::string& cmd, int64_t timeout,
|
||||
bool recv_by_socket)
|
||||
std::optional<std::string> 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<uchar> pipe_data;
|
||||
std::string pipe_data;
|
||||
|
||||
auto start_time = steady_clock::now();
|
||||
auto check_timeout = [&]() -> bool {
|
||||
@@ -331,8 +330,7 @@ std::optional<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
|
||||
auto duration = duration_cast<milliseconds>(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<std::vector<uchar>> 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<std::vector<uchar>> 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<std::vector<uchar>> asst::Controller::call_command(const std::stri
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void asst::Controller::convert_lf(std::vector<uchar>& 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<uchar>::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<uchar>& 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<uchar>& 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<uchar>& 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<bool> {});
|
||||
if (is_all_zero) {
|
||||
auto img_data = data.substr(header_size);
|
||||
if (ranges::all_of(img_data, std::logical_not<bool> {})) {
|
||||
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<char*>(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<uchar>& 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<bool> {});
|
||||
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<std::shared_mutex> 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<uchar>& 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()) {
|
||||
|
||||
Reference in New Issue
Block a user