refactor: 重构controller,改为同步操作,修改部分接口参数

This commit is contained in:
MistEO
2022-11-06 22:50:21 +08:00
parent ed107d6b35
commit 9055670e7d
16 changed files with 144 additions and 315 deletions

View File

@@ -20,7 +20,7 @@ extern "C"
#ifdef __cplusplus
typedef asst::Assistant* AsstHandle;
#else
typedef void* AsstHandle;
typedef void* AsstHandle;
#endif
typedef int TaskId;
typedef void(ASST_CALL* AsstApiCallback)(int msg, const char* detail_json, void* custom_arg);
@@ -41,7 +41,7 @@ extern "C"
bool ASSTAPI AsstStop(AsstHandle handle);
bool ASSTAPI AsstRunning(AsstHandle handle);
bool ASSTAPI AsstCtrlerClick(AsstHandle handle, int x, int y, bool block);
bool ASSTAPI AsstClick(AsstHandle handle, int x, int y);
unsigned long long ASSTAPI AsstGetImage(AsstHandle handle, void* buff, unsigned long long buff_size);
unsigned long long ASSTAPI AsstGetUUID(AsstHandle handle, char* buff, unsigned long long buff_size);
unsigned long long ASSTAPI AsstGetTasksList(AsstHandle handle, TaskId* buff, unsigned long long buff_size);

View File

@@ -166,15 +166,15 @@ std::vector<uchar> asst::Assistant::get_image() const
if (!inited()) {
return {};
}
return m_ctrler->get_image_encode();
return m_ctrler->get_encoded_image_cache();
}
bool asst::Assistant::ctrler_click(int x, int y, bool block)
bool asst::Assistant::ctrler_click(int x, int y)
{
if (!inited()) {
return false;
}
m_ctrler->click(Point(x, y), block);
m_ctrler->click(Point(x, y));
return true;
}

View File

@@ -45,7 +45,7 @@ namespace asst
bool running();
std::vector<uchar> get_image() const;
bool ctrler_click(int x, int y, bool block = true);
bool ctrler_click(int x, int y);
std::string get_uuid() const;
std::vector<TaskId> get_tasks_list() const;

View File

@@ -135,12 +135,12 @@ bool AsstSetTaskParams(AsstHandle handle, TaskId id, const char* params)
return handle->set_task_params(id, params ? params : "");
}
bool AsstCtrlerClick(AsstHandle handle, int x, int y, bool block)
bool AsstClick(AsstHandle handle, int x, int y)
{
if (!inited || handle == nullptr) {
return false;
}
return handle->ctrler_click(x, y, block);
return handle->ctrler_click(x, y);
}
unsigned long long AsstGetImage(AsstHandle handle, void* buff, unsigned long long buff_size)

View File

@@ -48,96 +48,32 @@ asst::Controller::Controller(AsstCallback callback, void* callback_arg)
}
#else
int pipe_in_ret = pipe(m_pipe_in);
int pipe_out_ret = pipe(m_pipe_out);
fcntl(m_pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
int pipe_in_ret = ::pipe(m_pipe_in);
int pipe_out_ret = ::pipe(m_pipe_out);
::fcntl(m_pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
if (pipe_in_ret < 0 || pipe_out_ret < 0) {
Log.error(__FUNCTION__, "controller pipe created failed", pipe_in_ret, pipe_out_ret);
}
m_support_socket = true;
#endif
m_cmd_thread = std::thread(&Controller::pipe_working_proc, this);
}
asst::Controller::~Controller()
{
LogTraceFunction;
m_thread_exit = true;
// m_thread_idle = true;
m_cmd_condvar.notify_all();
m_completed_id = UINT_MAX; // make all WinMacor::wait to exit
if (m_cmd_thread.joinable()) {
m_cmd_thread.join();
}
set_inited(false);
kill_adb_daemon();
#ifndef _WIN32
close(m_pipe_in[PIPE_READ]);
close(m_pipe_in[PIPE_WRITE]);
close(m_pipe_out[PIPE_READ]);
close(m_pipe_out[PIPE_WRITE]);
::close(m_pipe_in[PIPE_READ]);
::close(m_pipe_in[PIPE_WRITE]);
::close(m_pipe_out[PIPE_READ]);
::close(m_pipe_out[PIPE_WRITE]);
#endif
}
// asst::Rect asst::Controller::shaped_correct(const Rect & rect) const
//{
// if (rect.empty()
// || m_scale_size.first == 0
// || m_scale_size.second == 0) {
// return rect;
// }
// // 明日方舟在异形屏上,有的地方是按比例缩放的,有的地方又是直接位移。没法整,这里简单粗暴一点截一个长条
// Rect dst = rect;
// if (m_scale_size.first != WindowWidthDefault) { // 说明是宽屏
// if (rect.width <= WindowWidthDefault / 2) {
// if (rect.x + rect.width <= WindowWidthDefault / 2) { // 整个矩形都在左半边
// dst.x = 0;
// dst.width = m_scale_size.first / 2;
// }
// else if (rect.x >= WindowWidthDefault / 2) { // 整个矩形都在右半边
// dst.x = m_scale_size.first / 2;
// dst.width = m_scale_size.first / 2;
// }
// else { // 整个矩形横跨了中线
// dst.x = 0;
// dst.width = m_scale_size.first;
// }
// }
// else {
// dst.x = 0;
// dst.width = m_scale_size.first;
// }
// }
// else if (m_scale_size.second != WindowHeightDefault) { // 说明是偏方形屏
// if (rect.height <= WindowHeightDefault / 2) {
// if (rect.y + rect.height <= WindowHeightDefault / 2) { // 整个矩形都在上半边
// dst.y = 0;
// dst.height = m_scale_size.second / 2;
// }
// else if (rect.y >= WindowHeightDefault / 2) { // 整个矩形都在下半边
// dst.y = m_scale_size.second / 2;
// dst.height = m_scale_size.second / 2; // 整个矩形横跨了中线
// }
// else {
// dst.y = 0;
// dst.height = m_scale_size.second;
// }
// }
//
// else {
// dst.y = 0;
// dst.height = m_scale_size.second;
// }
// }
// return dst;
// }
std::pair<int, int> asst::Controller::get_scale_size() const noexcept
{
return m_scale_size;
@@ -148,40 +84,6 @@ bool asst::Controller::need_exit() const
return m_exit_flag != nullptr && *m_exit_flag;
}
void asst::Controller::pipe_working_proc()
{
LogTraceFunction;
while (!m_thread_exit) {
std::unique_lock<std::mutex> cmd_queue_lock(m_cmd_queue_mutex);
if (!m_cmd_queue.empty()) { // 队列中有任务就执行任务
std::string cmd = m_cmd_queue.front();
m_cmd_queue.pop();
cmd_queue_lock.unlock();
// todo 判断命令是否执行成功
call_command(cmd);
++m_completed_id;
}
// else if (!m_thread_idle) { // 队列中没有任务,又不是闲置的时候,就去截图
// cmd_queue_lock.unlock();
// auto start_time = std::chrono::steady_clock::now();
// screencap();
// cmd_queue_lock.lock();
// if (!m_cmd_queue.empty()) {
// continue;
// }
// m_cmd_condvar.wait_until(
// cmd_queue_lock,
// start_time + std::chrono::milliseconds(1000)); // todo 时间写到配置文件里
// }
else {
// m_cmd_condvar.wait(cmd_queue_lock, [&]() -> bool {return !m_thread_idle; });
m_cmd_condvar.wait(cmd_queue_lock);
}
}
}
std::optional<std::string> asst::Controller::call_command(const std::string& cmd, int64_t timeout, bool allow_reconnect,
bool recv_by_socket)
{
@@ -247,9 +149,9 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
sockov.hEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
DWORD dummy;
if (!m_AcceptEx(m_server_sock, client_socket, sock_buffer.value().get(),
(DWORD)sock_buffer.value().size() - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in) + 16,
sizeof(sockaddr_in) + 16, &dummy, &sockov)) {
if (!m_server_accept_ex(m_server_sock, client_socket, sock_buffer.value().get(),
(DWORD)sock_buffer.value().size() - ((sizeof(sockaddr_in) + 16) * 2),
sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &dummy, &sockov)) {
err = WSAGetLastError();
if (err == ERROR_IO_PENDING) {
accept_pending = true;
@@ -258,15 +160,12 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
Log.trace("AcceptEx failed, err:", err);
accept_pending = false;
socket_eof = true;
closesocket(client_socket);
::closesocket(client_socket);
}
}
}
while (true) {
if (need_exit()) {
break;
}
while (!need_exit()) {
wait_handles.clear();
if (process_running) wait_handles.push_back(process_info.hProcess);
if (!pipe_eof) wait_handles.push_back(pipeov.hEvent);
@@ -346,7 +245,7 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
if (len == 0) {
socket_eof = true;
closesocket(client_socket);
::closesocket(client_socket);
}
else {
// reset the overlapped since we reuse it for different handle
@@ -367,7 +266,7 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
sock_data.insert(sock_data.end(), sock_buffer.value().get(), sock_buffer.value().get() + len);
if (len == 0) {
socket_eof = true;
closesocket(client_socket);
::closesocket(client_socket);
}
else {
(void)ReadFile(reinterpret_cast<HANDLE>(client_socket), sock_buffer.value().get(),
@@ -377,7 +276,7 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
else {
// err = GetLastError();
socket_eof = true;
closesocket(client_socket);
::closesocket(client_socket);
}
}
}
@@ -400,13 +299,13 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
};
int exit_ret = 0;
m_child = fork();
m_child = ::fork();
if (m_child == 0) {
// child process
dup2(m_pipe_in[PIPE_READ], STDIN_FILENO);
dup2(m_pipe_out[PIPE_WRITE], STDOUT_FILENO);
dup2(m_pipe_out[PIPE_WRITE], STDERR_FILENO);
::dup2(m_pipe_in[PIPE_READ], STDIN_FILENO);
::dup2(m_pipe_out[PIPE_WRITE], STDOUT_FILENO);
::dup2(m_pipe_out[PIPE_WRITE], STDERR_FILENO);
// all these are for use by parent only
// close(m_pipe_in[PIPE_READ]);
@@ -415,7 +314,7 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
// close(m_pipe_out[PIPE_WRITE]);
exit_ret = execlp("sh", "sh", "-c", cmd.c_str(), nullptr);
exit(exit_ret);
::exit(exit_ret);
}
else if (m_child > 0) {
// parent process
@@ -446,7 +345,7 @@ std::optional<std::string> asst::Controller::call_command(const std::string& cmd
while (read_num > 0) {
pipe_data.insert(pipe_data.end(), pipe_buffer.get(), pipe_buffer.get() + read_num);
read_num = read(m_pipe_out[PIPE_READ], pipe_buffer.get(), pipe_buffer.size());
read_num = ::read(m_pipe_out[PIPE_READ], pipe_buffer.get(), pipe_buffer.size());
}
} while (::waitpid(m_child, &exit_ret, WNOHANG) == 0 && !check_timeout());
}
@@ -628,22 +527,12 @@ void asst::Controller::clear_info() noexcept
m_scale_size = { WindowWidthDefault, WindowHeightDefault };
}
int asst::Controller::push_cmd(const std::string& cmd)
{
random_delay();
std::unique_lock<std::mutex> lock(m_cmd_queue_mutex);
m_cmd_queue.emplace(cmd);
m_cmd_condvar.notify_one();
return static_cast<int>(++m_push_id);
}
void asst::Controller::try_to_close_socket() noexcept
void asst::Controller::close_socket(SOCKET& sock) noexcept
{
#ifdef _WIN32
if (m_server_sock != INVALID_SOCKET) {
::closesocket(m_server_sock);
m_server_sock = INVALID_SOCKET;
if (sock != INVALID_SOCKET) {
::closesocket(sock);
sock = INVALID_SOCKET;
}
#else
if (m_server_sock >= 0) {
@@ -654,7 +543,7 @@ void asst::Controller::try_to_close_socket() noexcept
m_server_started = false;
}
std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::string& local_address)
std::optional<unsigned short> asst::Controller::init_socket(const std::string& local_address)
{
LogTraceFunction;
@@ -666,18 +555,18 @@ std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::st
}
}
DWORD dummy;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
auto err = WSAIoctl(m_server_sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx),
&m_AcceptEx, sizeof(m_AcceptEx), &dummy, NULL, NULL);
DWORD dummy = 0;
GUID guid_accept_ex = WSAID_ACCEPTEX;
int err = WSAIoctl(m_server_sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_accept_ex, sizeof(guid_accept_ex),
&m_server_accept_ex, sizeof(m_server_accept_ex), &dummy, NULL, NULL);
if (err == SOCKET_ERROR) {
err = WSAGetLastError();
Log.error("failed to resolve AcceptEx, err:", err);
closesocket(m_server_sock);
::closesocket(m_server_sock);
return std::nullopt;
}
m_server_addr.sin_family = PF_INET;
inet_pton(AF_INET, local_address.c_str(), &m_server_addr.sin_addr);
m_server_sock_addr.sin_family = PF_INET;
::inet_pton(AF_INET, local_address.c_str(), &m_server_sock_addr.sin_addr);
#else
m_server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (m_server_sock < 0) {
@@ -692,10 +581,10 @@ std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::st
uint16_t port_result = 0;
#ifdef _WIN32
m_server_addr.sin_port = htons(0);
int bind_ret = ::bind(m_server_sock, reinterpret_cast<SOCKADDR*>(&m_server_addr), sizeof(SOCKADDR));
int addrlen = sizeof(m_server_addr);
int getname_ret = getsockname(m_server_sock, reinterpret_cast<sockaddr*>(&m_server_addr), &addrlen);
m_server_sock_addr.sin_port = ::htons(0);
int bind_ret = ::bind(m_server_sock, reinterpret_cast<SOCKADDR*>(&m_server_sock_addr), sizeof(SOCKADDR));
int addrlen = sizeof(m_server_sock_addr);
int getname_ret = ::getsockname(m_server_sock, reinterpret_cast<sockaddr*>(&m_server_sock_addr), &addrlen);
int listen_ret = ::listen(m_server_sock, 3);
server_start = bind_ret == 0 && getname_ret == 0 && listen_ret == 0;
#else
@@ -708,34 +597,18 @@ std::optional<unsigned short> asst::Controller::try_to_init_socket(const std::st
#endif
if (!server_start) {
Log.info("not supports netcat");
Log.info("not supports socket");
return std::nullopt;
}
port_result = ntohs(m_server_addr.sin_port);
Log.info("server_start", local_address, port_result);
Log.info("command server start", local_address, port_result);
return port_result;
}
void asst::Controller::wait(unsigned id) const noexcept
{
using namespace std::chrono_literals;
static constexpr auto delay = 10ms;
while (id > m_completed_id) {
std::this_thread::sleep_for(delay);
}
}
bool asst::Controller::screencap(bool allow_reconnect)
{
// if (true) {
// m_inited = true;
// std::unique_lock<std::shared_mutex> image_lock(m_image_mutex);
// m_cache_image = cv::imread("err/1.png");
// return true;
// }
DecodeFunc decode_raw = [&](std::string_view data) -> bool {
if (data.empty()) {
return false;
@@ -907,7 +780,7 @@ void asst::Controller::clear_lf_info()
m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::UnknownYet;
}
cv::Mat asst::Controller::get_resized_image() const
cv::Mat asst::Controller::get_resized_image_cache() const
{
const static cv::Size d_size(m_scale_size.first, m_scale_size.second);
@@ -921,67 +794,55 @@ cv::Mat asst::Controller::get_resized_image() const
return resized_mat;
}
std::optional<int> asst::Controller::start_game(const std::string& client_type, bool block)
bool asst::Controller::start_game(const std::string& client_type)
{
if (client_type.empty()) {
return std::nullopt;
return false;
}
if (auto intent_name = Configer.get_intent_name(client_type)) {
std::string cur_cmd = utils::string_replace_all(m_adb.start, "[Intent]", intent_name.value());
int id = push_cmd(cur_cmd);
if (block) {
wait(id);
}
return id;
auto intent_name = Configer.get_intent_name(client_type);
if (!intent_name) {
return false;
}
return std::nullopt;
std::string cur_cmd = utils::string_replace_all(m_adb.start, "[Intent]", intent_name.value());
return call_command(cur_cmd).has_value();
}
std::optional<int> asst::Controller::stop_game(bool block)
bool asst::Controller::stop_game()
{
std::string cur_cmd = m_adb.stop;
int id = push_cmd(cur_cmd);
if (block) {
wait(id);
}
return id;
return call_command(m_adb.stop).has_value();
}
int asst::Controller::click(const Point& p, bool block)
bool asst::Controller::click(const Point& p)
{
int x = static_cast<int>(p.x * m_control_scale);
int y = static_cast<int>(p.y * m_control_scale);
// log.trace("Click, raw:", p.x, p.y, "corr:", x, y);
return click_without_scale(Point(x, y), block);
return click_without_scale(Point(x, y));
}
int asst::Controller::click(const Rect& rect, bool block)
bool asst::Controller::click(const Rect& rect)
{
return click(rand_point_in_rect(rect), block);
return click(rand_point_in_rect(rect));
}
int asst::Controller::click_without_scale(const Point& p, bool block)
bool asst::Controller::click_without_scale(const Point& p)
{
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(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);
}
return id;
return call_command(cur_cmd).has_value();
}
int asst::Controller::click_without_scale(const Rect& rect, bool block)
bool asst::Controller::click_without_scale(const Rect& rect)
{
return click_without_scale(rand_point_in_rect(rect), block);
return click_without_scale(rand_point_in_rect(rect));
}
int asst::Controller::swipe(const Point& p1, const Point& p2, int duration, bool block, int extra_delay,
bool extra_swipe)
bool asst::Controller::swipe(const Point& p1, const Point& p2, int duration, bool extra_swipe)
{
int x1 = static_cast<int>(p1.x * m_control_scale);
int y1 = static_cast<int>(p1.y * m_control_scale);
@@ -989,16 +850,15 @@ int asst::Controller::swipe(const Point& p1, const Point& p2, int duration, bool
int y2 = static_cast<int>(p2.y * m_control_scale);
// log.trace("Swipe, raw:", p1.x, p1.y, p2.x, p2.y, "corr:", x1, y1, x2, y2);
return swipe_without_scale(Point(x1, y1), Point(x2, y2), duration, block, extra_delay, extra_swipe);
return swipe_without_scale(Point(x1, y1), Point(x2, y2), duration, extra_swipe);
}
int asst::Controller::swipe(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay, bool extra_swipe)
bool asst::Controller::swipe(const Rect& r1, const Rect& r2, int duration, bool extra_swipe)
{
return swipe(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay, extra_swipe);
return swipe(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, extra_swipe);
}
int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay,
bool extra_swipe)
bool asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool extra_swipe)
{
int x1 = p1.x, y1 = p1.y;
int x2 = p2.x, y2 = p2.y;
@@ -1018,8 +878,8 @@ int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int
{ "[y2]", std::to_string(y2) },
{ "[duration]", duration <= 0 ? "" : std::to_string(duration) },
});
bool ret = call_command(cur_cmd).has_value();
int id = 0;
// 额外的滑动adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来
const auto& opt = Configer.get_options();
if (extra_swipe && opt.adb_extra_swipe_duration > 0) {
@@ -1031,25 +891,14 @@ int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int
{ "[y2]", std::to_string(y2 - opt.adb_extra_swipe_dist /* * m_control_scale*/) },
{ "[duration]", std::to_string(opt.adb_extra_swipe_duration) },
});
push_cmd(cur_cmd);
id = push_cmd(extra_cmd);
ret &= call_command(extra_cmd).has_value();
}
else {
id = push_cmd(cur_cmd);
}
if (block) {
wait(id);
std::this_thread::sleep_for(std::chrono::milliseconds(extra_delay));
}
return id;
return ret;
}
int asst::Controller::swipe_without_scale(const Rect& r1, const Rect& r2, int duration, bool block, int extra_delay,
bool extra_swipe)
bool asst::Controller::swipe_without_scale(const Rect& r1, const Rect& r2, int duration, bool extra_swipe)
{
return swipe_without_scale(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, block, extra_delay,
extra_swipe);
return swipe_without_scale(rand_point_in_rect(r1), rand_point_in_rect(r2), duration, extra_swipe);
}
bool asst::Controller::connect(const std::string& adb_path, const std::string& address, const std::string& config)
@@ -1292,22 +1141,17 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
bind_address = "127.0.0.1";
}
// Todo: detect remote address, and check remote port
// reference from
// 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) {
if (nc_address_ret && !m_server_started) {
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);
}
}
if (need_exit()) {
return false;
}
auto socket_opt = try_to_init_socket(bind_address);
auto socket_opt = init_socket(bind_address);
if (socket_opt) {
nc_port = socket_opt.value();
m_adb.screencap_raw_by_nc = cmd_replace(adb_cfg.screencap_raw_by_nc);
@@ -1318,6 +1162,10 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a
}
}
if (need_exit()) {
return false;
}
// try to find the fastest way
if (!screencap()) {
Log.error("Cannot find a proper way to screencap!");
@@ -1364,7 +1212,8 @@ void asst::Controller::kill_adb_daemon()
bool asst::Controller::release()
{
try_to_close_socket();
close_socket(m_server_sock);
m_server_started = false;
#ifndef _WIN32
if (m_child)
@@ -1439,14 +1288,14 @@ cv::Mat asst::Controller::get_image(bool raw)
return copy;
}
return get_resized_image();
return get_resized_image_cache();
}
std::vector<uchar> asst::Controller::get_image_encode() const
std::vector<uchar> asst::Controller::get_encoded_image_cache() const
{
cv::Mat img = get_resized_image();
cv::Mat img = get_resized_image_cache();
std::vector<uchar> buf;
cv::imencode(".png", img, buf);
return buf;
}
}

View File

@@ -43,32 +43,21 @@ namespace asst
const std::string& get_uuid() const;
cv::Mat get_image(bool raw = false);
std::vector<uchar> get_image_encode() const;
std::vector<uchar> get_encoded_image_cache() const;
/* 开启游戏、点击和滑动都是异步执行返回该任务的id */
bool start_game(const std::string& client_type);
bool stop_game();
std::optional<int> start_game(const std::string& client_type, bool block = true);
std::optional<int> stop_game(bool block = true);
bool click(const Point& p);
bool click(const Rect& rect);
bool click_without_scale(const Point& p);
bool click_without_scale(const Rect& rect);
int click(const Point& p, bool block = true);
int click(const Rect& rect, bool block = true);
int click_without_scale(const Point& p, bool block = true);
int click_without_scale(const Rect& rect, bool block = true);
bool swipe(const Point& p1, const Point& p2, int duration = 0, bool extra_swipe = false);
bool swipe(const Rect& r1, const Rect& r2, int duration = 0, bool extra_swipe = false);
bool swipe_without_scale(const Point& p1, const Point& p2, int duration = 0, bool extra_swipe = false);
bool swipe_without_scale(const Rect& r1, const Rect& r2, int duration = 0, bool extra_swipe = false);
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,
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
int swipe_without_scale(const Point& p1, const Point& p2, int duration = 0, bool block = true,
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
int swipe_without_scale(const Rect& r1, const Rect& r2, int duration = 0, bool block = true,
int extra_delay = SwipeExtraDelayDefault, bool extra_swipe = false);
void wait(unsigned id) const noexcept;
// 异形屏矫正
// Rect shaped_correct(const Rect& rect) const;
std::pair<int, int> get_scale_size() const noexcept;
Controller& operator=(const Controller&) = delete;
@@ -76,23 +65,21 @@ namespace asst
private:
bool need_exit() const;
void pipe_working_proc();
std::optional<std::string> call_command(const std::string& cmd, int64_t timeout = 20000,
bool allow_reconnect = true, bool recv_by_socket = false);
int push_cmd(const std::string& cmd);
bool release();
void kill_adb_daemon();
bool set_inited(bool inited);
void try_to_close_socket() noexcept;
std::optional<unsigned short> try_to_init_socket(const std::string& local_address);
void close_socket(SOCKET& sock) noexcept;
std::optional<unsigned short> init_socket(const std::string& local_address);
using DecodeFunc = std::function<bool(std::string_view)>;
bool screencap(bool allow_reconnect = false);
bool screencap(const std::string& cmd, const DecodeFunc& decode_func, bool allow_reconnect = false,
bool by_socket = false);
void clear_lf_info();
cv::Mat get_resized_image() const;
cv::Mat get_resized_image_cache() const;
Point rand_point_in_rect(const Rect& rect);
@@ -111,13 +98,14 @@ namespace asst
std::minstd_rand m_rand_engine;
std::mutex m_callcmd_mutex;
#ifdef _WIN32
ASST_AUTO_DEDUCED_ZERO_INIT_START
WSADATA m_wsa_data {};
SOCKET m_server_sock = INVALID_SOCKET;
sockaddr_in m_server_addr {};
LPFN_ACCEPTEX m_AcceptEx = nullptr;
sockaddr_in m_server_sock_addr {};
LPFN_ACCEPTEX m_server_accept_ex = nullptr;
ASST_AUTO_DEDUCED_ZERO_INIT_END
#else
@@ -180,15 +168,6 @@ namespace asst
mutable std::shared_mutex m_image_mutex;
cv::Mat m_cache_image;
bool m_thread_exit = false;
// bool m_thread_idle = true;
std::mutex m_cmd_queue_mutex;
std::condition_variable m_cmd_condvar;
std::queue<std::string> m_cmd_queue;
std::atomic<unsigned> m_completed_id = 0;
unsigned m_push_id = 0; // push_id的自增总是伴随着queue的push肯定是要上锁的所以没必要原子
std::thread m_cmd_thread;
private:
#ifdef _WIN32
// for Windows socket

View File

@@ -719,15 +719,16 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle()
placed_point, { opt_oper.rect.x + opt_oper.rect.width / 2, opt_oper.rect.y + opt_oper.rect.height / 2 }));
// 1000 是随便取的一个系数,把整数的 pre_delay 转成小数用的
int duration = static_cast<int>(swipe_oper_task_ptr->pre_delay / 800.0 * dist * log10(dist));
m_ctrler->swipe(opt_oper.rect, placed_rect, duration, true, 0);
m_ctrler->swipe(opt_oper.rect, placed_rect, duration);
sleep(use_oper_task_ptr->post_delay);
// 将方向转换为实际的 swipe end 坐标点
if (direction != Point::zero()) {
constexpr int coeff = 500;
Point end_point = placed_point + (direction * coeff);
m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->post_delay, true, 100);
m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->post_delay);
}
sleep(Task.get("BattleUseOper")->post_delay);
if (opt_oper.role == BattleRole::Drone) {
cancel_oper_selection();

View File

@@ -9,7 +9,7 @@ bool StartGameTaskPlugin::_run()
if (m_client_type.empty()) {
return false;
}
return m_ctrler->start_game(m_client_type).has_value();
return m_ctrler->start_game(m_client_type);
}
StartGameTaskPlugin& StartGameTaskPlugin::set_client_type(std::string client_type) noexcept

View File

@@ -6,5 +6,5 @@ using namespace asst;
bool StopGameTaskPlugin::_run()
{
return m_ctrler->stop_game().has_value();
return m_ctrler->stop_game();
}

View File

@@ -520,7 +520,7 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action)
Point::distance(placed_point, { oper_rect.x + oper_rect.width / 2, oper_rect.y + oper_rect.height / 2 }));
// 1000 是随便取的一个系数,把整数的 pre_delay 转成小数用的
int duration = static_cast<int>(swipe_oper_task_ptr->pre_delay / 1000.0 * dist * log10(dist));
m_ctrler->swipe(oper_rect, placed_rect, duration, true, 0);
m_ctrler->swipe(oper_rect, placed_rect, duration);
sleep(use_oper_task_ptr->post_delay);
@@ -539,7 +539,8 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action)
constexpr int coeff = 500;
Point end_point = placed_point + (direction * coeff);
m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->post_delay, true, 100);
m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->post_delay);
sleep(Task.get("BattleUseOper")->post_delay);
}
m_used_opers[iter->first] =
@@ -910,4 +911,4 @@ std::optional<std::unordered_map<GroupNameType, CharNameType>> asst::BattleProce
}
return return_value;
}
}

View File

@@ -307,5 +307,5 @@ void ProcessTask::exec_click_task(const Rect& matched_rect)
void asst::ProcessTask::exec_swipe_task(const Rect& r1, const Rect& r2, int duration, bool extra_swipe)
{
m_ctrler->swipe(r1, r2, duration, true, 0, extra_swipe);
m_ctrler->swipe(r1, r2, duration, extra_swipe);
}

View File

@@ -196,7 +196,7 @@ asst::http::Response asst::ReportDataTask::escape_and_request(const std::string&
utils::string_replace_all(format, { { "[body]", body_escape }, { "[extra]", m_extra_param } });
Log.info("request:\n" + cmd_line);
std::string response = utils::callcmd(cmd_line);
std::string response = utils::call_command(cmd_line);
Log.info("response:\n" + response);
// Log.info("response:\n" + utils::string_replace_all(response, {

View File

@@ -19,7 +19,7 @@ namespace asst::utils
using platform::path_to_utf8_string;
using platform::to_osstring;
using platform::callcmd;
using platform::call_command;
namespace path_literals
{
@@ -29,5 +29,4 @@ namespace asst::utils
return asst::utils::path(std::string(std::string_view(utf8_str, len)));
}
}
} // namespace asst::utils
} // namespace asst::utils

View File

@@ -9,7 +9,7 @@
namespace asst::platform
{
std::string callcmd(const std::string&);
std::string call_command(const std::string& cmdline, bool* exit_flag = nullptr);
using os_string = std::filesystem::path::string_type;

View File

@@ -21,10 +21,10 @@ void* asst::platform::aligned_alloc(size_t len, size_t align)
void asst::platform::aligned_free(void* ptr)
{
free(ptr);
::free(ptr);
}
std::string asst::platform::callcmd(const std::string& cmdline)
std::string asst::platform::call_command(const std::string& cmdline, bool* exit_flag)
{
constexpr int PipeBuffSize = 4096;
std::string pipe_str;
@@ -39,49 +39,49 @@ std::string asst::platform::callcmd(const std::string& cmdline)
if (pipe_in_ret != 0 || pipe_out_ret != 0) {
return {};
}
fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
::fcntl(pipe_out[PIPE_READ], F_SETFL, O_NONBLOCK);
int exit_ret = 0;
int child = fork();
int child = ::fork();
if (child == 0) {
// child process
dup2(pipe_in[PIPE_READ], STDIN_FILENO);
dup2(pipe_out[PIPE_WRITE], STDOUT_FILENO);
dup2(pipe_out[PIPE_WRITE], STDERR_FILENO);
::dup2(pipe_in[PIPE_READ], STDIN_FILENO);
::dup2(pipe_out[PIPE_WRITE], STDOUT_FILENO);
::dup2(pipe_out[PIPE_WRITE], STDERR_FILENO);
// all these are for use by parent only
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
::close(pipe_in[PIPE_READ]);
::close(pipe_in[PIPE_WRITE]);
::close(pipe_out[PIPE_READ]);
::close(pipe_out[PIPE_WRITE]);
exit_ret = execlp("sh", "sh", "-c", cmdline.c_str(), nullptr);
exit(exit_ret);
::exit(exit_ret);
}
else if (child > 0) {
// parent process
// close unused file descriptors, these are for child only
close(pipe_in[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
::close(pipe_in[PIPE_READ]);
::close(pipe_out[PIPE_WRITE]);
do {
ssize_t read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
ssize_t read_num = ::read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
while (read_num > 0) {
pipe_str.append(pipe_buffer.get(), pipe_buffer.get() + read_num);
read_num = read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
read_num = ::read(pipe_out[PIPE_READ], pipe_buffer.get(), PipeBuffSize);
};
} while (::waitpid(child, &exit_ret, WNOHANG) == 0);
} while (::waitpid(child, &exit_ret, WNOHANG) == 0 && !(exit_flag && *exit_flag));
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
::close(pipe_in[PIPE_WRITE]);
::close(pipe_out[PIPE_READ]);
}
else {
// failed to create child process
close(pipe_in[PIPE_READ]);
close(pipe_in[PIPE_WRITE]);
close(pipe_out[PIPE_READ]);
close(pipe_out[PIPE_WRITE]);
::close(pipe_in[PIPE_READ]);
::close(pipe_in[PIPE_WRITE]);
::close(pipe_out[PIPE_READ]);
::close(pipe_out[PIPE_WRITE]);
}
return pipe_str;
}

View File

@@ -120,7 +120,7 @@ std::string asst::platform::from_osstring(const os_string& os_str)
return result;
}
std::string asst::platform::callcmd(const std::string& cmdline)
std::string asst::platform::call_command(const std::string& cmdline, bool* exit_flag)
{
constexpr int PipeBuffSize = 4096;
auto pipe_buffer = std::make_unique<char[]>(PipeBuffSize);
@@ -164,7 +164,7 @@ std::string asst::platform::callcmd(const std::string& cmdline)
OVERLAPPED pipeov { .hEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr) };
(void)ReadFile(pipe_parent_read, pipe_buffer.get(), PipeBuffSize, nullptr, &pipeov);
while (true) {
while (!(exit_flag && *exit_flag)) {
wait_handles.clear();
if (process_running) wait_handles.push_back(process_info.hProcess);
if (!pipe_eof) wait_handles.push_back(pipeov.hEvent);