mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-16 01:40:46 +08:00
feat.初步完成跨平台移植的初始化部分
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -432,3 +432,4 @@ screen.png
|
||||
adb_screen.png
|
||||
tools/*.png
|
||||
resource/infrast
|
||||
.vscode/settings.json
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
project(MeoAssistantArknights)
|
||||
|
||||
option(BUILD_TEST "build a demo" OFF)
|
||||
|
||||
include_directories(include 3rdparty/include)
|
||||
aux_source_directory(src/MeoAssistant SRC)
|
||||
add_definitions(-DASST_DLL_EXPORTS)
|
||||
@@ -16,9 +18,20 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_library(MeoAssistant SHARED ${SRC})
|
||||
|
||||
find_library(Opencv_LIB NAMES opencv_world453 PATHS 3rdparty/lib)
|
||||
find_library(PaddleOCR_LIB NAMES ppocr PATHS 3rdparty/lib)
|
||||
find_library(Penguin_LIB NAMES penguin-stats-recognize PATHS 3rdparty/lib)
|
||||
find_library(MeoJson_LIB NAMES libmeojson PATHS 3rdparty/lib)
|
||||
find_library(MeoJson_LIB NAMES meojson PATHS 3rdparty/lib)
|
||||
|
||||
target_link_libraries(MeoAssistant ${Opencv_LIB} ${PaddleOCR_LIB} ${Penguin_LIB} ${MeoJson_LIB})
|
||||
if (WIN32)
|
||||
find_library(OpenCV NAMES opencv_world453 PATHS 3rdparty/lib)
|
||||
else ()
|
||||
find_package(OpenCV REQUIRED)
|
||||
endif ()
|
||||
|
||||
|
||||
target_link_libraries(MeoAssistant ${OpenCV} ${PaddleOCR_LIB} ${Penguin_LIB} ${MeoJson_LIB})
|
||||
|
||||
if (BUILD_TEST)
|
||||
add_executable(test tools/TestCaller/main.cpp)
|
||||
target_link_libraries(test MeoAssistant)
|
||||
endif(BUILD_TEST)
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
|
||||
bool asst::AbstractConfiger::load(const std::string& filename)
|
||||
{
|
||||
std::string content = utils::load_file_without_bom(filename);
|
||||
|
||||
auto&& ret = json::parser::parse(content);
|
||||
if (!ret) {
|
||||
m_last_error = "json pasing error " + content;
|
||||
return false;
|
||||
}
|
||||
|
||||
json::value root = std::move(ret.value());
|
||||
|
||||
try {
|
||||
return parse(root);
|
||||
}
|
||||
catch (json::exception& e) {
|
||||
m_last_error = std::string("json field error ") + e.what();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
|
||||
bool asst::AbstractConfiger::load(const std::string& filename)
|
||||
{
|
||||
std::string content = utils::load_file_without_bom(filename);
|
||||
|
||||
auto&& ret = json::parser::parse(content);
|
||||
if (!ret) {
|
||||
m_last_error = "json pasing error, content:" + content;
|
||||
return false;
|
||||
}
|
||||
|
||||
json::value root = std::move(ret.value());
|
||||
|
||||
try {
|
||||
return parse(root);
|
||||
}
|
||||
catch (json::exception& e) {
|
||||
m_last_error = std::string("json field error ") + e.what();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractResource.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace json
|
||||
{
|
||||
class value;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class AbstractConfiger : public AbstractResource
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractConfiger() = default;
|
||||
virtual bool load(const std::string& filename) override;
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) = 0;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include "AbstractResource.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace json
|
||||
{
|
||||
class value;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class AbstractConfiger : public AbstractResource
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractConfiger() = default;
|
||||
virtual bool load(const std::string& filename) override;
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class AbstractImageAnalyzer
|
||||
{
|
||||
public:
|
||||
AbstractImageAnalyzer() = default;
|
||||
AbstractImageAnalyzer(const cv::Mat& image);
|
||||
AbstractImageAnalyzer(const cv::Mat& image, const Rect& roi);
|
||||
AbstractImageAnalyzer(const AbstractImageAnalyzer&) = delete;
|
||||
AbstractImageAnalyzer(AbstractImageAnalyzer&&) = delete;
|
||||
virtual ~AbstractImageAnalyzer() = default;
|
||||
|
||||
virtual void set_image(const cv::Mat& image);
|
||||
virtual void set_image(const cv::Mat& image, const Rect& roi);
|
||||
virtual void set_roi(const Rect& roi) noexcept;
|
||||
virtual bool analyze() = 0;
|
||||
virtual void correct_roi() noexcept;
|
||||
|
||||
std::string calc_name_hash() const; // 使用m_roi
|
||||
std::string calc_name_hash(const Rect& roi) const; // 使用参数roi
|
||||
|
||||
AbstractImageAnalyzer& operator=(const AbstractImageAnalyzer&) = delete;
|
||||
AbstractImageAnalyzer& operator=(AbstractImageAnalyzer&&) = delete;
|
||||
|
||||
protected:
|
||||
static Rect empty_rect_to_full(const Rect& rect, const cv::Mat& image) noexcept;
|
||||
|
||||
cv::Mat m_image;
|
||||
Rect m_roi;
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
cv::Mat m_image_draw;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class AbstractImageAnalyzer
|
||||
{
|
||||
public:
|
||||
AbstractImageAnalyzer() = default;
|
||||
AbstractImageAnalyzer(const cv::Mat& image);
|
||||
AbstractImageAnalyzer(const cv::Mat& image, const Rect& roi);
|
||||
AbstractImageAnalyzer(const AbstractImageAnalyzer&) = delete;
|
||||
AbstractImageAnalyzer(AbstractImageAnalyzer&&) = delete;
|
||||
virtual ~AbstractImageAnalyzer() = default;
|
||||
|
||||
virtual void set_image(const cv::Mat& image);
|
||||
virtual void set_image(const cv::Mat& image, const Rect& roi);
|
||||
virtual void set_roi(const Rect& roi) noexcept;
|
||||
virtual bool analyze() = 0;
|
||||
virtual void correct_roi() noexcept;
|
||||
|
||||
std::string calc_name_hash() const; // 使用m_roi
|
||||
std::string calc_name_hash(const Rect& roi) const; // 使用参数roi
|
||||
|
||||
AbstractImageAnalyzer& operator=(const AbstractImageAnalyzer&) = delete;
|
||||
AbstractImageAnalyzer& operator=(AbstractImageAnalyzer&&) = delete;
|
||||
|
||||
protected:
|
||||
static Rect empty_rect_to_full(const Rect& rect, const cv::Mat& image) noexcept;
|
||||
|
||||
cv::Mat m_image;
|
||||
Rect m_roi;
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
cv::Mat m_image_draw;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class AbstractResource
|
||||
{
|
||||
public:
|
||||
AbstractResource() = default;
|
||||
AbstractResource(const AbstractResource& rhs) = delete;
|
||||
AbstractResource(AbstractResource&& rhs) noexcept = delete;
|
||||
|
||||
virtual ~AbstractResource() = default;
|
||||
|
||||
virtual bool load(const std::string& filename) = 0;
|
||||
virtual const std::string& get_last_error() const noexcept
|
||||
{
|
||||
return m_last_error;
|
||||
}
|
||||
|
||||
AbstractResource& operator=(const AbstractResource& rhs) = delete;
|
||||
AbstractResource& operator=(AbstractResource&& rhs) noexcept = delete;
|
||||
|
||||
protected:
|
||||
std::string m_last_error;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class AbstractResource
|
||||
{
|
||||
public:
|
||||
AbstractResource() = default;
|
||||
AbstractResource(const AbstractResource& rhs) = delete;
|
||||
AbstractResource(AbstractResource&& rhs) noexcept = delete;
|
||||
|
||||
virtual ~AbstractResource() = default;
|
||||
|
||||
virtual bool load(const std::string& filename) = 0;
|
||||
virtual const std::string& get_last_error() const noexcept
|
||||
{
|
||||
return m_last_error;
|
||||
}
|
||||
|
||||
AbstractResource& operator=(const AbstractResource& rhs) = delete;
|
||||
AbstractResource& operator=(AbstractResource&& rhs) noexcept = delete;
|
||||
|
||||
protected:
|
||||
std::string m_last_error;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,145 +1,152 @@
|
||||
#include "AipOcr.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <meojson/json.h>
|
||||
#include <cpp-base64/base64.hpp>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
|
||||
bool asst::AipOcr::request_access_token(const std::string& client_id, const std::string& client_secret)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
m_access_token.clear();
|
||||
|
||||
std::string_view cmd_fmt =
|
||||
R"(curl -s -k "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s")";
|
||||
|
||||
constexpr int cmd_len = 256;
|
||||
char cmd[cmd_len] = { 0 };
|
||||
sprintf_s(cmd, cmd_len, cmd_fmt.data(), client_id.c_str(), client_secret.c_str());
|
||||
|
||||
Log.trace("call cmd:", cmd);
|
||||
|
||||
std::string response = utils::callcmd(cmd);
|
||||
|
||||
Log.trace("response:", response);
|
||||
|
||||
auto parse_res = json::parse(response);
|
||||
if (!parse_res) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
auto json = parse_res.value();
|
||||
m_access_token = json.at("access_token").as_string();
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::AipOcr::request_ocr_general(const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
if (m_access_token.empty()) {
|
||||
auto& cfg = Resrc.cfg().get_options().aip_ocr;
|
||||
request_access_token(cfg.client_id, cfg.client_secret);
|
||||
}
|
||||
|
||||
std::string_view cmd_fmt =
|
||||
R"(curl -s -k "https://aip.baidubce.com/rest/2.0/ocr/v1/general?access_token=%s" --data "image=%s" -H "Content-Type:application/x-www-form-urlencoded")";
|
||||
|
||||
return request_ocr_and_parse(cmd_fmt, image, out_result, pred);
|
||||
}
|
||||
|
||||
bool asst::AipOcr::request_ocr_accurate(const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
if (m_access_token.empty()) {
|
||||
auto& cfg = Resrc.cfg().get_options().aip_ocr;
|
||||
request_access_token(cfg.client_id, cfg.client_secret);
|
||||
}
|
||||
|
||||
std::string_view cmd_fmt =
|
||||
R"(curl -s -k "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=%s" --data "image=%s" -H "Content-Type:application/x-www-form-urlencoded")";
|
||||
|
||||
return request_ocr_and_parse(cmd_fmt, image, out_result, pred);
|
||||
}
|
||||
|
||||
bool asst::AipOcr::request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
if (m_access_token.empty()) {
|
||||
return false;
|
||||
}
|
||||
// CreateProcess 最大只能接受 32767 chars,一张图片随便就超过了
|
||||
// 这个功能暂时没法用,得集成下 libcurl 或者别的
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
auto* enc_msg = reinterpret_cast<unsigned char*>(buf.data());
|
||||
std::string encoded = base64_encode(enc_msg, buf.size());
|
||||
|
||||
size_t cmd_len = encoded.size() + cmd_fmt.size() + m_access_token.size();
|
||||
char* cmd = new char[cmd_len];
|
||||
memset(cmd, 0, cmd_len);
|
||||
sprintf_s(cmd, cmd_len, cmd_fmt.data(), m_access_token.c_str(), encoded.c_str());
|
||||
|
||||
Log.trace("call cmd:", cmd);
|
||||
std::string response = utils::callcmd(cmd);
|
||||
delete[] cmd;
|
||||
Log.trace("response:", response);
|
||||
|
||||
auto parse_res = json::parse(response);
|
||||
if (!parse_res) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
auto json = parse_res.value();
|
||||
return parse_response(json, out_result, pred);
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool asst::AipOcr::parse_response(const json::value& json, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
if (!json.exist("words_result")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<TextRect> result;
|
||||
std::string log_str_raw;
|
||||
std::string log_str_proc;
|
||||
for (const auto& word : json.at("words_result").as_array()) {
|
||||
std::string text = word.at("words").as_string();
|
||||
|
||||
auto& loc = word.at("location").as_object();
|
||||
int left = loc.at("left").as_integer();
|
||||
int right = loc.at("right").as_integer();
|
||||
int top = loc.at("top").as_integer();
|
||||
int bottom = loc.at("bottom").as_integer();
|
||||
|
||||
Rect rect(left, top, right - left, bottom - top);
|
||||
|
||||
TextRect tr{ text, rect, 0 };
|
||||
|
||||
log_str_raw += tr.to_string() + ", ";
|
||||
if (!pred || pred(tr)) {
|
||||
log_str_proc += tr.to_string() + ", ";
|
||||
result.emplace_back(std::move(tr));
|
||||
}
|
||||
}
|
||||
|
||||
Log.trace("AipOcr::parse_response | raw : ", log_str_raw);
|
||||
Log.trace("AipOcr::parse_response | proc : ", log_str_proc);
|
||||
|
||||
out_result = result;
|
||||
return true;
|
||||
}
|
||||
#include "AipOcr.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <meojson/json.h>
|
||||
#include <cpp-base64/base64.hpp>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
|
||||
bool asst::AipOcr::request_access_token(const std::string& client_id, const std::string& client_secret)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
m_access_token.clear();
|
||||
|
||||
std::string_view cmd_fmt =
|
||||
R"(curl -s -k "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s")";
|
||||
|
||||
constexpr int cmd_len = 256;
|
||||
char cmd[cmd_len] = { 0 };
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(cmd, cmd_len, cmd_fmt.data(), client_id.c_str(), client_secret.c_str());
|
||||
#else
|
||||
sprintf(cmd, cmd_fmt.data(), client_id.c_str(), client_secret.c_str());
|
||||
#endif
|
||||
|
||||
Log.trace("call cmd:", cmd);
|
||||
|
||||
std::string response = utils::callcmd(cmd);
|
||||
|
||||
Log.trace("response:", response);
|
||||
|
||||
auto parse_res = json::parse(response);
|
||||
if (!parse_res) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
auto json = parse_res.value();
|
||||
m_access_token = json.at("access_token").as_string();
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::AipOcr::request_ocr_general(const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
if (m_access_token.empty()) {
|
||||
auto& cfg = Resrc.cfg().get_options().aip_ocr;
|
||||
request_access_token(cfg.client_id, cfg.client_secret);
|
||||
}
|
||||
|
||||
std::string_view cmd_fmt =
|
||||
R"(curl -s -k "https://aip.baidubce.com/rest/2.0/ocr/v1/general?access_token=%s" --data "image=%s" -H "Content-Type:application/x-www-form-urlencoded")";
|
||||
|
||||
return request_ocr_and_parse(cmd_fmt, image, out_result, pred);
|
||||
}
|
||||
|
||||
bool asst::AipOcr::request_ocr_accurate(const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
if (m_access_token.empty()) {
|
||||
auto& cfg = Resrc.cfg().get_options().aip_ocr;
|
||||
request_access_token(cfg.client_id, cfg.client_secret);
|
||||
}
|
||||
|
||||
std::string_view cmd_fmt =
|
||||
R"(curl -s -k "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=%s" --data "image=%s" -H "Content-Type:application/x-www-form-urlencoded")";
|
||||
|
||||
return request_ocr_and_parse(cmd_fmt, image, out_result, pred);
|
||||
}
|
||||
|
||||
bool asst::AipOcr::request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
if (m_access_token.empty()) {
|
||||
return false;
|
||||
}
|
||||
// CreateProcess 最大只能接受 32767 chars,一张图片随便就超过了
|
||||
// 这个功能暂时没法用,得集成下 libcurl 或者别的
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
auto* enc_msg = reinterpret_cast<unsigned char*>(buf.data());
|
||||
std::string encoded = base64_encode(enc_msg, buf.size());
|
||||
|
||||
size_t cmd_len = encoded.size() + cmd_fmt.size() + m_access_token.size();
|
||||
char* cmd = new char[cmd_len];
|
||||
memset(cmd, 0, cmd_len);
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(cmd, cmd_len, cmd_fmt.data(), m_access_token.c_str(), encoded.c_str());
|
||||
#else
|
||||
sprintf(cmd, cmd_fmt.data(), m_access_token.c_str(), encoded.c_str());
|
||||
#endif
|
||||
Log.trace("call cmd:", cmd);
|
||||
std::string response = utils::callcmd(cmd);
|
||||
delete[] cmd;
|
||||
Log.trace("response:", response);
|
||||
|
||||
auto parse_res = json::parse(response);
|
||||
if (!parse_res) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
auto json = parse_res.value();
|
||||
return parse_response(json, out_result, pred);
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool asst::AipOcr::parse_response(const json::value& json, std::vector<TextRect>& out_result, const TextRectProc& pred)
|
||||
{
|
||||
if (!json.exist("words_result")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<TextRect> result;
|
||||
std::string log_str_raw;
|
||||
std::string log_str_proc;
|
||||
for (const auto& word : json.at("words_result").as_array()) {
|
||||
std::string text = word.at("words").as_string();
|
||||
|
||||
auto& loc = word.at("location").as_object();
|
||||
int left = loc.at("left").as_integer();
|
||||
int right = loc.at("right").as_integer();
|
||||
int top = loc.at("top").as_integer();
|
||||
int bottom = loc.at("bottom").as_integer();
|
||||
|
||||
Rect rect(left, top, right - left, bottom - top);
|
||||
|
||||
TextRect tr{ text, rect, 0 };
|
||||
|
||||
log_str_raw += tr.to_string() + ", ";
|
||||
if (!pred || pred(tr)) {
|
||||
log_str_proc += tr.to_string() + ", ";
|
||||
result.emplace_back(std::move(tr));
|
||||
}
|
||||
}
|
||||
|
||||
Log.trace("AipOcr::parse_response | raw : ", log_str_raw);
|
||||
Log.trace("AipOcr::parse_response | proc : ", log_str_proc);
|
||||
|
||||
out_result = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,111 +1,111 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "AbstractTask.h"
|
||||
#include "AsstDef.h"
|
||||
#include "AsstMsg.h"
|
||||
#include "AsstInfrastDef.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
class Mat;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Controller;
|
||||
class Identify;
|
||||
|
||||
class Assistant
|
||||
{
|
||||
public:
|
||||
Assistant(std::string dirname, AsstCallback callback = nullptr, void* callback_arg = nullptr);
|
||||
~Assistant();
|
||||
|
||||
// 根据配置文件,决定捕获模拟器、USB 还是远程设备
|
||||
bool catch_default();
|
||||
// 捕获模拟器
|
||||
bool catch_emulator(const std::string& emulator_name = std::string());
|
||||
// 捕获自定义设备
|
||||
bool catch_custom(const std::string& address = std::string());
|
||||
// 不实际进行捕获,调试用接口
|
||||
bool catch_fake();
|
||||
|
||||
// 添加开始游戏的任务(进入到主界面)
|
||||
bool append_start_up(bool only_append = true);
|
||||
// 添加刷理智任务
|
||||
bool append_fight(const std::string& stage, int mecidine = 0, int stone = 0, int times = INT_MAX, bool only_append = true);
|
||||
// 添加领取日常任务奖励任务
|
||||
bool append_award(bool only_append = true);
|
||||
// 添加访问好友任务
|
||||
bool append_visit(bool only_append = true);
|
||||
// 添加领取当日信用及信用购的任务
|
||||
bool append_mall(bool with_shopping, bool only_append = true);
|
||||
|
||||
// 添加基建换班任务任务
|
||||
bool append_infrast(infrast::WorkMode work_mode, const std::vector<std::string>& order, const std::string& uses_of_drones, double dorm_threshold, bool only_append = true);
|
||||
|
||||
// 添加自动公招任务
|
||||
// 参数max_times: 最多进行几次公招
|
||||
// 参数select_level: 需要的选择Tags的等级
|
||||
// 参数confirm_level: 需要点击确认按钮的等级
|
||||
bool append_recruit(unsigned max_times, const std::vector<int>& select_level, const std::vector<int>& confirm_level, bool need_refresh);
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
// 调试用
|
||||
bool append_debug();
|
||||
#endif
|
||||
|
||||
// 开始公开招募计算
|
||||
bool start_recruit_calc(const std::vector<int>& select_level, bool set_time);
|
||||
|
||||
// 开始执行任务队列
|
||||
bool start(bool block = true);
|
||||
// 停止任务队列并清空
|
||||
bool stop(bool block = true);
|
||||
|
||||
// 设置企鹅数据汇报个人ID
|
||||
void set_penguin_id(const std::string& id);
|
||||
|
||||
[[deprecated]] bool set_param(const std::string& type, const std::string& param, const std::string& value);
|
||||
|
||||
static constexpr int ProcessTaskRetryTimesDefault = 20;
|
||||
static constexpr int OpenRecruitTaskRetryTimesDefault = 10;
|
||||
static constexpr int AutoRecruitTaskRetryTimesDefault = 5;
|
||||
|
||||
private:
|
||||
void working_proc();
|
||||
void msg_proc();
|
||||
static void task_callback(AsstMsg msg, const json::value& detail, void* custom_arg);
|
||||
|
||||
bool append_process_task(const std::string& task, std::string task_chain = std::string(), int retry_times = ProcessTaskRetryTimesDefault);
|
||||
void append_callback(AsstMsg msg, json::value detail);
|
||||
void clear_cache();
|
||||
json::value organize_stage_drop(const json::value& rec); // 整理关卡掉落的材料信息
|
||||
|
||||
bool m_inited = false;
|
||||
std::string m_dirname;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
std::queue<std::shared_ptr<AbstractTask>> m_tasks_queue;
|
||||
AsstCallback m_callback = nullptr;
|
||||
void* m_callback_arg = nullptr;
|
||||
|
||||
bool m_thread_idle = true;
|
||||
std::thread m_working_thread;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condvar;
|
||||
|
||||
std::thread m_msg_thread;
|
||||
std::queue<std::pair<AsstMsg, json::value>> m_msg_queue;
|
||||
std::mutex m_msg_mutex;
|
||||
std::condition_variable m_msg_condvar;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "AbstractTask.h"
|
||||
#include "AsstDef.h"
|
||||
#include "AsstMsg.h"
|
||||
#include "AsstInfrastDef.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
class Mat;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Controller;
|
||||
class Identify;
|
||||
|
||||
class Assistant
|
||||
{
|
||||
public:
|
||||
Assistant(std::string dirname, AsstCallback callback = nullptr, void* callback_arg = nullptr);
|
||||
~Assistant();
|
||||
|
||||
// 根据配置文件,决定捕获模拟器、USB 还是远程设备
|
||||
bool catch_default();
|
||||
// 捕获模拟器
|
||||
bool catch_emulator(const std::string& emulator_name = std::string());
|
||||
// 捕获自定义设备
|
||||
bool catch_custom(const std::string& address = std::string());
|
||||
// 不实际进行捕获,调试用接口
|
||||
bool catch_fake();
|
||||
|
||||
// 添加开始游戏的任务(进入到主界面)
|
||||
bool append_start_up(bool only_append = true);
|
||||
// 添加刷理智任务
|
||||
bool append_fight(const std::string& stage, int mecidine = 0, int stone = 0, int times = INT_MAX, bool only_append = true);
|
||||
// 添加领取日常任务奖励任务
|
||||
bool append_award(bool only_append = true);
|
||||
// 添加访问好友任务
|
||||
bool append_visit(bool only_append = true);
|
||||
// 添加领取当日信用及信用购的任务
|
||||
bool append_mall(bool with_shopping, bool only_append = true);
|
||||
|
||||
// 添加基建换班任务任务
|
||||
bool append_infrast(infrast::WorkMode work_mode, const std::vector<std::string>& order, const std::string& uses_of_drones, double dorm_threshold, bool only_append = true);
|
||||
|
||||
// 添加自动公招任务
|
||||
// 参数max_times: 最多进行几次公招
|
||||
// 参数select_level: 需要的选择Tags的等级
|
||||
// 参数confirm_level: 需要点击确认按钮的等级
|
||||
bool append_recruit(unsigned max_times, const std::vector<int>& select_level, const std::vector<int>& confirm_level, bool need_refresh);
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
// 调试用
|
||||
bool append_debug();
|
||||
#endif
|
||||
|
||||
// 开始公开招募计算
|
||||
bool start_recruit_calc(const std::vector<int>& select_level, bool set_time);
|
||||
|
||||
// 开始执行任务队列
|
||||
bool start(bool block = true);
|
||||
// 停止任务队列并清空
|
||||
bool stop(bool block = true);
|
||||
|
||||
// 设置企鹅数据汇报个人ID
|
||||
void set_penguin_id(const std::string& id);
|
||||
|
||||
[[deprecated]] bool set_param(const std::string& type, const std::string& param, const std::string& value);
|
||||
|
||||
static constexpr int ProcessTaskRetryTimesDefault = 20;
|
||||
static constexpr int OpenRecruitTaskRetryTimesDefault = 10;
|
||||
static constexpr int AutoRecruitTaskRetryTimesDefault = 5;
|
||||
|
||||
private:
|
||||
void working_proc();
|
||||
void msg_proc();
|
||||
static void task_callback(AsstMsg msg, const json::value& detail, void* custom_arg);
|
||||
|
||||
bool append_process_task(const std::string& task, std::string task_chain = std::string(), int retry_times = ProcessTaskRetryTimesDefault);
|
||||
void append_callback(AsstMsg msg, json::value detail);
|
||||
void clear_cache();
|
||||
json::value organize_stage_drop(const json::value& rec); // 整理关卡掉落的材料信息
|
||||
|
||||
bool m_inited = false;
|
||||
std::string m_dirname;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
std::queue<std::shared_ptr<AbstractTask>> m_tasks_queue;
|
||||
AsstCallback m_callback = nullptr;
|
||||
void* m_callback_arg = nullptr;
|
||||
|
||||
bool m_thread_idle = true;
|
||||
std::thread m_working_thread;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condvar;
|
||||
|
||||
std::thread m_msg_thread;
|
||||
std::queue<std::pair<AsstMsg, json::value>> m_msg_queue;
|
||||
std::mutex m_msg_mutex;
|
||||
std::condition_variable m_msg_condvar;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,259 +1,264 @@
|
||||
#include "AsstCaller.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <meojson/json_value.h>
|
||||
|
||||
#include "Assistant.h"
|
||||
#include "AsstDef.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Version.h"
|
||||
|
||||
#if 0
|
||||
#if _MSC_VER
|
||||
// Win32平台下Dll的入口
|
||||
BOOL APIENTRY DllMain(HINSTANCE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hModule);
|
||||
UNREFERENCED_PARAMETER(lpReserved);
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#elif VA_GNUC
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
AsstCallback _callback = nullptr;
|
||||
|
||||
void CallbackTrans(asst::AsstMsg msg, const json::value& json, void* custom_arg)
|
||||
{
|
||||
_callback(static_cast<int>(msg), asst::utils::utf8_to_gbk(json.to_string()).c_str(), custom_arg);
|
||||
}
|
||||
|
||||
asst::Assistant* AsstCreate(const char* dirname)
|
||||
{
|
||||
try {
|
||||
return new asst::Assistant(dirname);
|
||||
}
|
||||
catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
asst::Assistant* AsstCreateEx(const char* dirname, AsstCallback callback, void* custom_arg)
|
||||
{
|
||||
try {
|
||||
// 创建多实例回调会有问题,有空再慢慢整
|
||||
_callback = callback;
|
||||
return new asst::Assistant(dirname, CallbackTrans, custom_arg);
|
||||
}
|
||||
catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AsstDestroy(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete p_asst;
|
||||
p_asst = nullptr;
|
||||
}
|
||||
|
||||
bool AsstCatchDefault(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((asst::Assistant*)p_asst)->catch_default();
|
||||
}
|
||||
|
||||
bool AsstCatchEmulator(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((asst::Assistant*)p_asst)->catch_emulator();
|
||||
}
|
||||
|
||||
bool AsstCatchCustom(asst::Assistant* p_asst, const char* address)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((asst::Assistant*)p_asst)->catch_custom(address);
|
||||
}
|
||||
|
||||
bool AsstCatchFake(asst::Assistant* p_asst)
|
||||
{
|
||||
#ifdef LOG_TRACE
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->catch_fake();
|
||||
#else
|
||||
return false;
|
||||
#endif // LOG_TRACE
|
||||
}
|
||||
|
||||
bool ASSTAPI AsstAppendStartUp(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_start_up();
|
||||
}
|
||||
|
||||
bool AsstAppendFight(asst::Assistant* p_asst, const char* stage, int max_mecidine, int max_stone, int max_times)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_fight(stage, max_mecidine, max_stone, max_times);
|
||||
}
|
||||
|
||||
bool AsstAppendAward(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_award();
|
||||
}
|
||||
|
||||
bool AsstAppendVisit(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_visit();
|
||||
}
|
||||
|
||||
bool AsstAppendMall(asst::Assistant* p_asst, bool with_shopping)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_mall(with_shopping);
|
||||
}
|
||||
|
||||
//bool AsstAppendProcessTask(asst::Assistant* p_asst, const char* task)
|
||||
//{
|
||||
// if (p_asst == nullptr) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return p_asst->append_process_task(task);
|
||||
//}
|
||||
|
||||
bool AsstStartRecruitCalc(asst::Assistant* p_asst, const int select_level[], int required_len, bool set_time)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<int> level_vector;
|
||||
level_vector.assign(select_level, select_level + required_len);
|
||||
return p_asst->start_recruit_calc(level_vector, set_time);
|
||||
}
|
||||
|
||||
bool AsstAppendInfrast(asst::Assistant* p_asst, int work_mode, const char** order, int order_size, const char* uses_of_drones, double dorm_threshold)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> order_vector;
|
||||
order_vector.assign(order, order + order_size);
|
||||
|
||||
return p_asst->append_infrast(
|
||||
static_cast<asst::infrast::WorkMode>(work_mode),
|
||||
order_vector,
|
||||
uses_of_drones,
|
||||
dorm_threshold);
|
||||
}
|
||||
|
||||
bool AsstAppendRecruit(asst::Assistant* p_asst, int max_times, const int select_level[], int select_len, const int confirm_level[], int confirm_len, bool need_refresh)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<int> required_vector;
|
||||
required_vector.assign(select_level, select_level + select_len);
|
||||
std::vector<int> confirm_vector;
|
||||
confirm_vector.assign(confirm_level, confirm_level + confirm_len);
|
||||
|
||||
return p_asst->append_recruit(max_times, required_vector, confirm_vector, need_refresh);
|
||||
}
|
||||
|
||||
bool AsstStart(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->start();
|
||||
}
|
||||
|
||||
bool AsstStop(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->stop();
|
||||
}
|
||||
|
||||
bool AsstSetPenguinId(asst::Assistant* p_asst, const char* id)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p_asst->set_penguin_id(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool AsstSetParam(asst::Assistant* p_asst, const char* type, const char* param, const char* value)
|
||||
//{
|
||||
// if (p_asst == nullptr) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return p_asst->set_param(type, param, value);
|
||||
//}
|
||||
|
||||
const char* AsstGetVersion()
|
||||
{
|
||||
return asst::Version;
|
||||
}
|
||||
|
||||
bool AsstAppendDebug(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
#if LOG_TRACE
|
||||
return p_asst->append_debug();
|
||||
#else
|
||||
return false;
|
||||
#endif // LOG_TRACE
|
||||
}
|
||||
#include "AsstCaller.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <meojson/json_value.h>
|
||||
|
||||
#include "Assistant.h"
|
||||
#include "AsstDef.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Version.h"
|
||||
|
||||
#if 0
|
||||
#if _MSC_VER
|
||||
// Win32平台下Dll的入口
|
||||
BOOL APIENTRY DllMain(HINSTANCE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hModule);
|
||||
UNREFERENCED_PARAMETER(lpReserved);
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#elif VA_GNUC
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
AsstCallback _callback = nullptr;
|
||||
|
||||
void CallbackTrans(asst::AsstMsg msg, const json::value& json, void* custom_arg)
|
||||
{
|
||||
_callback(static_cast<int>(msg), asst::utils::utf8_to_gbk(json.to_string()).c_str(), custom_arg);
|
||||
}
|
||||
|
||||
asst::Assistant* AsstCreate(const char* dirname)
|
||||
{
|
||||
try {
|
||||
return new asst::Assistant(dirname);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::cerr << "create failed: " << e.what() << std::endl;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "create failed: unknown exception" << std::endl;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
asst::Assistant* AsstCreateEx(const char* dirname, AsstCallback callback, void* custom_arg)
|
||||
{
|
||||
try {
|
||||
// 创建多实例回调会有问题,有空再慢慢整
|
||||
_callback = callback;
|
||||
return new asst::Assistant(dirname, CallbackTrans, custom_arg);
|
||||
}
|
||||
catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AsstDestroy(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete p_asst;
|
||||
p_asst = nullptr;
|
||||
}
|
||||
|
||||
bool AsstCatchDefault(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((asst::Assistant*)p_asst)->catch_default();
|
||||
}
|
||||
|
||||
bool AsstCatchEmulator(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((asst::Assistant*)p_asst)->catch_emulator();
|
||||
}
|
||||
|
||||
bool AsstCatchCustom(asst::Assistant* p_asst, const char* address)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((asst::Assistant*)p_asst)->catch_custom(address);
|
||||
}
|
||||
|
||||
bool AsstCatchFake(asst::Assistant* p_asst)
|
||||
{
|
||||
#ifdef LOG_TRACE
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->catch_fake();
|
||||
#else
|
||||
return false;
|
||||
#endif // LOG_TRACE
|
||||
}
|
||||
|
||||
bool ASSTAPI AsstAppendStartUp(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_start_up();
|
||||
}
|
||||
|
||||
bool AsstAppendFight(asst::Assistant* p_asst, const char* stage, int max_mecidine, int max_stone, int max_times)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_fight(stage, max_mecidine, max_stone, max_times);
|
||||
}
|
||||
|
||||
bool AsstAppendAward(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_award();
|
||||
}
|
||||
|
||||
bool AsstAppendVisit(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_visit();
|
||||
}
|
||||
|
||||
bool AsstAppendMall(asst::Assistant* p_asst, bool with_shopping)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->append_mall(with_shopping);
|
||||
}
|
||||
|
||||
//bool AsstAppendProcessTask(asst::Assistant* p_asst, const char* task)
|
||||
//{
|
||||
// if (p_asst == nullptr) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return p_asst->append_process_task(task);
|
||||
//}
|
||||
|
||||
bool AsstStartRecruitCalc(asst::Assistant* p_asst, const int select_level[], int required_len, bool set_time)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<int> level_vector;
|
||||
level_vector.assign(select_level, select_level + required_len);
|
||||
return p_asst->start_recruit_calc(level_vector, set_time);
|
||||
}
|
||||
|
||||
bool AsstAppendInfrast(asst::Assistant* p_asst, int work_mode, const char** order, int order_size, const char* uses_of_drones, double dorm_threshold)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> order_vector;
|
||||
order_vector.assign(order, order + order_size);
|
||||
|
||||
return p_asst->append_infrast(
|
||||
static_cast<asst::infrast::WorkMode>(work_mode),
|
||||
order_vector,
|
||||
uses_of_drones,
|
||||
dorm_threshold);
|
||||
}
|
||||
|
||||
bool AsstAppendRecruit(asst::Assistant* p_asst, int max_times, const int select_level[], int select_len, const int confirm_level[], int confirm_len, bool need_refresh)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::vector<int> required_vector;
|
||||
required_vector.assign(select_level, select_level + select_len);
|
||||
std::vector<int> confirm_vector;
|
||||
confirm_vector.assign(confirm_level, confirm_level + confirm_len);
|
||||
|
||||
return p_asst->append_recruit(max_times, required_vector, confirm_vector, need_refresh);
|
||||
}
|
||||
|
||||
bool AsstStart(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->start();
|
||||
}
|
||||
|
||||
bool AsstStop(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_asst->stop();
|
||||
}
|
||||
|
||||
bool AsstSetPenguinId(asst::Assistant* p_asst, const char* id)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p_asst->set_penguin_id(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool AsstSetParam(asst::Assistant* p_asst, const char* type, const char* param, const char* value)
|
||||
//{
|
||||
// if (p_asst == nullptr) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return p_asst->set_param(type, param, value);
|
||||
//}
|
||||
|
||||
const char* AsstGetVersion()
|
||||
{
|
||||
return asst::Version;
|
||||
}
|
||||
|
||||
bool AsstAppendDebug(asst::Assistant* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return false;
|
||||
}
|
||||
#if LOG_TRACE
|
||||
return p_asst->append_debug();
|
||||
#else
|
||||
return false;
|
||||
#endif // LOG_TRACE
|
||||
}
|
||||
|
||||
@@ -1,258 +1,259 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace json
|
||||
{
|
||||
class value;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
constexpr double DoubleDiff = 1e-12;
|
||||
|
||||
constexpr static int WindowWidthDefault = 1280;
|
||||
constexpr static int WindowHeightDefault = 720;
|
||||
|
||||
constexpr static double TemplThresholdDefault = 0.8;
|
||||
|
||||
struct Point
|
||||
{
|
||||
Point() = default;
|
||||
Point(const Point&) noexcept = default;
|
||||
Point(Point&&) noexcept = default;
|
||||
Point(int x, int y) : x(x), y(y) {}
|
||||
Point& operator=(const Point&) noexcept = default;
|
||||
Point& operator=(Point&&) noexcept = default;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
Rect() = default;
|
||||
Rect(const Rect&) noexcept = default;
|
||||
Rect(Rect&&) noexcept = default;
|
||||
Rect(int x, int y, int width, int height)
|
||||
: x(x), y(y), width(width), height(height)
|
||||
{}
|
||||
Rect operator*(double rhs) const
|
||||
{
|
||||
return { x, y, static_cast<int>(width * rhs), static_cast<int>(height * rhs) };
|
||||
}
|
||||
int area() const noexcept
|
||||
{
|
||||
return width * height;
|
||||
}
|
||||
Rect center_zoom(double scale, int max_width = INT_MAX, int max_height = INT_MAX) const
|
||||
{
|
||||
int half_width_scale = static_cast<int>(width * (1 - scale) / 2);
|
||||
int half_hight_scale = static_cast<int>(height * (1 - scale) / 2);
|
||||
Rect dst(x + half_width_scale, y + half_hight_scale,
|
||||
static_cast<int>(width * scale), static_cast<int>(height * scale));
|
||||
if (dst.x < 0) {
|
||||
dst.x = 0;
|
||||
}
|
||||
if (dst.y < 0) {
|
||||
dst.y = 0;
|
||||
}
|
||||
if (dst.width + dst.x >= max_width) {
|
||||
dst.width = max_width - dst.x;
|
||||
}
|
||||
if (dst.height + dst.y >= max_height) {
|
||||
dst.height = max_height - dst.y;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
Rect& operator=(const Rect&) noexcept = default;
|
||||
Rect& operator=(Rect&&) noexcept = default;
|
||||
bool empty() const noexcept { return width == 0 || height == 0; }
|
||||
bool operator==(const Rect& rhs) const noexcept
|
||||
{
|
||||
return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
|
||||
}
|
||||
bool include(const Rect& rhs) const noexcept
|
||||
{
|
||||
return x <= rhs.x && y <= rhs.y && (x + width) >= (rhs.x + rhs.width) && (y + height) >= (rhs.y + rhs.height);
|
||||
}
|
||||
std::string to_string() const
|
||||
{
|
||||
return "[ " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(width) + ", " + std::to_string(height) + " ]";
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
};
|
||||
|
||||
struct TextRect
|
||||
{
|
||||
TextRect() = default;
|
||||
TextRect(const TextRect&) = default;
|
||||
TextRect(TextRect&&) noexcept = default;
|
||||
|
||||
explicit operator std::string() const noexcept { return text; }
|
||||
explicit operator Rect() const noexcept { return rect; }
|
||||
std::string to_string() const
|
||||
{
|
||||
return text + " : " + rect.to_string() + ", score: " + std::to_string(score);
|
||||
}
|
||||
TextRect& operator=(const TextRect&) = default;
|
||||
TextRect& operator=(TextRect&&) noexcept = default;
|
||||
bool operator==(const TextRect& rhs) const noexcept
|
||||
{
|
||||
return text == rhs.text && rect == rhs.rect;
|
||||
}
|
||||
|
||||
std::string text;
|
||||
Rect rect;
|
||||
float score;
|
||||
};
|
||||
using TextRectProc = std::function<bool(TextRect&)>;
|
||||
|
||||
enum class AlgorithmType
|
||||
{
|
||||
Invaild = -1,
|
||||
JustReturn,
|
||||
MatchTemplate,
|
||||
CompareHist,
|
||||
OcrDetect
|
||||
};
|
||||
|
||||
struct MatchRect
|
||||
{
|
||||
MatchRect() = default;
|
||||
MatchRect(const MatchRect&) = default;
|
||||
MatchRect(MatchRect&&) noexcept = default;
|
||||
|
||||
explicit operator Rect() const noexcept { return rect; }
|
||||
MatchRect& operator=(const MatchRect&) = default;
|
||||
MatchRect& operator=(MatchRect&&) noexcept = default;
|
||||
|
||||
AlgorithmType algorithm = AlgorithmType::Invaild;
|
||||
double score = 0.0;
|
||||
Rect rect;
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
class hash<asst::Rect>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const asst::Rect& rect) const
|
||||
{
|
||||
return std::hash<int>()(rect.x) ^ std::hash<int>()(rect.y) ^ std::hash<int>()(rect.width) ^ std::hash<int>()(rect.height);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class hash<asst::TextRect>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const asst::TextRect& tr) const
|
||||
{
|
||||
return std::hash<std::string>()(tr.text) ^ std::hash<asst::Rect>()(tr.rect);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
enum class ProcessTaskAction
|
||||
{
|
||||
Invalid = 0,
|
||||
BasicClick = 0x100,
|
||||
ClickSelf = BasicClick | 1, // 点击自身位置
|
||||
ClickRect = BasicClick | 2, // 点击指定区域
|
||||
ClickRand = BasicClick | 4, // 点击随机区域
|
||||
DoNothing = 0x200, // 什么都不做
|
||||
Stop = 0x400, // 停止当前Task
|
||||
StageDrops = 0x800, // 关卡结束,特化动作
|
||||
BasicSwipe = 0x1000,
|
||||
SwipeToTheLeft = BasicSwipe | 1, // 往左划一下
|
||||
SwipeToTheRight = BasicSwipe | 2, // 往右划一下
|
||||
};
|
||||
|
||||
// 任务信息
|
||||
struct TaskInfo
|
||||
{
|
||||
virtual ~TaskInfo() = default;
|
||||
std::string name; // 任务名
|
||||
AlgorithmType algorithm = // 图像算法类型
|
||||
AlgorithmType::Invaild;
|
||||
ProcessTaskAction action = // 要进行的操作
|
||||
ProcessTaskAction::Invalid;
|
||||
std::vector<std::string> next; // 下一个可能的任务(列表)
|
||||
[[ deprecated ]] int exec_times = 0; // [已废弃] 任务已执行了多少次
|
||||
int max_times = INT_MAX; // 任务最多执行多少次
|
||||
std::vector<std::string> exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
|
||||
std::vector<std::string> reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1
|
||||
asst::Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域
|
||||
int pre_delay = 0; // 执行该任务前的延时
|
||||
int rear_delay = 0; // 执行该任务后的延时
|
||||
int retry_times = INT_MAX; // 未找到图像时的重试次数
|
||||
Rect roi; // 要识别的区域,若为0则全图识别
|
||||
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。即识别到了res,点击res + result_move的位置
|
||||
bool cache = false; // 是否使用缓存区域
|
||||
Rect region_of_appeared; // 缓存区域:上次识别成功过,本次只在这个rect里识别,省点性能
|
||||
};
|
||||
|
||||
// 文字识别任务的信息
|
||||
struct OcrTaskInfo : public TaskInfo
|
||||
{
|
||||
virtual ~OcrTaskInfo() = default;
|
||||
std::vector<std::string> text; // 文字的容器,匹配到这里面任一个,就算匹配上了
|
||||
bool need_full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
|
||||
std::unordered_map<std::string, std::string>
|
||||
replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配
|
||||
};
|
||||
|
||||
// 图片匹配任务的信息
|
||||
struct MatchTaskInfo : public TaskInfo
|
||||
{
|
||||
virtual ~MatchTaskInfo() = default;
|
||||
std::string templ_name; // 匹配模板图片文件名
|
||||
double templ_threshold = 0; // 模板匹配阈值
|
||||
double special_threshold = 0; // 某些任务使用的特殊的阈值
|
||||
std::pair<int, int> mask_range; // 掩码的二值化范围
|
||||
};
|
||||
|
||||
struct HandleInfo
|
||||
{
|
||||
std::string class_name;
|
||||
std::string window_name;
|
||||
};
|
||||
|
||||
struct AdbCmd
|
||||
{
|
||||
std::string path;
|
||||
std::vector<std::string> addresses; // 会优先尝试连接addresses中的地址,若均失败,则会使用devices获取地址
|
||||
std::string devices;
|
||||
std::string address_regex;
|
||||
std::string connect;
|
||||
std::string click;
|
||||
std::string swipe;
|
||||
std::string display;
|
||||
std::string display_format;
|
||||
std::string screencap;
|
||||
std::string release;
|
||||
//std::string pullscreen;
|
||||
int display_width = 0;
|
||||
int display_height = 0;
|
||||
};
|
||||
|
||||
struct EmulatorInfo
|
||||
{
|
||||
std::string name;
|
||||
HandleInfo handle;
|
||||
AdbCmd adb;
|
||||
std::string path;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <climits>
|
||||
|
||||
namespace json
|
||||
{
|
||||
class value;
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
constexpr double DoubleDiff = 1e-12;
|
||||
|
||||
constexpr static int WindowWidthDefault = 1280;
|
||||
constexpr static int WindowHeightDefault = 720;
|
||||
|
||||
constexpr static double TemplThresholdDefault = 0.8;
|
||||
|
||||
struct Point
|
||||
{
|
||||
Point() = default;
|
||||
Point(const Point&) noexcept = default;
|
||||
Point(Point&&) noexcept = default;
|
||||
Point(int x, int y) : x(x), y(y) {}
|
||||
Point& operator=(const Point&) noexcept = default;
|
||||
Point& operator=(Point&&) noexcept = default;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
Rect() = default;
|
||||
Rect(const Rect&) noexcept = default;
|
||||
Rect(Rect&&) noexcept = default;
|
||||
Rect(int x, int y, int width, int height)
|
||||
: x(x), y(y), width(width), height(height)
|
||||
{}
|
||||
Rect operator*(double rhs) const
|
||||
{
|
||||
return { x, y, static_cast<int>(width * rhs), static_cast<int>(height * rhs) };
|
||||
}
|
||||
int area() const noexcept
|
||||
{
|
||||
return width * height;
|
||||
}
|
||||
Rect center_zoom(double scale, int max_width = INT_MAX, int max_height = INT_MAX) const
|
||||
{
|
||||
int half_width_scale = static_cast<int>(width * (1 - scale) / 2);
|
||||
int half_hight_scale = static_cast<int>(height * (1 - scale) / 2);
|
||||
Rect dst(x + half_width_scale, y + half_hight_scale,
|
||||
static_cast<int>(width * scale), static_cast<int>(height * scale));
|
||||
if (dst.x < 0) {
|
||||
dst.x = 0;
|
||||
}
|
||||
if (dst.y < 0) {
|
||||
dst.y = 0;
|
||||
}
|
||||
if (dst.width + dst.x >= max_width) {
|
||||
dst.width = max_width - dst.x;
|
||||
}
|
||||
if (dst.height + dst.y >= max_height) {
|
||||
dst.height = max_height - dst.y;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
Rect& operator=(const Rect&) noexcept = default;
|
||||
Rect& operator=(Rect&&) noexcept = default;
|
||||
bool empty() const noexcept { return width == 0 || height == 0; }
|
||||
bool operator==(const Rect& rhs) const noexcept
|
||||
{
|
||||
return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
|
||||
}
|
||||
bool include(const Rect& rhs) const noexcept
|
||||
{
|
||||
return x <= rhs.x && y <= rhs.y && (x + width) >= (rhs.x + rhs.width) && (y + height) >= (rhs.y + rhs.height);
|
||||
}
|
||||
std::string to_string() const
|
||||
{
|
||||
return "[ " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(width) + ", " + std::to_string(height) + " ]";
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
};
|
||||
|
||||
struct TextRect
|
||||
{
|
||||
TextRect() = default;
|
||||
TextRect(const TextRect&) = default;
|
||||
TextRect(TextRect&&) noexcept = default;
|
||||
|
||||
explicit operator std::string() const noexcept { return text; }
|
||||
explicit operator Rect() const noexcept { return rect; }
|
||||
std::string to_string() const
|
||||
{
|
||||
return text + " : " + rect.to_string() + ", score: " + std::to_string(score);
|
||||
}
|
||||
TextRect& operator=(const TextRect&) = default;
|
||||
TextRect& operator=(TextRect&&) noexcept = default;
|
||||
bool operator==(const TextRect& rhs) const noexcept
|
||||
{
|
||||
return text == rhs.text && rect == rhs.rect;
|
||||
}
|
||||
|
||||
std::string text;
|
||||
Rect rect;
|
||||
float score;
|
||||
};
|
||||
using TextRectProc = std::function<bool(TextRect&)>;
|
||||
|
||||
enum class AlgorithmType
|
||||
{
|
||||
Invaild = -1,
|
||||
JustReturn,
|
||||
MatchTemplate,
|
||||
CompareHist,
|
||||
OcrDetect
|
||||
};
|
||||
|
||||
struct MatchRect
|
||||
{
|
||||
MatchRect() = default;
|
||||
MatchRect(const MatchRect&) = default;
|
||||
MatchRect(MatchRect&&) noexcept = default;
|
||||
|
||||
explicit operator Rect() const noexcept { return rect; }
|
||||
MatchRect& operator=(const MatchRect&) = default;
|
||||
MatchRect& operator=(MatchRect&&) noexcept = default;
|
||||
|
||||
AlgorithmType algorithm = AlgorithmType::Invaild;
|
||||
double score = 0.0;
|
||||
Rect rect;
|
||||
};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
class hash<asst::Rect>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const asst::Rect& rect) const
|
||||
{
|
||||
return std::hash<int>()(rect.x) ^ std::hash<int>()(rect.y) ^ std::hash<int>()(rect.width) ^ std::hash<int>()(rect.height);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class hash<asst::TextRect>
|
||||
{
|
||||
public:
|
||||
size_t operator()(const asst::TextRect& tr) const
|
||||
{
|
||||
return std::hash<std::string>()(tr.text) ^ std::hash<asst::Rect>()(tr.rect);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace asst
|
||||
{
|
||||
enum class ProcessTaskAction
|
||||
{
|
||||
Invalid = 0,
|
||||
BasicClick = 0x100,
|
||||
ClickSelf = BasicClick | 1, // 点击自身位置
|
||||
ClickRect = BasicClick | 2, // 点击指定区域
|
||||
ClickRand = BasicClick | 4, // 点击随机区域
|
||||
DoNothing = 0x200, // 什么都不做
|
||||
Stop = 0x400, // 停止当前Task
|
||||
StageDrops = 0x800, // 关卡结束,特化动作
|
||||
BasicSwipe = 0x1000,
|
||||
SwipeToTheLeft = BasicSwipe | 1, // 往左划一下
|
||||
SwipeToTheRight = BasicSwipe | 2, // 往右划一下
|
||||
};
|
||||
|
||||
// 任务信息
|
||||
struct TaskInfo
|
||||
{
|
||||
virtual ~TaskInfo() = default;
|
||||
std::string name; // 任务名
|
||||
AlgorithmType algorithm = // 图像算法类型
|
||||
AlgorithmType::Invaild;
|
||||
ProcessTaskAction action = // 要进行的操作
|
||||
ProcessTaskAction::Invalid;
|
||||
std::vector<std::string> next; // 下一个可能的任务(列表)
|
||||
[[ deprecated ]] int exec_times = 0; // [已废弃] 任务已执行了多少次
|
||||
int max_times = INT_MAX; // 任务最多执行多少次
|
||||
std::vector<std::string> exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
|
||||
std::vector<std::string> reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1
|
||||
asst::Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域
|
||||
int pre_delay = 0; // 执行该任务前的延时
|
||||
int rear_delay = 0; // 执行该任务后的延时
|
||||
int retry_times = INT_MAX; // 未找到图像时的重试次数
|
||||
Rect roi; // 要识别的区域,若为0则全图识别
|
||||
Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。即识别到了res,点击res + result_move的位置
|
||||
bool cache = false; // 是否使用缓存区域
|
||||
Rect region_of_appeared; // 缓存区域:上次识别成功过,本次只在这个rect里识别,省点性能
|
||||
};
|
||||
|
||||
// 文字识别任务的信息
|
||||
struct OcrTaskInfo : public TaskInfo
|
||||
{
|
||||
virtual ~OcrTaskInfo() = default;
|
||||
std::vector<std::string> text; // 文字的容器,匹配到这里面任一个,就算匹配上了
|
||||
bool need_full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
|
||||
std::unordered_map<std::string, std::string>
|
||||
replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配
|
||||
};
|
||||
|
||||
// 图片匹配任务的信息
|
||||
struct MatchTaskInfo : public TaskInfo
|
||||
{
|
||||
virtual ~MatchTaskInfo() = default;
|
||||
std::string templ_name; // 匹配模板图片文件名
|
||||
double templ_threshold = 0; // 模板匹配阈值
|
||||
double special_threshold = 0; // 某些任务使用的特殊的阈值
|
||||
std::pair<int, int> mask_range; // 掩码的二值化范围
|
||||
};
|
||||
|
||||
struct HandleInfo
|
||||
{
|
||||
std::string class_name;
|
||||
std::string window_name;
|
||||
};
|
||||
|
||||
struct AdbCmd
|
||||
{
|
||||
std::string path;
|
||||
std::vector<std::string> addresses; // 会优先尝试连接addresses中的地址,若均失败,则会使用devices获取地址
|
||||
std::string devices;
|
||||
std::string address_regex;
|
||||
std::string connect;
|
||||
std::string click;
|
||||
std::string swipe;
|
||||
std::string display;
|
||||
std::string display_format;
|
||||
std::string screencap;
|
||||
std::string release;
|
||||
//std::string pullscreen;
|
||||
int display_width = 0;
|
||||
int display_height = 0;
|
||||
};
|
||||
|
||||
struct EmulatorInfo
|
||||
{
|
||||
std::string name;
|
||||
HandleInfo handle;
|
||||
AdbCmd adb;
|
||||
std::string path;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,229 +1,270 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace asst
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
static std::string string_replace_all(const std::string& src, const std::string& old_value, const std::string& new_value)
|
||||
{
|
||||
std::string str = src;
|
||||
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)
|
||||
str.replace(pos, old_value.length(), new_value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::vector<std::string> string_split(const std::string& str, const std::string& delimiter)
|
||||
{
|
||||
std::string::size_type pos1 = 0;
|
||||
std::string::size_type pos2 = str.find(delimiter);
|
||||
std::vector<std::string> result;
|
||||
|
||||
while (std::string::npos != pos2) {
|
||||
result.emplace_back(str.substr(pos1, pos2 - pos1));
|
||||
|
||||
pos1 = pos2 + delimiter.size();
|
||||
pos2 = str.find(delimiter, pos1);
|
||||
}
|
||||
if (pos1 != str.length())
|
||||
result.emplace_back(str.substr(pos1));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string get_format_time()
|
||||
{
|
||||
SYSTEMTIME curtime;
|
||||
GetLocalTime(&curtime);
|
||||
char buff[64] = { 0 };
|
||||
sprintf_s(buff, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
||||
curtime.wYear, curtime.wMonth, curtime.wDay,
|
||||
curtime.wHour, curtime.wMinute, curtime.wSecond, curtime.wMilliseconds);
|
||||
return buff;
|
||||
}
|
||||
|
||||
static std::string gbk_2_utf8(const std::string& gbk_str)
|
||||
{
|
||||
const char* src_str = gbk_str.c_str();
|
||||
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
|
||||
wchar_t* wstr = new wchar_t[len + 1];
|
||||
memset(wstr, 0, len + 1);
|
||||
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
|
||||
char* str = new char[len + 1];
|
||||
memset(str, 0, len + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
|
||||
std::string strTemp = str;
|
||||
if (wstr)
|
||||
delete[] wstr;
|
||||
if (str)
|
||||
delete[] str;
|
||||
return strTemp;
|
||||
}
|
||||
|
||||
static std::string utf8_to_gbk(const std::string& utf8_str)
|
||||
{
|
||||
const char* src_str = utf8_str.c_str();
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0);
|
||||
wchar_t* wszGBK = new wchar_t[len + 1];
|
||||
memset(wszGBK, 0, len * 2 + 2);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len);
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
|
||||
char* szGBK = new char[len + 1];
|
||||
memset(szGBK, 0, len + 1);
|
||||
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
|
||||
std::string strTemp(szGBK);
|
||||
if (wszGBK)
|
||||
delete[] wszGBK;
|
||||
if (szGBK)
|
||||
delete[] szGBK;
|
||||
return strTemp;
|
||||
}
|
||||
|
||||
template <typename RetTy, typename ArgType>
|
||||
constexpr inline RetTy make_rect(const ArgType& rect)
|
||||
{
|
||||
return RetTy{ rect.x, rect.y, rect.width, rect.height };
|
||||
}
|
||||
|
||||
static std::string load_file_without_bom(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
return std::string();
|
||||
}
|
||||
std::stringstream iss;
|
||||
iss << ifs.rdbuf();
|
||||
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;
|
||||
|
||||
if (str.size() >= 3 && static_cast<uchar>(str.at(0)) == Bom_0 && static_cast<uchar>(str.at(1)) == Bom_1 && static_cast<uchar>(str.at(2)) == Bom_2) {
|
||||
str.assign(str.begin() + 3, str.end());
|
||||
return str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static int hamming(std::string hash1, std::string hash2)
|
||||
{
|
||||
constexpr static int HammingFlags = 64;
|
||||
|
||||
hash1.insert(hash1.begin(), HammingFlags - hash1.size(), '0');
|
||||
hash2.insert(hash2.begin(), HammingFlags - hash2.size(), '0');
|
||||
int dist = 0;
|
||||
for (int i = 0; i < HammingFlags; i = i + 16) {
|
||||
unsigned long long x = strtoull(hash1.substr(i, 16).c_str(), NULL, 16) ^ strtoull(hash2.substr(i, 16).c_str(), NULL, 16);
|
||||
while (x) {
|
||||
dist++;
|
||||
x = x & (x - 1);
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
static std::string callcmd(const std::string& cmdline)
|
||||
{
|
||||
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
|
||||
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
pipe_sec_attr.lpSecurityDescriptor = nullptr;
|
||||
pipe_sec_attr.bInheritHandle = TRUE;
|
||||
HANDLE pipe_read = nullptr;
|
||||
HANDLE pipe_child_write = nullptr;
|
||||
CreatePipe(&pipe_read, &pipe_child_write, &pipe_sec_attr, 4096);
|
||||
|
||||
STARTUPINFOA si = { 0 };
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = pipe_child_write;
|
||||
si.hStdError = pipe_child_write;
|
||||
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
|
||||
BOOL p_ret = CreateProcessA(NULL, const_cast<LPSTR>(cmdline.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
|
||||
std::string pipe_str;
|
||||
if (p_ret) {
|
||||
DWORD read_num = 0;
|
||||
DWORD std_num = 0;
|
||||
do {
|
||||
while (::PeekNamedPipe(pipe_read, NULL, 0, NULL, &read_num, NULL) && read_num > 0) {
|
||||
char* pipe_buffer = new char[read_num];
|
||||
BOOL read_ret = ::ReadFile(pipe_read, pipe_buffer, read_num, &std_num, NULL);
|
||||
if (read_ret) {
|
||||
pipe_str.append(pipe_buffer, pipe_buffer + std_num);
|
||||
}
|
||||
if (pipe_buffer != nullptr) {
|
||||
delete[] pipe_buffer;
|
||||
pipe_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
} while (::WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT);
|
||||
|
||||
DWORD exit_ret = -1;
|
||||
::GetExitCodeProcess(pi.hProcess, &exit_ret);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
::CloseHandle(pipe_read);
|
||||
::CloseHandle(pipe_child_write);
|
||||
|
||||
return pipe_str;
|
||||
}
|
||||
|
||||
//template<typename T,
|
||||
// typename = typename std::enable_if<std::is_constructible<T, std::string>::value>::type>
|
||||
// std::string VectorToString(const std::vector<T>& vector, bool to_gbk = false) {
|
||||
// if (vector.empty()) {
|
||||
// return std::string();
|
||||
// }
|
||||
// static const std::string inter = ", ";
|
||||
// std::string str;
|
||||
// for (const T& ele : vector) {
|
||||
// if (to_gbk) {
|
||||
// str += utils::utf8_to_gbk(ele) + inter;
|
||||
// }
|
||||
// else {
|
||||
// str += ele + inter;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!str.empty()) {
|
||||
// str.erase(str.size() - inter.size(), inter.size());
|
||||
// }
|
||||
// return str;
|
||||
//}
|
||||
|
||||
//template<typename T,
|
||||
// typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
|
||||
// std::string VectorToString(const std::vector<T>& vector) {
|
||||
// if (vector.empty()) {
|
||||
// return std::string();
|
||||
// }
|
||||
// static const std::string inter = ", ";
|
||||
// std::string str;
|
||||
// for (const T& ele : vector) {
|
||||
// str += std::to_string(ele) + inter;
|
||||
// }
|
||||
|
||||
// if (!str.empty()) {
|
||||
// str.erase(str.size() - inter.size(), inter.size());
|
||||
// }
|
||||
// return str;
|
||||
//}
|
||||
}
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace asst
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
static std::string string_replace_all(const std::string& src, const std::string& old_value, const std::string& new_value)
|
||||
{
|
||||
std::string str = src;
|
||||
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)
|
||||
str.replace(pos, old_value.length(), new_value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::vector<std::string> string_split(const std::string& str, const std::string& delimiter)
|
||||
{
|
||||
std::string::size_type pos1 = 0;
|
||||
std::string::size_type pos2 = str.find(delimiter);
|
||||
std::vector<std::string> result;
|
||||
|
||||
while (std::string::npos != pos2) {
|
||||
result.emplace_back(str.substr(pos1, pos2 - pos1));
|
||||
|
||||
pos1 = pos2 + delimiter.size();
|
||||
pos2 = str.find(delimiter, pos1);
|
||||
}
|
||||
if (pos1 != str.length())
|
||||
result.emplace_back(str.substr(pos1));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string get_format_time()
|
||||
{
|
||||
char buff[128] = { 0 };
|
||||
#ifdef _WIN32
|
||||
SYSTEMTIME curtime;
|
||||
GetLocalTime(&curtime);
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buff, sizeof(buff),
|
||||
#else // ! _MSC_VER
|
||||
sprintf(buff,
|
||||
#endif // END _MSC_VER
|
||||
"%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
||||
curtime.wYear, curtime.wMonth, curtime.wDay,
|
||||
curtime.wHour, curtime.wMinute, curtime.wSecond, curtime.wMilliseconds);
|
||||
|
||||
#else // ! _WIN32
|
||||
struct timeval tv = { 0 };
|
||||
gettimeofday(&tv, NULL);
|
||||
time_t nowtime = tv.tv_sec;
|
||||
struct tm* tm_info = localtime(&nowtime);
|
||||
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
sprintf(buff, "%s.%03d", buff, tv.tv_usec / 1000);
|
||||
#endif // END _WIN32
|
||||
return buff;
|
||||
}
|
||||
|
||||
static std::string gbk_2_utf8(const std::string& gbk_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char* src_str = gbk_str.c_str();
|
||||
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
|
||||
wchar_t* wstr = new wchar_t[len + 1];
|
||||
memset(wstr, 0, len + 1);
|
||||
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
|
||||
char* str = new char[len + 1];
|
||||
memset(str, 0, len + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
|
||||
std::string strTemp = str;
|
||||
if (wstr)
|
||||
delete[] wstr;
|
||||
if (str)
|
||||
delete[] str;
|
||||
return strTemp;
|
||||
#else // Don't fucking use gbk in linux!
|
||||
return gbk_str;
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::string utf8_to_gbk(const std::string& utf8_str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char* src_str = utf8_str.c_str();
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0);
|
||||
wchar_t* wszGBK = new wchar_t[len + 1];
|
||||
memset(wszGBK, 0, len * 2 + 2);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len);
|
||||
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
|
||||
char* szGBK = new char[len + 1];
|
||||
memset(szGBK, 0, len + 1);
|
||||
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
|
||||
std::string strTemp(szGBK);
|
||||
if (wszGBK)
|
||||
delete[] wszGBK;
|
||||
if (szGBK)
|
||||
delete[] szGBK;
|
||||
return strTemp;
|
||||
#else // Don't fucking use gbk in linux!
|
||||
return utf8_str;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename RetTy, typename ArgType>
|
||||
constexpr inline RetTy make_rect(const ArgType& rect)
|
||||
{
|
||||
return RetTy{ rect.x, rect.y, rect.width, rect.height };
|
||||
}
|
||||
|
||||
static std::string load_file_without_bom(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
return std::string();
|
||||
}
|
||||
std::stringstream iss;
|
||||
iss << ifs.rdbuf();
|
||||
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;
|
||||
|
||||
if (str.size() >= 3 && static_cast<uchar>(str.at(0)) == Bom_0 && static_cast<uchar>(str.at(1)) == Bom_1 && static_cast<uchar>(str.at(2)) == Bom_2) {
|
||||
str.assign(str.begin() + 3, str.end());
|
||||
return str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static int hamming(std::string hash1, std::string hash2)
|
||||
{
|
||||
constexpr static int HammingFlags = 64;
|
||||
|
||||
hash1.insert(hash1.begin(), HammingFlags - hash1.size(), '0');
|
||||
hash2.insert(hash2.begin(), HammingFlags - hash2.size(), '0');
|
||||
int dist = 0;
|
||||
for (int i = 0; i < HammingFlags; i = i + 16) {
|
||||
unsigned long long x = strtoull(hash1.substr(i, 16).c_str(), NULL, 16) ^ strtoull(hash2.substr(i, 16).c_str(), NULL, 16);
|
||||
while (x) {
|
||||
dist++;
|
||||
x = x & (x - 1);
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
static std::string callcmd(const std::string& cmdline)
|
||||
{
|
||||
std::string pipe_str;
|
||||
#ifdef _WIN32
|
||||
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
|
||||
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
pipe_sec_attr.lpSecurityDescriptor = nullptr;
|
||||
pipe_sec_attr.bInheritHandle = TRUE;
|
||||
HANDLE pipe_read = nullptr;
|
||||
HANDLE pipe_child_write = nullptr;
|
||||
CreatePipe(&pipe_read, &pipe_child_write, &pipe_sec_attr, 4096);
|
||||
|
||||
STARTUPINFOA si = { 0 };
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = pipe_child_write;
|
||||
si.hStdError = pipe_child_write;
|
||||
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
|
||||
BOOL p_ret = CreateProcessA(NULL, const_cast<LPSTR>(cmdline.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
|
||||
if (p_ret) {
|
||||
DWORD read_num = 0;
|
||||
DWORD std_num = 0;
|
||||
do {
|
||||
while (::PeekNamedPipe(pipe_read, NULL, 0, NULL, &read_num, NULL) && read_num > 0) {
|
||||
char* pipe_buffer = new char[read_num];
|
||||
BOOL read_ret = ::ReadFile(pipe_read, pipe_buffer, read_num, &std_num, NULL);
|
||||
if (read_ret) {
|
||||
pipe_str.append(pipe_buffer, pipe_buffer + std_num);
|
||||
}
|
||||
if (pipe_buffer != nullptr) {
|
||||
delete[] pipe_buffer;
|
||||
pipe_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
} while (::WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT);
|
||||
|
||||
DWORD exit_ret = -1;
|
||||
::GetExitCodeProcess(pi.hProcess, &exit_ret);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
::CloseHandle(pipe_read);
|
||||
::CloseHandle(pipe_child_write);
|
||||
|
||||
return pipe_str;
|
||||
#else
|
||||
char buff[4096] = { 0 };
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmdline.c_str(), "r"), pclose);
|
||||
if (!pipe) {
|
||||
return std::string();
|
||||
}
|
||||
while (fgets(buff, sizeof(buff), pipe.get()) != nullptr) {
|
||||
pipe_str += buff;
|
||||
}
|
||||
#endif
|
||||
return pipe_str;
|
||||
}
|
||||
|
||||
//template<typename T,
|
||||
// typename = typename std::enable_if<std::is_constructible<T, std::string>::value>::type>
|
||||
// std::string VectorToString(const std::vector<T>& vector, bool to_gbk = false) {
|
||||
// if (vector.empty()) {
|
||||
// return std::string();
|
||||
// }
|
||||
// static const std::string inter = ", ";
|
||||
// std::string str;
|
||||
// for (const T& ele : vector) {
|
||||
// if (to_gbk) {
|
||||
// str += utils::utf8_to_gbk(ele) + inter;
|
||||
// }
|
||||
// else {
|
||||
// str += ele + inter;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!str.empty()) {
|
||||
// str.erase(str.size() - inter.size(), inter.size());
|
||||
// }
|
||||
// return str;
|
||||
//}
|
||||
|
||||
//template<typename T,
|
||||
// typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
|
||||
// std::string VectorToString(const std::vector<T>& vector) {
|
||||
// if (vector.empty()) {
|
||||
// return std::string();
|
||||
// }
|
||||
// static const std::string inter = ", ";
|
||||
// std::string str;
|
||||
// for (const T& ele : vector) {
|
||||
// str += std::to_string(ele) + inter;
|
||||
// }
|
||||
|
||||
// if (!str.empty()) {
|
||||
// str.erase(str.size() - inter.size(), inter.size());
|
||||
// }
|
||||
// return str;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,108 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory> // for pimpl
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <shared_mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Controller
|
||||
{
|
||||
public:
|
||||
Controller(const Controller&) = delete;
|
||||
Controller(Controller&&) = delete;
|
||||
~Controller();
|
||||
|
||||
static Controller& get_instance()
|
||||
{
|
||||
static Controller unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
static void set_dirname(std::string dirname) noexcept;
|
||||
|
||||
bool try_capture(const EmulatorInfo& info, bool without_handle = false);
|
||||
cv::Mat get_image(bool raw = false);
|
||||
|
||||
// 点击和滑动都是异步执行,返回该任务的id
|
||||
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);
|
||||
|
||||
constexpr static 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;
|
||||
Controller& operator=(Controller&&) = delete;
|
||||
|
||||
private:
|
||||
Controller();
|
||||
|
||||
bool connect_adb(const std::string& address);
|
||||
|
||||
void pipe_working_proc();
|
||||
std::pair<bool, std::vector<unsigned char>> call_command(const std::string& cmd);
|
||||
int push_cmd(const std::string& cmd);
|
||||
bool screencap();
|
||||
Point rand_point_in_rect(const Rect& rect);
|
||||
|
||||
void random_delay() const;
|
||||
|
||||
// 转换data中所有的crlf为lf:有些模拟器自带的adb,exec-out输出的\n,会被替换成\r\n,导致解码错误,所以这里转一下回来(点名批评mumu)
|
||||
static void convert_lf(std::vector<unsigned char>& data);
|
||||
|
||||
inline static std::string m_dirname;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
//bool m_thread_idle = true;
|
||||
std::thread m_cmd_thread;
|
||||
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::shared_mutex m_image_mutex;
|
||||
cv::Mat m_cache_image;
|
||||
bool m_image_convert_lf = false;
|
||||
|
||||
constexpr static int PipeBuffSize = 1048576; // 管道缓冲区大小
|
||||
HANDLE m_pipe_read = nullptr; // 读管道句柄
|
||||
HANDLE m_pipe_write = nullptr; // 写管道句柄
|
||||
HANDLE m_pipe_child_read = nullptr; // 子进程的读管道句柄
|
||||
HANDLE m_pipe_child_write = nullptr; // 子进程的写管道句柄
|
||||
SECURITY_ATTRIBUTES m_pipe_sec_attr = { 0 }; // 管道安全描述符
|
||||
STARTUPINFOA m_child_startup_info = { 0 }; // 子进程启动信息
|
||||
|
||||
EmulatorInfo m_emulator_info;
|
||||
std::minstd_rand m_rand_engine;
|
||||
std::pair<int, int> m_scale_size;
|
||||
double m_control_scale = 1.0;
|
||||
};
|
||||
|
||||
//static auto& ctrler = Controller::get_instance();
|
||||
#define Ctrler Controller::get_instance()
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory> // for pimpl
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <shared_mutex>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Controller
|
||||
{
|
||||
public:
|
||||
Controller(const Controller&) = delete;
|
||||
Controller(Controller&&) = delete;
|
||||
~Controller();
|
||||
|
||||
static Controller& get_instance()
|
||||
{
|
||||
static Controller unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
static void set_dirname(std::string dirname) noexcept;
|
||||
|
||||
bool try_capture(const EmulatorInfo& info, bool without_handle = false);
|
||||
cv::Mat get_image(bool raw = false);
|
||||
|
||||
// 点击和滑动都是异步执行,返回该任务的id
|
||||
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);
|
||||
|
||||
constexpr static 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;
|
||||
Controller& operator=(Controller&&) = delete;
|
||||
|
||||
private:
|
||||
Controller();
|
||||
|
||||
bool connect_adb(const std::string& address);
|
||||
|
||||
void pipe_working_proc();
|
||||
std::pair<bool, std::vector<unsigned char>> call_command(const std::string& cmd);
|
||||
int push_cmd(const std::string& cmd);
|
||||
bool screencap();
|
||||
Point rand_point_in_rect(const Rect& rect);
|
||||
|
||||
void random_delay() const;
|
||||
|
||||
// 转换data中所有的crlf为lf:有些模拟器自带的adb,exec-out输出的\n,会被替换成\r\n,导致解码错误,所以这里转一下回来(点名批评mumu)
|
||||
static void convert_lf(std::vector<unsigned char>& data);
|
||||
|
||||
inline static std::string m_dirname;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
//bool m_thread_idle = true;
|
||||
std::thread m_cmd_thread;
|
||||
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::shared_mutex m_image_mutex;
|
||||
cv::Mat m_cache_image;
|
||||
bool m_image_convert_lf = false;
|
||||
|
||||
constexpr static int PipeBuffSize = 1048576; // 管道缓冲区大小
|
||||
#ifdef _WIN32
|
||||
HANDLE m_pipe_read = nullptr; // 读管道句柄
|
||||
HANDLE m_pipe_write = nullptr; // 写管道句柄
|
||||
HANDLE m_pipe_child_read = nullptr; // 子进程的读管道句柄
|
||||
HANDLE m_pipe_child_write = nullptr; // 子进程的写管道句柄
|
||||
SECURITY_ATTRIBUTES m_pipe_sec_attr = { 0 }; // 管道安全描述符
|
||||
STARTUPINFOA m_child_startup_info = { 0 }; // 子进程启动信息
|
||||
#endif
|
||||
|
||||
EmulatorInfo m_emulator_info;
|
||||
std::minstd_rand m_rand_engine;
|
||||
std::pair<int, int> m_scale_size;
|
||||
double m_control_scale = 1.0;
|
||||
};
|
||||
|
||||
//static auto& ctrler = Controller::get_instance();
|
||||
#define Ctrler Controller::get_instance()
|
||||
}
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
#include "GeneralConfiger.h"
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
bool asst::GeneralConfiger::parse(const json::value& json)
|
||||
{
|
||||
m_version = json.at("version").as_string();
|
||||
|
||||
{
|
||||
const json::value& options_json = json.at("options");
|
||||
m_options.connect_type = static_cast<ConnectType>(options_json.at("connectType").as_integer());
|
||||
m_options.task_delay = options_json.at("taskDelay").as_integer();
|
||||
m_options.control_delay_lower = options_json.at("controlDelayRange")[0].as_integer();
|
||||
m_options.control_delay_upper = options_json.at("controlDelayRange")[1].as_integer();
|
||||
//m_options.print_window = options_json.at("printWindow").as_boolean();
|
||||
m_options.adb_extra_swipe_dist = options_json.get("adbExtraSwipeDist", 100);
|
||||
#include "GeneralConfiger.h"
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
bool asst::GeneralConfiger::parse(const json::value& json)
|
||||
{
|
||||
m_version = json.at("version").as_string();
|
||||
|
||||
{
|
||||
const json::value& options_json = json.at("options");
|
||||
m_options.connect_type = static_cast<ConnectType>(options_json.at("connectType").as_integer());
|
||||
m_options.task_delay = options_json.at("taskDelay").as_integer();
|
||||
m_options.control_delay_lower = options_json.at("controlDelayRange")[0].as_integer();
|
||||
m_options.control_delay_upper = options_json.at("controlDelayRange")[1].as_integer();
|
||||
//m_options.print_window = options_json.at("printWindow").as_boolean();
|
||||
m_options.adb_extra_swipe_dist = options_json.get("adbExtraSwipeDist", 100);
|
||||
m_options.adb_extra_swipe_duration = options_json.get("adbExtraSwipeDuration", -1);
|
||||
|
||||
auto& penguin_report = options_json.at("penguinReport");
|
||||
m_options.penguin_report.enable = penguin_report.get("enable", true);
|
||||
m_options.penguin_report.cmd_format = penguin_report.get("cmdFormat", std::string());
|
||||
auto& penguin_report = options_json.at("penguinReport");
|
||||
m_options.penguin_report.enable = penguin_report.get("enable", true);
|
||||
m_options.penguin_report.cmd_format = penguin_report.get("cmdFormat", std::string());
|
||||
m_options.penguin_report.server = penguin_report.get("server", "CN");
|
||||
|
||||
if (options_json.exist("aipOcr")) {
|
||||
auto& aip_ocr = options_json.at("aipOcr");
|
||||
auto& aip_ocr = options_json.at("aipOcr");
|
||||
m_options.aip_ocr.enable = aip_ocr.get("enable", false);
|
||||
m_options.aip_ocr.accurate = aip_ocr.get("accurate", false);
|
||||
m_options.aip_ocr.client_id = aip_ocr.get("clientId", std::string());
|
||||
m_options.aip_ocr.client_secret = aip_ocr.get("clientSerect", std::string());
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [name, emulator_json] : json.at("emulator").as_object()) {
|
||||
EmulatorInfo emulator_info;
|
||||
emulator_info.name = name;
|
||||
|
||||
const json::object& handle_json = emulator_json.at("handle").as_object();
|
||||
emulator_info.handle.class_name = handle_json.at("class").as_string();
|
||||
emulator_info.handle.window_name = handle_json.at("window").as_string();
|
||||
|
||||
const json::object& adb_json = emulator_json.at("adb").as_object();
|
||||
emulator_info.adb.path = adb_json.at("path").as_string();
|
||||
|
||||
for (const json::value& address_json : adb_json.at("addresses").as_array()) {
|
||||
emulator_info.adb.addresses.emplace_back(address_json.as_string());
|
||||
}
|
||||
emulator_info.adb.devices = adb_json.at("devices").as_string();
|
||||
emulator_info.adb.address_regex = adb_json.at("addressRegex").as_string();
|
||||
emulator_info.adb.connect = adb_json.at("connect").as_string();
|
||||
emulator_info.adb.click = adb_json.at("click").as_string();
|
||||
emulator_info.adb.swipe = adb_json.at("swipe").as_string();
|
||||
emulator_info.adb.display = adb_json.at("display").as_string();
|
||||
emulator_info.adb.display_format = adb_json.at("displayFormat").as_string();
|
||||
emulator_info.adb.screencap = adb_json.at("screencap").as_string();
|
||||
emulator_info.adb.release = adb_json.at("release").as_string();
|
||||
//emulator_info.adb.pullscreen = adb_json.at("pullscreen").as_string();
|
||||
|
||||
m_emulators_info.emplace(name, std::move(emulator_info));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& [name, emulator_json] : json.at("emulator").as_object()) {
|
||||
EmulatorInfo emulator_info;
|
||||
emulator_info.name = name;
|
||||
|
||||
const json::object& handle_json = emulator_json.at("handle").as_object();
|
||||
emulator_info.handle.class_name = handle_json.at("class").as_string();
|
||||
emulator_info.handle.window_name = handle_json.at("window").as_string();
|
||||
|
||||
const json::object& adb_json = emulator_json.at("adb").as_object();
|
||||
emulator_info.adb.path = adb_json.at("path").as_string();
|
||||
|
||||
for (const json::value& address_json : adb_json.at("addresses").as_array()) {
|
||||
emulator_info.adb.addresses.emplace_back(address_json.as_string());
|
||||
}
|
||||
emulator_info.adb.devices = adb_json.at("devices").as_string();
|
||||
emulator_info.adb.address_regex = adb_json.at("addressRegex").as_string();
|
||||
emulator_info.adb.connect = adb_json.at("connect").as_string();
|
||||
emulator_info.adb.click = adb_json.at("click").as_string();
|
||||
emulator_info.adb.swipe = adb_json.at("swipe").as_string();
|
||||
emulator_info.adb.display = adb_json.at("display").as_string();
|
||||
emulator_info.adb.display_format = adb_json.at("displayFormat").as_string();
|
||||
emulator_info.adb.screencap = adb_json.at("screencap").as_string();
|
||||
emulator_info.adb.release = adb_json.at("release").as_string();
|
||||
//emulator_info.adb.pullscreen = adb_json.at("pullscreen").as_string();
|
||||
|
||||
m_emulators_info.emplace(name, std::move(emulator_info));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
enum class ConnectType
|
||||
{
|
||||
Emulator,
|
||||
Custom
|
||||
#pragma once
|
||||
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
enum class ConnectType
|
||||
{
|
||||
Emulator,
|
||||
Custom
|
||||
};
|
||||
|
||||
struct AipOcrCfg // 百度 OCR API 的配置
|
||||
{
|
||||
struct AipOcrCfg // 百度 OCR API 的配置
|
||||
{
|
||||
bool enable = false;
|
||||
bool accurate = false; // 是否使用高精度识别
|
||||
std::string client_id;
|
||||
std::string client_secret;
|
||||
std::string client_secret;
|
||||
};
|
||||
|
||||
struct PenguinReportCfg // 企鹅物流数据汇报 的配置
|
||||
{
|
||||
{
|
||||
bool enable = false;
|
||||
std::string cmd_format; // 命令格式
|
||||
std::string extra_param; // 额外参数
|
||||
std::string server; // 上传参数中"server"字段,"CN", "US", "JP" and "KR".
|
||||
};
|
||||
|
||||
struct Options
|
||||
{
|
||||
ConnectType connect_type = ConnectType::Emulator; // 连接类型
|
||||
int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗
|
||||
int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时
|
||||
int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时
|
||||
//bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下
|
||||
int adb_extra_swipe_dist = 0; // 额外的滑动距离:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来
|
||||
std::string server; // 上传参数中"server"字段,"CN", "US", "JP" and "KR".
|
||||
};
|
||||
|
||||
struct Options
|
||||
{
|
||||
ConnectType connect_type = ConnectType::Emulator; // 连接类型
|
||||
int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗
|
||||
int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时
|
||||
int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时
|
||||
//bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下
|
||||
int adb_extra_swipe_dist = 0; // 额外的滑动距离:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来
|
||||
int adb_extra_swipe_duration = -1; // 额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能
|
||||
PenguinReportCfg penguin_report; // 企鹅数据汇报:每次到结算界面,汇报掉落数据至企鹅数据 https://penguin-stats.cn/
|
||||
AipOcrCfg aip_ocr; // 百度 OCR API 的配置
|
||||
};
|
||||
|
||||
class GeneralConfiger : public AbstractConfiger
|
||||
{
|
||||
public:
|
||||
virtual ~GeneralConfiger() = default;
|
||||
|
||||
const std::string& get_version() const noexcept
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
const Options& get_options() const noexcept
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
Options& get_options()
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
const std::unordered_map<std::string, EmulatorInfo>& get_emulators_info() const noexcept
|
||||
{
|
||||
return m_emulators_info;
|
||||
}
|
||||
|
||||
void set_options(Options opt) noexcept
|
||||
{
|
||||
m_options = std::move(opt);
|
||||
}
|
||||
void set_emulator_info(std::string name, EmulatorInfo emu)
|
||||
{
|
||||
m_emulators_info.emplace(std::move(name), std::move(emu));
|
||||
}
|
||||
void set_emulator_path(std::string name, std::string path)
|
||||
{
|
||||
m_emulators_info[name].path = path;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
|
||||
std::string m_version;
|
||||
Options m_options;
|
||||
std::unordered_map<std::string, EmulatorInfo> m_emulators_info;
|
||||
};
|
||||
}
|
||||
AipOcrCfg aip_ocr; // 百度 OCR API 的配置
|
||||
};
|
||||
|
||||
class GeneralConfiger : public AbstractConfiger
|
||||
{
|
||||
public:
|
||||
virtual ~GeneralConfiger() = default;
|
||||
|
||||
const std::string& get_version() const noexcept
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
const Options& get_options() const noexcept
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
Options& get_options()
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
const std::unordered_map<std::string, EmulatorInfo>& get_emulators_info() const noexcept
|
||||
{
|
||||
return m_emulators_info;
|
||||
}
|
||||
|
||||
void set_options(Options opt) noexcept
|
||||
{
|
||||
m_options = std::move(opt);
|
||||
}
|
||||
void set_emulator_info(std::string name, EmulatorInfo emu)
|
||||
{
|
||||
m_emulators_info.emplace(std::move(name), std::move(emu));
|
||||
}
|
||||
void set_emulator_path(std::string name, std::string path)
|
||||
{
|
||||
m_emulators_info[name].path = path;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
|
||||
std::string m_version;
|
||||
Options m_options;
|
||||
std::unordered_map<std::string, EmulatorInfo> m_emulators_info;
|
||||
};
|
||||
}
|
||||
|
||||
37
src/MeoAssistant/Linux编译教程.md
Normal file
37
src/MeoAssistant/Linux编译教程.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Linux 编译教程
|
||||
|
||||
**本教程需要读者有一定的 Linux 环境配置能力及编程基础!**
|
||||
|
||||
虽然没想明白为什么 Linux 下需要用助手挂模拟器,嘛总之大家有这个需求还是弄一下_(:з」∠)_
|
||||
|
||||
作者对 Linux 一些环境问题也是半懂不懂,所以虽说是教程,也只是分享一下自己的踩坑经历,如果遇到其他问题欢迎提出 ISSUE 一起讨论下 orz
|
||||
|
||||
## 下载编译第三方库
|
||||
|
||||
### Opencv
|
||||
|
||||
请自行搜索教程安装,没什么特别的,作者当前成功验证过的版本为`4.5.3`版本,不需要`opencv_contrib`
|
||||
|
||||
### PaddleOCR
|
||||
|
||||
1. 使用我魔改了接口的版本:https://github.com/MistEO/PaddleOCR
|
||||
2. 参考 [这个教程](https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.3/deploy/cpp_infer#readme)
|
||||
3. PaddlePaddle 直接[下载](https://www.paddlepaddle.org.cn/documentation/docs/zh/2.0/guides/05_inference_deployment/inference/build_and_install_lib_cn.html)即可
|
||||
|
||||
编译选项参考
|
||||
|
||||
```bash
|
||||
cmake ../ -DPADDLE_LIB=/your_path/paddle_inference/ -D OPENCV_DIR=/your_path_to_opencv/ -DBUILD_SHARED=ON -DWITH_MKL=OFF -DWITH_STATIC_LIB=OFF
|
||||
```
|
||||
|
||||
### meojson
|
||||
|
||||
https://github.com/MistEO/meojson
|
||||
|
||||
```bash
|
||||
make shared
|
||||
```
|
||||
|
||||
### penguin-stats-recognize-v3
|
||||
|
||||
使用我魔改了接口的版本:https://github.com/MistEO/penguin-stats-recognize-v3
|
||||
@@ -1,182 +1,201 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Version.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
~Logger()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
Logger(const Logger&) = delete;
|
||||
Logger(Logger&&) = delete;
|
||||
|
||||
static Logger& get_instance()
|
||||
{
|
||||
static Logger _unique_instance;
|
||||
return _unique_instance;
|
||||
}
|
||||
|
||||
static void set_dirname(std::string dirname) noexcept
|
||||
{
|
||||
m_dirname = std::move(dirname);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void trace(Args&&... args)
|
||||
{
|
||||
std::string_view level = "TRC";
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void info(Args&&... args)
|
||||
{
|
||||
std::string_view level = "INF";
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void error(Args&&... args)
|
||||
{
|
||||
std::string_view level = "ERR";
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
void flush()
|
||||
{
|
||||
std::unique_lock<std::mutex> trace_lock(m_trace_mutex);
|
||||
if (m_ofs.is_open()) {
|
||||
m_ofs.close();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string m_log_filename = m_dirname + "asst.log";
|
||||
const std::string m_log_bak_filename = m_dirname + "asst.bak.log";
|
||||
|
||||
private:
|
||||
Logger()
|
||||
{
|
||||
check_filesize_and_remove();
|
||||
log_init_info();
|
||||
}
|
||||
|
||||
void check_filesize_and_remove()
|
||||
{
|
||||
constexpr uintmax_t MaxLogSize = 4 * 1024 * 1024;
|
||||
try {
|
||||
if (std::filesystem::exists(m_log_filename)) {
|
||||
uintmax_t log_size = std::filesystem::file_size(m_log_filename);
|
||||
if (log_size >= MaxLogSize) {
|
||||
std::filesystem::rename(m_log_filename, m_log_bak_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
;
|
||||
}
|
||||
}
|
||||
void log_init_info()
|
||||
{
|
||||
trace("-----------------------------");
|
||||
trace("MeoAssistant Process Start");
|
||||
trace("Version", asst::Version);
|
||||
trace("Build DataTime", __DATE__, __TIME__);
|
||||
trace("Working Path", m_dirname);
|
||||
trace("-----------------------------");
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void log(std::string_view level, Args&&... args)
|
||||
{
|
||||
std::unique_lock<std::mutex> trace_lock(m_trace_mutex);
|
||||
|
||||
constexpr int buff_len = 128;
|
||||
char buff[buff_len] = { 0 };
|
||||
sprintf_s(buff, buff_len, "[%s][%s][Px%x][Tx%x]",
|
||||
asst::utils::get_format_time().c_str(),
|
||||
level.data(), _getpid(), ::GetCurrentThreadId());
|
||||
|
||||
if (!m_ofs.is_open()) {
|
||||
m_ofs = std::ofstream(m_log_filename, std::ios::out | std::ios::app);
|
||||
}
|
||||
#ifdef LOG_TRACE
|
||||
stream_args(m_ofs, buff, args...);
|
||||
#else
|
||||
stream_args(m_ofs, buff, std::forward<Args>(args)...);
|
||||
#endif
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
stream_args<true>(std::cout, buff, std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <bool ToGbk = false, typename T, typename... Args>
|
||||
inline void stream_args(std::ostream& os, T&& first, Args&&... rest)
|
||||
{
|
||||
stream<ToGbk, T>()(os, std::forward<T>(first));
|
||||
stream_args<ToGbk>(os, std::forward<Args>(rest)...);
|
||||
}
|
||||
template <bool>
|
||||
inline void stream_args(std::ostream& os)
|
||||
{
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
template <bool ToGbk, typename T, typename = void>
|
||||
struct stream
|
||||
{
|
||||
inline void operator()(std::ostream& os, T&& first)
|
||||
{
|
||||
os << first << " ";
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct stream<true, T, typename std::enable_if<std::is_constructible<std::string, T>::value>::type>
|
||||
{
|
||||
inline void operator()(std::ostream& os, T&& first)
|
||||
{
|
||||
os << utils::utf8_to_gbk(first) << " ";
|
||||
}
|
||||
};
|
||||
|
||||
inline static std::string m_dirname;
|
||||
std::mutex m_trace_mutex;
|
||||
std::ofstream m_ofs;
|
||||
};
|
||||
|
||||
class LoggerAux
|
||||
{
|
||||
public:
|
||||
LoggerAux(const std::string& func_name)
|
||||
: m_func_name(func_name),
|
||||
m_start_time(std::chrono::steady_clock::now())
|
||||
{
|
||||
Logger::get_instance().trace(m_func_name, " | enter");
|
||||
}
|
||||
~LoggerAux()
|
||||
{
|
||||
auto duration = std::chrono::steady_clock::now() - m_start_time;
|
||||
Logger::get_instance().trace(m_func_name, " | leave,",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(), "ms");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_func_name;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start_time;
|
||||
};
|
||||
|
||||
//static auto& log = Logger::get_instance();
|
||||
#define Log Logger::get_instance()
|
||||
#define LogTraceFunction LoggerAux _func_aux(__FUNCTION__)
|
||||
#define LogTraceScope LoggerAux _func_aux
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Version.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
~Logger()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
Logger(const Logger&) = delete;
|
||||
Logger(Logger&&) = delete;
|
||||
|
||||
static Logger& get_instance()
|
||||
{
|
||||
static Logger _unique_instance;
|
||||
return _unique_instance;
|
||||
}
|
||||
|
||||
static void set_dirname(std::string dirname) noexcept
|
||||
{
|
||||
m_dirname = std::move(dirname);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void trace(Args&&... args)
|
||||
{
|
||||
std::string_view level = "TRC";
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void info(Args&&... args)
|
||||
{
|
||||
std::string_view level = "INF";
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void error(Args&&... args)
|
||||
{
|
||||
std::string_view level = "ERR";
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
void flush()
|
||||
{
|
||||
std::unique_lock<std::mutex> trace_lock(m_trace_mutex);
|
||||
if (m_ofs.is_open()) {
|
||||
m_ofs.close();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string m_log_filename = m_dirname + "asst.log";
|
||||
const std::string m_log_bak_filename = m_dirname + "asst.bak.log";
|
||||
|
||||
private:
|
||||
Logger()
|
||||
{
|
||||
check_filesize_and_remove();
|
||||
log_init_info();
|
||||
}
|
||||
|
||||
void check_filesize_and_remove()
|
||||
{
|
||||
constexpr uintmax_t MaxLogSize = 4 * 1024 * 1024;
|
||||
try {
|
||||
if (std::filesystem::exists(m_log_filename)) {
|
||||
uintmax_t log_size = std::filesystem::file_size(m_log_filename);
|
||||
if (log_size >= MaxLogSize) {
|
||||
std::filesystem::rename(m_log_filename, m_log_bak_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
;
|
||||
}
|
||||
}
|
||||
void log_init_info()
|
||||
{
|
||||
trace("-----------------------------");
|
||||
trace("MeoAssistant Process Start");
|
||||
trace("Version", asst::Version);
|
||||
trace("Build DataTime", __DATE__, __TIME__);
|
||||
trace("Working Path", m_dirname);
|
||||
trace("-----------------------------");
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void log(std::string_view level, Args&&... args)
|
||||
{
|
||||
std::unique_lock<std::mutex> trace_lock(m_trace_mutex);
|
||||
|
||||
constexpr int buff_len = 128;
|
||||
char buff[buff_len] = { 0 };
|
||||
#ifdef _WIN32
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buff, buff_len,
|
||||
#else // ! _MSC_VER
|
||||
sprintf(buff,
|
||||
#endif // END _MSC_VER
|
||||
"[%s][%s][Px%x][Tx%x]",
|
||||
asst::utils::get_format_time().c_str(),
|
||||
level.data(), _getpid(), ::GetCurrentThreadId()
|
||||
);
|
||||
#else // ! _WIN32
|
||||
sprintf(buff, "[%s][%s][Px%x][Tx%x]",
|
||||
asst::utils::get_format_time().c_str(),
|
||||
level.data(), getpid(), gettid()
|
||||
);
|
||||
#endif // END _WIN32
|
||||
|
||||
if (!m_ofs.is_open()) {
|
||||
m_ofs = std::ofstream(m_log_filename, std::ios::out | std::ios::app);
|
||||
}
|
||||
#ifdef LOG_TRACE
|
||||
stream_args(m_ofs, buff, args...);
|
||||
#else
|
||||
stream_args(m_ofs, buff, std::forward<Args>(args)...);
|
||||
#endif
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
stream_args<true>(std::cout, buff, std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <bool ToGbk = false, typename T, typename... Args>
|
||||
inline void stream_args(std::ostream& os, T&& first, Args&&... rest)
|
||||
{
|
||||
stream<ToGbk, T>()(os, std::forward<T>(first));
|
||||
stream_args<ToGbk>(os, std::forward<Args>(rest)...);
|
||||
}
|
||||
template <bool>
|
||||
inline void stream_args(std::ostream& os)
|
||||
{
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
template <bool ToGbk, typename T, typename = void>
|
||||
struct stream
|
||||
{
|
||||
inline void operator()(std::ostream& os, T&& first)
|
||||
{
|
||||
os << first << " ";
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct stream<true, T, typename std::enable_if<std::is_constructible<std::string, T>::value>::type>
|
||||
{
|
||||
inline void operator()(std::ostream& os, T&& first)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
os << utils::utf8_to_gbk(first) << " ";
|
||||
#else
|
||||
os << first << " "; // Don't fucking use gbk in linux
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
inline static std::string m_dirname;
|
||||
std::mutex m_trace_mutex;
|
||||
std::ofstream m_ofs;
|
||||
};
|
||||
|
||||
class LoggerAux
|
||||
{
|
||||
public:
|
||||
LoggerAux(const std::string& func_name)
|
||||
: m_func_name(func_name),
|
||||
m_start_time(std::chrono::steady_clock::now())
|
||||
{
|
||||
Logger::get_instance().trace(m_func_name, " | enter");
|
||||
}
|
||||
~LoggerAux()
|
||||
{
|
||||
auto duration = std::chrono::steady_clock::now() - m_start_time;
|
||||
Logger::get_instance().trace(m_func_name, " | leave,",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(), "ms");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_func_name;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start_time;
|
||||
};
|
||||
|
||||
//static auto& log = Logger::get_instance();
|
||||
#define Log Logger::get_instance()
|
||||
#define LogTraceFunction LoggerAux _func_aux(__FUNCTION__)
|
||||
#define LogTraceScope LoggerAux _func_aux
|
||||
}
|
||||
|
||||
@@ -1,115 +1,115 @@
|
||||
#include "OcrPack.h"
|
||||
|
||||
#include <PaddleOCR/paddle_ocr.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
asst::OcrPack::~OcrPack()
|
||||
{
|
||||
PaddleOcrDestroy(m_ocr);
|
||||
}
|
||||
|
||||
bool asst::OcrPack::load(const std::string& dir)
|
||||
{
|
||||
constexpr static const char* DetName = "\\det";
|
||||
//constexpr static const char* ClsName = "\\cls";
|
||||
constexpr static const char* RecName = "\\rec";
|
||||
constexpr static const char* KeysName = "\\ppocr_keys_v1.txt";
|
||||
|
||||
const std::string dst_filename = dir + DetName;
|
||||
//const std::string cls_filename = dir + ClsName;
|
||||
const std::string rec_filename = dir + RecName;
|
||||
const std::string keys_filename = dir + KeysName;
|
||||
|
||||
if (m_ocr != nullptr) {
|
||||
PaddleOcrDestroy(m_ocr);
|
||||
}
|
||||
m_ocr = PaddleOcrCreate(dst_filename.c_str(), rec_filename.c_str(), keys_filename.c_str(), nullptr);
|
||||
|
||||
return m_ocr != nullptr;
|
||||
}
|
||||
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const asst::TextRectProc& pred, bool without_det)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
|
||||
constexpr static size_t MaxBoxSize = 128;
|
||||
// each box has 8 value ( 4 points, x and y )
|
||||
int boxes[MaxBoxSize * 8] = { 0 };
|
||||
char* strs[MaxBoxSize] = { 0 };
|
||||
for (size_t i = 0; i != MaxBoxSize; ++i) {
|
||||
constexpr static size_t MaxTextSize = 1024;
|
||||
*(strs + i) = new char[MaxTextSize];
|
||||
memset(*(strs + i), 0, MaxTextSize);
|
||||
}
|
||||
float scores[MaxBoxSize] = { 0 };
|
||||
size_t size;
|
||||
|
||||
Log.trace("Without Det:", without_det);
|
||||
if (!without_det) {
|
||||
PaddleOcrSystem(m_ocr, buf.data(), buf.size(), false,
|
||||
boxes, strs, scores, &size, nullptr, nullptr);
|
||||
}
|
||||
else {
|
||||
PaddleOcrRec(m_ocr, buf.data(), buf.size(),
|
||||
strs, scores, &size, nullptr, nullptr);
|
||||
}
|
||||
|
||||
std::vector<TextRect> result;
|
||||
std::string log_str_raw;
|
||||
std::string log_str_proc;
|
||||
for (size_t i = 0; i != size; ++i) {
|
||||
// the box rect like ↓
|
||||
// 0 - 1
|
||||
// 3 - 2
|
||||
Rect rect;
|
||||
if (!without_det) {
|
||||
int* box = boxes + i * 8;
|
||||
int x_collect[4] = { *(box + 0), *(box + 2), *(box + 4), *(box + 6) };
|
||||
int y_collect[4] = { *(box + 1), *(box + 3), *(box + 5), *(box + 7) };
|
||||
int left = int(*std::min_element(x_collect, x_collect + 4));
|
||||
int right = int(*std::max_element(x_collect, x_collect + 4));
|
||||
int top = int(*std::min_element(y_collect, y_collect + 4));
|
||||
int bottom = int(*std::max_element(y_collect, y_collect + 4));
|
||||
rect = Rect(left, top, right - left, bottom - top);
|
||||
}
|
||||
std::string text(*(strs + i));
|
||||
float score = *(scores + i);
|
||||
|
||||
TextRect tr{ text, rect, score };
|
||||
|
||||
log_str_raw += tr.to_string() + ", ";
|
||||
if (!pred || pred(tr)) {
|
||||
log_str_proc += tr.to_string() + ", ";
|
||||
result.emplace_back(std::move(tr));
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i != MaxBoxSize; ++i) {
|
||||
delete[] * (strs + i);
|
||||
}
|
||||
|
||||
Log.trace("OcrPack::recognize | raw : ", log_str_raw);
|
||||
Log.trace("OcrPack::recognize | proc : ", log_str_proc);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const asst::Rect& roi, const asst::TextRectProc& pred, bool without_det)
|
||||
{
|
||||
auto rect_cor = [&roi, &pred, &without_det](TextRect& tr) -> bool {
|
||||
if (without_det) {
|
||||
tr.rect = roi;
|
||||
}
|
||||
else {
|
||||
tr.rect.x += roi.x;
|
||||
tr.rect.y += roi.y;
|
||||
}
|
||||
return pred(tr);
|
||||
};
|
||||
Log.trace("OcrPack::recognize | roi : ", roi.to_string());
|
||||
return recognize(image(utils::make_rect<cv::Rect>(roi)), rect_cor, without_det);
|
||||
}
|
||||
#include "OcrPack.h"
|
||||
|
||||
#include <PaddleOCR/paddle_ocr.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
asst::OcrPack::~OcrPack()
|
||||
{
|
||||
PaddleOcrDestroy(m_ocr);
|
||||
}
|
||||
|
||||
bool asst::OcrPack::load(const std::string& dir)
|
||||
{
|
||||
constexpr static const char* DetName = "/det";
|
||||
//constexpr static const char* ClsName = "/cls";
|
||||
constexpr static const char* RecName = "/rec";
|
||||
constexpr static const char* KeysName = "/ppocr_keys_v1.txt";
|
||||
|
||||
const std::string dst_filename = dir + DetName;
|
||||
//const std::string cls_filename = dir + ClsName;
|
||||
const std::string rec_filename = dir + RecName;
|
||||
const std::string keys_filename = dir + KeysName;
|
||||
|
||||
if (m_ocr != nullptr) {
|
||||
PaddleOcrDestroy(m_ocr);
|
||||
}
|
||||
m_ocr = PaddleOcrCreate(dst_filename.c_str(), rec_filename.c_str(), keys_filename.c_str(), nullptr);
|
||||
|
||||
return m_ocr != nullptr;
|
||||
}
|
||||
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const asst::TextRectProc& pred, bool without_det)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
|
||||
constexpr static size_t MaxBoxSize = 128;
|
||||
// each box has 8 value ( 4 points, x and y )
|
||||
int boxes[MaxBoxSize * 8] = { 0 };
|
||||
char* strs[MaxBoxSize] = { 0 };
|
||||
for (size_t i = 0; i != MaxBoxSize; ++i) {
|
||||
constexpr static size_t MaxTextSize = 1024;
|
||||
*(strs + i) = new char[MaxTextSize];
|
||||
memset(*(strs + i), 0, MaxTextSize);
|
||||
}
|
||||
float scores[MaxBoxSize] = { 0 };
|
||||
size_t size;
|
||||
|
||||
Log.trace("Without Det:", without_det);
|
||||
if (!without_det) {
|
||||
PaddleOcrSystem(m_ocr, buf.data(), buf.size(), false,
|
||||
boxes, strs, scores, &size, nullptr, nullptr);
|
||||
}
|
||||
else {
|
||||
PaddleOcrRec(m_ocr, buf.data(), buf.size(),
|
||||
strs, scores, &size, nullptr, nullptr);
|
||||
}
|
||||
|
||||
std::vector<TextRect> result;
|
||||
std::string log_str_raw;
|
||||
std::string log_str_proc;
|
||||
for (size_t i = 0; i != size; ++i) {
|
||||
// the box rect like ↓
|
||||
// 0 - 1
|
||||
// 3 - 2
|
||||
Rect rect;
|
||||
if (!without_det) {
|
||||
int* box = boxes + i * 8;
|
||||
int x_collect[4] = { *(box + 0), *(box + 2), *(box + 4), *(box + 6) };
|
||||
int y_collect[4] = { *(box + 1), *(box + 3), *(box + 5), *(box + 7) };
|
||||
int left = int(*std::min_element(x_collect, x_collect + 4));
|
||||
int right = int(*std::max_element(x_collect, x_collect + 4));
|
||||
int top = int(*std::min_element(y_collect, y_collect + 4));
|
||||
int bottom = int(*std::max_element(y_collect, y_collect + 4));
|
||||
rect = Rect(left, top, right - left, bottom - top);
|
||||
}
|
||||
std::string text(*(strs + i));
|
||||
float score = *(scores + i);
|
||||
|
||||
TextRect tr{ text, rect, score };
|
||||
|
||||
log_str_raw += tr.to_string() + ", ";
|
||||
if (!pred || pred(tr)) {
|
||||
log_str_proc += tr.to_string() + ", ";
|
||||
result.emplace_back(std::move(tr));
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i != MaxBoxSize; ++i) {
|
||||
delete[] * (strs + i);
|
||||
}
|
||||
|
||||
Log.trace("OcrPack::recognize | raw : ", log_str_raw);
|
||||
Log.trace("OcrPack::recognize | proc : ", log_str_proc);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat& image, const asst::Rect& roi, const asst::TextRectProc& pred, bool without_det)
|
||||
{
|
||||
auto rect_cor = [&roi, &pred, &without_det](TextRect& tr) -> bool {
|
||||
if (without_det) {
|
||||
tr.rect = roi;
|
||||
}
|
||||
else {
|
||||
tr.rect.x += roi.x;
|
||||
tr.rect.y += roi.y;
|
||||
}
|
||||
return pred(tr);
|
||||
};
|
||||
Log.trace("OcrPack::recognize | roi : ", roi.to_string());
|
||||
return recognize(image(utils::make_rect<cv::Rect>(roi)), rect_cor, without_det);
|
||||
}
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
#include "PenguinPack.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <meojson/json.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
namespace penguin
|
||||
{
|
||||
#include <penguin-stats-recognize/penguin_wasm.h>
|
||||
}
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
|
||||
bool asst::PenguinPack::load(const std::string& dir)
|
||||
{
|
||||
bool ret = load_json(dir + "\\json\\stages.json", dir + "\\json\\hash_index.json");
|
||||
|
||||
for (const auto& file : std::filesystem::directory_iterator(dir + "\\items")) {
|
||||
ret &= load_templ(file.path().stem().u8string(), file.path().u8string());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void asst::PenguinPack::set_language(const std::string& server)
|
||||
{
|
||||
m_language = server;
|
||||
penguin::load_server(server.c_str());
|
||||
}
|
||||
|
||||
std::string asst::PenguinPack::recognize(const cv::Mat& image)
|
||||
{
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
return penguin::recognize(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
bool asst::PenguinPack::load_json(const std::string& stage_path, const std::string& hash_path)
|
||||
{
|
||||
auto stage_parse_ret = json::parse(utils::load_file_without_bom(stage_path));
|
||||
if (!stage_parse_ret) {
|
||||
m_last_error = stage_path + " parsing failed";
|
||||
return false;
|
||||
}
|
||||
// stage_json 来自 https://penguin-stats.io/PenguinStats/api/v2/stages
|
||||
// 和接口需要的json有点区别,这里做个转换
|
||||
json::value stage_json = std::move(stage_parse_ret.value());
|
||||
json::object cvt_stage_json;
|
||||
try {
|
||||
for (const json::value& stage_info : stage_json.as_array()) {
|
||||
if (!stage_info.exist("dropInfos")) { // 这种一般是以前的活动关,现在已经关闭了的
|
||||
continue;
|
||||
}
|
||||
std::string key = stage_info.at("code").as_string();
|
||||
json::value stage_dst;
|
||||
stage_dst["stageId"] = stage_info.at("stageId");
|
||||
std::vector<json::value> drops_vector;
|
||||
for (const json::value& drop_info : stage_info.at("dropInfos").as_array()) {
|
||||
if (drop_info.exist("itemId")) {
|
||||
// 幸运掉落,家具啥的,企鹅数据不接,忽略掉
|
||||
if (drop_info.at("dropType").as_string() == "FURNITURE") {
|
||||
continue;
|
||||
}
|
||||
drops_vector.emplace_back(drop_info.at("itemId"));
|
||||
}
|
||||
}
|
||||
stage_dst["drops"] = json::array(std::move(drops_vector));
|
||||
stage_dst["existence"] = stage_info.at("existence").at(m_language).at("exist");
|
||||
|
||||
cvt_stage_json.emplace(std::move(key), std::move(stage_dst));
|
||||
}
|
||||
}
|
||||
catch (json::exception& e) {
|
||||
m_last_error = stage_path + " parsing error " + e.what();
|
||||
return false;
|
||||
}
|
||||
std::string cvt_stage_string = cvt_stage_json.to_string();
|
||||
penguin::load_json(cvt_stage_string.c_str(), utils::load_file_without_bom(hash_path).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::PenguinPack::load_templ(const std::string& item_id, const std::string& path)
|
||||
{
|
||||
cv::Mat image = cv::imread(path);
|
||||
if (image.empty()) {
|
||||
m_last_error = "templ is empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
|
||||
penguin::load_templ(item_id.c_str(), buf.data(), buf.size());
|
||||
|
||||
return true;
|
||||
#include "PenguinPack.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <meojson/json.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
namespace penguin
|
||||
{
|
||||
#include <penguin-stats-recognize/penguin_wasm.h>
|
||||
}
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
|
||||
bool asst::PenguinPack::load(const std::string& dir)
|
||||
{
|
||||
bool ret = load_json(dir + "/json/stages.json", dir + "/json/hash_index.json");
|
||||
|
||||
for (const auto& file : std::filesystem::directory_iterator(dir + "/items")) {
|
||||
ret &= load_templ(file.path().stem().u8string(), file.path().u8string());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void asst::PenguinPack::set_language(const std::string& server)
|
||||
{
|
||||
m_language = server;
|
||||
penguin::load_server(server.c_str());
|
||||
}
|
||||
|
||||
std::string asst::PenguinPack::recognize(const cv::Mat& image)
|
||||
{
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
return penguin::recognize(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
bool asst::PenguinPack::load_json(const std::string& stage_path, const std::string& hash_path)
|
||||
{
|
||||
auto stage_parse_ret = json::parse(utils::load_file_without_bom(stage_path));
|
||||
if (!stage_parse_ret) {
|
||||
m_last_error = stage_path + " parsing failed";
|
||||
return false;
|
||||
}
|
||||
// stage_json 来自 https://penguin-stats.io/PenguinStats/api/v2/stages
|
||||
// 和接口需要的json有点区别,这里做个转换
|
||||
json::value stage_json = std::move(stage_parse_ret.value());
|
||||
json::object cvt_stage_json;
|
||||
try {
|
||||
for (const json::value& stage_info : stage_json.as_array()) {
|
||||
if (!stage_info.exist("dropInfos")) { // 这种一般是以前的活动关,现在已经关闭了的
|
||||
continue;
|
||||
}
|
||||
std::string key = stage_info.at("code").as_string();
|
||||
json::value stage_dst;
|
||||
stage_dst["stageId"] = stage_info.at("stageId");
|
||||
std::vector<json::value> drops_vector;
|
||||
for (const json::value& drop_info : stage_info.at("dropInfos").as_array()) {
|
||||
if (drop_info.exist("itemId")) {
|
||||
// 幸运掉落,家具啥的,企鹅数据不接,忽略掉
|
||||
if (drop_info.at("dropType").as_string() == "FURNITURE") {
|
||||
continue;
|
||||
}
|
||||
drops_vector.emplace_back(drop_info.at("itemId"));
|
||||
}
|
||||
}
|
||||
stage_dst["drops"] = json::array(std::move(drops_vector));
|
||||
stage_dst["existence"] = stage_info.at("existence").at(m_language).at("exist");
|
||||
|
||||
cvt_stage_json.emplace(std::move(key), std::move(stage_dst));
|
||||
}
|
||||
}
|
||||
catch (json::exception& e) {
|
||||
m_last_error = stage_path + " parsing error " + e.what();
|
||||
return false;
|
||||
}
|
||||
std::string cvt_stage_string = cvt_stage_json.to_string();
|
||||
penguin::load_json(cvt_stage_string.c_str(), utils::load_file_without_bom(hash_path).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::PenguinPack::load_templ(const std::string& item_id, const std::string& path)
|
||||
{
|
||||
cv::Mat image = cv::imread(path);
|
||||
if (image.empty()) {
|
||||
m_last_error = "templ is empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uchar> buf;
|
||||
cv::imencode(".png", image, buf);
|
||||
|
||||
penguin::load_templ(item_id.c_str(), buf.data(), buf.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,58 +1,58 @@
|
||||
#include "PenguinUploader.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
#include "Version.h"
|
||||
|
||||
bool asst::PenguinUploader::upload(const std::string& rec_res)
|
||||
{
|
||||
std::string body = cvt_json(rec_res);
|
||||
return request_penguin(body);
|
||||
}
|
||||
|
||||
std::string asst::PenguinUploader::cvt_json(const std::string& rec_res)
|
||||
{
|
||||
auto parse_ret = json::parse(rec_res);
|
||||
if (!parse_ret) {
|
||||
return std::string();
|
||||
}
|
||||
json::value rec = std::move(parse_ret.value());
|
||||
|
||||
// Doc: https://developer.penguin-stats.io/public-api/api-v2-instruction/report-api
|
||||
json::value body;
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
body["server"] = opt.penguin_report.server;
|
||||
body["stageId"] = rec["stage"]["stageId"];
|
||||
// To fix: https://github.com/MistEO/MeoAssistantArknights/issues/40
|
||||
body["drops"] = json::array();
|
||||
for (auto&& drop : rec["drops"].as_array()) {
|
||||
if (!drop["itemId"].as_string().empty()) {
|
||||
body["drops"].as_array().emplace_back(drop);
|
||||
}
|
||||
}
|
||||
body["source"] = "MeoAssistant";
|
||||
body["version"] = Version;
|
||||
|
||||
return body.to_string();
|
||||
}
|
||||
|
||||
bool asst::PenguinUploader::request_penguin(const std::string& body)
|
||||
{
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
std::string body_escape = utils::string_replace_all(body, "\"", "\\\"");
|
||||
std::string cmd_line = utils::string_replace_all(opt.penguin_report.cmd_format, "[body]", body_escape);
|
||||
cmd_line = utils::string_replace_all(cmd_line, "[extra]", opt.penguin_report.extra_param);
|
||||
|
||||
Log.trace("request_penguin |", cmd_line);
|
||||
|
||||
std::string response = utils::callcmd(cmd_line);
|
||||
|
||||
Log.trace("response:\n", response);
|
||||
|
||||
return true;
|
||||
}
|
||||
#include "PenguinUploader.h"
|
||||
|
||||
// #include <Windows.h>
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "Resource.h"
|
||||
#include "Version.h"
|
||||
|
||||
bool asst::PenguinUploader::upload(const std::string& rec_res)
|
||||
{
|
||||
std::string body = cvt_json(rec_res);
|
||||
return request_penguin(body);
|
||||
}
|
||||
|
||||
std::string asst::PenguinUploader::cvt_json(const std::string& rec_res)
|
||||
{
|
||||
auto parse_ret = json::parse(rec_res);
|
||||
if (!parse_ret) {
|
||||
return std::string();
|
||||
}
|
||||
json::value rec = std::move(parse_ret.value());
|
||||
|
||||
// Doc: https://developer.penguin-stats.io/public-api/api-v2-instruction/report-api
|
||||
json::value body;
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
body["server"] = opt.penguin_report.server;
|
||||
body["stageId"] = rec["stage"]["stageId"];
|
||||
// To fix: https://github.com/MistEO/MeoAssistantArknights/issues/40
|
||||
body["drops"] = json::array();
|
||||
for (auto&& drop : rec["drops"].as_array()) {
|
||||
if (!drop["itemId"].as_string().empty()) {
|
||||
body["drops"].as_array().emplace_back(drop);
|
||||
}
|
||||
}
|
||||
body["source"] = "MeoAssistant";
|
||||
body["version"] = Version;
|
||||
|
||||
return body.to_string();
|
||||
}
|
||||
|
||||
bool asst::PenguinUploader::request_penguin(const std::string& body)
|
||||
{
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
std::string body_escape = utils::string_replace_all(body, "\"", "\\\"");
|
||||
std::string cmd_line = utils::string_replace_all(opt.penguin_report.cmd_format, "[body]", body_escape);
|
||||
cmd_line = utils::string_replace_all(cmd_line, "[extra]", opt.penguin_report.extra_param);
|
||||
|
||||
Log.trace("request_penguin |", cmd_line);
|
||||
|
||||
std::string response = utils::callcmd(cmd_line);
|
||||
|
||||
Log.trace("response:\n", response);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,126 +1,126 @@
|
||||
#include "ProcessTaskImageAnalyzer.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
|
||||
asst::ProcessTaskImageAnalyzer::ProcessTaskImageAnalyzer(const cv::Mat& image, std::vector<std::string> tasks_name)
|
||||
: AbstractImageAnalyzer(image),
|
||||
m_tasks_name(std::move(tasks_name))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
asst::ProcessTaskImageAnalyzer::~ProcessTaskImageAnalyzer() = default;
|
||||
|
||||
bool asst::ProcessTaskImageAnalyzer::match_analyze(std::shared_ptr<TaskInfo> task_ptr)
|
||||
{
|
||||
if (!m_match_analyzer) {
|
||||
m_match_analyzer = std::make_unique<MatchImageAnalyzer>(m_image);
|
||||
}
|
||||
const auto match_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(task_ptr);
|
||||
m_match_analyzer->set_task_info(*match_task_ptr);
|
||||
|
||||
if (m_match_analyzer->analyze()) {
|
||||
m_result = match_task_ptr;
|
||||
m_result_rect = m_match_analyzer->get_result().rect;
|
||||
task_ptr->region_of_appeared = m_result_rect;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asst::ProcessTaskImageAnalyzer::ocr_analyze(std::shared_ptr<TaskInfo> task_ptr)
|
||||
{
|
||||
std::shared_ptr<OcrTaskInfo> ocr_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(task_ptr);
|
||||
|
||||
// 先尝试从缓存的结果里找
|
||||
//for (const TextRect& tr : m_ocr_cache) {
|
||||
// TextRect temp = tr;
|
||||
// for (const auto& [regex, new_str] : ocr_task_ptr->replace_map) {
|
||||
// temp.text = std::regex_replace(temp.text, std::regex(regex), new_str);
|
||||
// }
|
||||
// for (const auto& text : ocr_task_ptr->text) {
|
||||
// bool flag = false;
|
||||
// if (ocr_task_ptr->need_full_match) {
|
||||
// if (temp.text == text) {
|
||||
// flag = true;
|
||||
// }
|
||||
// }
|
||||
// else if (temp.text.find(text) != std::string::npos) {
|
||||
// flag = true;
|
||||
// }
|
||||
// // 即使找到了,也得在ROI里才行,不然过滤掉
|
||||
// if (flag && ocr_task_ptr->roi.include(tr.rect)) {
|
||||
// m_result = ocr_task_ptr;
|
||||
// m_result_rect = tr.rect;
|
||||
// ocr_task_ptr->region_of_appeared = m_result_rect;
|
||||
// Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found in cache", tr.to_string());
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
if (!m_ocr_analyzer) {
|
||||
m_ocr_analyzer = std::make_unique<OcrImageAnalyzer>(m_image);
|
||||
}
|
||||
m_ocr_analyzer->set_task_info(*ocr_task_ptr);
|
||||
|
||||
bool ret = m_ocr_analyzer->analyze();
|
||||
|
||||
if (ret) {
|
||||
const auto& ocr_result = m_ocr_analyzer->get_result();
|
||||
auto& res = ocr_result.front();
|
||||
m_result = ocr_task_ptr;
|
||||
m_result_rect = res.rect;
|
||||
ocr_task_ptr->region_of_appeared = res.rect;
|
||||
//m_ocr_cache.insert(m_ocr_cache.end(), ocr_result.begin(), ocr_result.end());
|
||||
Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found", res.to_string());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void asst::ProcessTaskImageAnalyzer::reset() noexcept
|
||||
{
|
||||
//m_ocr_cache.clear();
|
||||
m_ocr_analyzer = nullptr;
|
||||
m_match_analyzer = nullptr;
|
||||
}
|
||||
|
||||
bool asst::ProcessTaskImageAnalyzer::analyze()
|
||||
{
|
||||
m_result = nullptr;
|
||||
m_result_rect = Rect();
|
||||
|
||||
for (const std::string& task_name : m_tasks_name) {
|
||||
auto task_ptr = task.get(task_name);
|
||||
|
||||
switch (task_ptr->algorithm) {
|
||||
case AlgorithmType::JustReturn:
|
||||
m_result = task_ptr;
|
||||
return true;
|
||||
case AlgorithmType::MatchTemplate:
|
||||
if (match_analyze(task_ptr)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case AlgorithmType::OcrDetect:
|
||||
if (ocr_analyze(task_ptr)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void asst::ProcessTaskImageAnalyzer::set_image(const cv::Mat & image)
|
||||
{
|
||||
AbstractImageAnalyzer::set_image(image);
|
||||
reset();
|
||||
}
|
||||
#include "ProcessTaskImageAnalyzer.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "OcrImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
|
||||
asst::ProcessTaskImageAnalyzer::ProcessTaskImageAnalyzer(const cv::Mat& image, std::vector<std::string> tasks_name)
|
||||
: AbstractImageAnalyzer(image),
|
||||
m_tasks_name(std::move(tasks_name))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
asst::ProcessTaskImageAnalyzer::~ProcessTaskImageAnalyzer() = default;
|
||||
|
||||
bool asst::ProcessTaskImageAnalyzer::match_analyze(std::shared_ptr<TaskInfo> task_ptr)
|
||||
{
|
||||
if (!m_match_analyzer) {
|
||||
m_match_analyzer = std::make_unique<MatchImageAnalyzer>(m_image);
|
||||
}
|
||||
const auto match_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(task_ptr);
|
||||
m_match_analyzer->set_task_info(*match_task_ptr);
|
||||
|
||||
if (m_match_analyzer->analyze()) {
|
||||
m_result = match_task_ptr;
|
||||
m_result_rect = m_match_analyzer->get_result().rect;
|
||||
task_ptr->region_of_appeared = m_result_rect;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asst::ProcessTaskImageAnalyzer::ocr_analyze(std::shared_ptr<TaskInfo> task_ptr)
|
||||
{
|
||||
std::shared_ptr<OcrTaskInfo> ocr_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(task_ptr);
|
||||
|
||||
// 先尝试从缓存的结果里找
|
||||
//for (const TextRect& tr : m_ocr_cache) {
|
||||
// TextRect temp = tr;
|
||||
// for (const auto& [regex, new_str] : ocr_task_ptr->replace_map) {
|
||||
// temp.text = std::regex_replace(temp.text, std::regex(regex), new_str);
|
||||
// }
|
||||
// for (const auto& text : ocr_task_ptr->text) {
|
||||
// bool flag = false;
|
||||
// if (ocr_task_ptr->need_full_match) {
|
||||
// if (temp.text == text) {
|
||||
// flag = true;
|
||||
// }
|
||||
// }
|
||||
// else if (temp.text.find(text) != std::string::npos) {
|
||||
// flag = true;
|
||||
// }
|
||||
// // 即使找到了,也得在ROI里才行,不然过滤掉
|
||||
// if (flag && ocr_task_ptr->roi.include(tr.rect)) {
|
||||
// m_result = ocr_task_ptr;
|
||||
// m_result_rect = tr.rect;
|
||||
// ocr_task_ptr->region_of_appeared = m_result_rect;
|
||||
// Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found in cache", tr.to_string());
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
if (!m_ocr_analyzer) {
|
||||
m_ocr_analyzer = std::make_unique<OcrImageAnalyzer>(m_image);
|
||||
}
|
||||
m_ocr_analyzer->set_task_info(*ocr_task_ptr);
|
||||
|
||||
bool ret = m_ocr_analyzer->analyze();
|
||||
|
||||
if (ret) {
|
||||
const auto& ocr_result = m_ocr_analyzer->get_result();
|
||||
auto& res = ocr_result.front();
|
||||
m_result = ocr_task_ptr;
|
||||
m_result_rect = res.rect;
|
||||
ocr_task_ptr->region_of_appeared = res.rect;
|
||||
//m_ocr_cache.insert(m_ocr_cache.end(), ocr_result.begin(), ocr_result.end());
|
||||
Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found", res.to_string());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void asst::ProcessTaskImageAnalyzer::reset() noexcept
|
||||
{
|
||||
//m_ocr_cache.clear();
|
||||
m_ocr_analyzer = nullptr;
|
||||
m_match_analyzer = nullptr;
|
||||
}
|
||||
|
||||
bool asst::ProcessTaskImageAnalyzer::analyze()
|
||||
{
|
||||
m_result = nullptr;
|
||||
m_result_rect = Rect();
|
||||
|
||||
for (const std::string& task_name : m_tasks_name) {
|
||||
auto task_ptr = task.get(task_name);
|
||||
|
||||
switch (task_ptr->algorithm) {
|
||||
case AlgorithmType::JustReturn:
|
||||
m_result = task_ptr;
|
||||
return true;
|
||||
case AlgorithmType::MatchTemplate:
|
||||
if (match_analyze(task_ptr)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case AlgorithmType::OcrDetect:
|
||||
if (ocr_analyze(task_ptr)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void asst::ProcessTaskImageAnalyzer::set_image(const cv::Mat & image)
|
||||
{
|
||||
AbstractImageAnalyzer::set_image(image);
|
||||
reset();
|
||||
}
|
||||
|
||||
@@ -1,60 +1,63 @@
|
||||
#pragma once
|
||||
#include "AbstractImageAnalyzer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class OcrImageAnalyzer;
|
||||
class MatchImageAnalyzer;
|
||||
|
||||
class ProcessTaskImageAnalyzer final : public AbstractImageAnalyzer
|
||||
{
|
||||
public:
|
||||
using AbstractImageAnalyzer::AbstractImageAnalyzer;
|
||||
ProcessTaskImageAnalyzer(const cv::Mat& image, const Rect& roi) = delete;
|
||||
ProcessTaskImageAnalyzer(const cv::Mat& image, std::vector<std::string> tasks_name);
|
||||
virtual ~ProcessTaskImageAnalyzer();
|
||||
|
||||
virtual bool analyze() override;
|
||||
virtual void set_image(const cv::Mat& image) override;
|
||||
|
||||
void set_tasks(std::vector<std::string> tasks_name)
|
||||
{
|
||||
m_tasks_name = std::move(tasks_name);
|
||||
}
|
||||
std::shared_ptr<TaskInfo> get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const Rect& get_rect() const noexcept
|
||||
{
|
||||
return m_result_rect;
|
||||
}
|
||||
|
||||
private:
|
||||
// 该分析器不支持外部设置ROI
|
||||
virtual void set_roi(const Rect& roi) noexcept override
|
||||
{
|
||||
AbstractImageAnalyzer::set_roi(roi);
|
||||
}
|
||||
virtual void set_image(const cv::Mat& image, const Rect& roi)
|
||||
{
|
||||
AbstractImageAnalyzer::set_image(image, roi);
|
||||
}
|
||||
bool match_analyze(std::shared_ptr<TaskInfo> task_ptr);
|
||||
bool ocr_analyze(std::shared_ptr<TaskInfo> task_ptr);
|
||||
void reset() noexcept;
|
||||
|
||||
std::unique_ptr<OcrImageAnalyzer> m_ocr_analyzer = nullptr;
|
||||
std::unique_ptr<MatchImageAnalyzer> m_match_analyzer = nullptr;
|
||||
std::vector<std::string> m_tasks_name;
|
||||
std::shared_ptr<TaskInfo> m_result;
|
||||
Rect m_result_rect;
|
||||
//std::vector<TextRect> m_ocr_cache;
|
||||
};
|
||||
}
|
||||
#pragma once
|
||||
#include "AbstractImageAnalyzer.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class OcrImageAnalyzer;
|
||||
class MatchImageAnalyzer;
|
||||
|
||||
class ProcessTaskImageAnalyzer final : public AbstractImageAnalyzer
|
||||
{
|
||||
public:
|
||||
using AbstractImageAnalyzer::AbstractImageAnalyzer;
|
||||
ProcessTaskImageAnalyzer(const cv::Mat& image, const Rect& roi) = delete;
|
||||
ProcessTaskImageAnalyzer(const cv::Mat& image, std::vector<std::string> tasks_name);
|
||||
virtual ~ProcessTaskImageAnalyzer();
|
||||
|
||||
virtual bool analyze() override;
|
||||
virtual void set_image(const cv::Mat& image) override;
|
||||
|
||||
void set_tasks(std::vector<std::string> tasks_name)
|
||||
{
|
||||
m_tasks_name = std::move(tasks_name);
|
||||
}
|
||||
std::shared_ptr<TaskInfo> get_result() const noexcept
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
const Rect& get_rect() const noexcept
|
||||
{
|
||||
return m_result_rect;
|
||||
}
|
||||
|
||||
ProcessTaskImageAnalyzer& operator=(const ProcessTaskImageAnalyzer&) = delete;
|
||||
ProcessTaskImageAnalyzer& operator=(ProcessTaskImageAnalyzer&&) = delete;
|
||||
|
||||
private:
|
||||
// 该分析器不支持外部设置ROI
|
||||
virtual void set_roi(const Rect& roi) noexcept override
|
||||
{
|
||||
AbstractImageAnalyzer::set_roi(roi);
|
||||
}
|
||||
virtual void set_image(const cv::Mat& image, const Rect& roi)
|
||||
{
|
||||
AbstractImageAnalyzer::set_image(image, roi);
|
||||
}
|
||||
bool match_analyze(std::shared_ptr<TaskInfo> task_ptr);
|
||||
bool ocr_analyze(std::shared_ptr<TaskInfo> task_ptr);
|
||||
void reset() noexcept;
|
||||
|
||||
std::unique_ptr<OcrImageAnalyzer> m_ocr_analyzer;
|
||||
std::unique_ptr<MatchImageAnalyzer> m_match_analyzer;
|
||||
std::vector<std::string> m_tasks_name;
|
||||
std::shared_ptr<TaskInfo> m_result;
|
||||
Rect m_result_rect;
|
||||
//std::vector<TextRect> m_ocr_cache;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
#include "Resource.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
bool asst::Resource::load(const std::string& dir)
|
||||
{
|
||||
constexpr static const char* TemplsFilename = "template";
|
||||
constexpr static const char* GeneralCfgFilename = "config.json";
|
||||
constexpr static const char* TaskDataFilename = "tasks.json";
|
||||
constexpr static const char* RecruitCfgFilename = "recruit.json";
|
||||
constexpr static const char* ItemCfgFilename = "item_index.json";
|
||||
constexpr static const char* InfrastCfgFilename = "infrast.json";
|
||||
constexpr static const char* UserCfgFilename = "..\\user.json";
|
||||
constexpr static const char* OcrResourceFilename = "PaddleOCR";
|
||||
constexpr static const char* PenguinResourceFilename = "penguin-stats-recognize";
|
||||
|
||||
/* 加载各个Json配置文件 */
|
||||
if (!m_general_cfg_unique_ins.load(dir + GeneralCfgFilename)) {
|
||||
m_last_error = m_general_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (!task.load(dir + TaskDataFilename)) {
|
||||
m_last_error = task.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_recruit_cfg_unique_ins.load(dir + RecruitCfgFilename)) {
|
||||
m_last_error = m_recruit_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (!m_item_cfg_unique_ins.load(dir + ItemCfgFilename)) {
|
||||
m_last_error = m_item_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (!m_infrast_cfg_unique_ins.load(dir + InfrastCfgFilename)) {
|
||||
m_last_error = m_infrast_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_user_cfg_unique_ins.load(dir + UserCfgFilename)) {
|
||||
m_last_error = m_user_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
/* 根据用户配置,覆盖原有的部分配置 */
|
||||
for (const auto& [name, path] : m_user_cfg_unique_ins.get_emulator_path()) {
|
||||
m_general_cfg_unique_ins.set_emulator_path(name, path);
|
||||
}
|
||||
const auto& opt = m_general_cfg_unique_ins.get_options();
|
||||
|
||||
/* 加载模板图片资源 */
|
||||
// task所需要的模板资源
|
||||
m_templ_resource_unique_ins.append_load_required(task.get_templ_required());
|
||||
// 基建所需要的模板资源
|
||||
m_templ_resource_unique_ins.append_load_required(m_infrast_cfg_unique_ins.get_templ_required());
|
||||
|
||||
if (!m_templ_resource_unique_ins.load(dir + TemplsFilename)) {
|
||||
m_last_error = m_templ_resource_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 加载OCR库所需要的资源 */
|
||||
//m_ocr_pack_unique_ins.set_param(opt.ocr_gpu_index, opt.ocr_thread_number);
|
||||
if (!m_ocr_pack_unique_ins.load(dir + OcrResourceFilename)) {
|
||||
m_last_error = m_ocr_pack_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
/* 加载企鹅数据识别库所需要的资源 */
|
||||
m_penguin_pack_unique_ins.set_language(opt.penguin_report.server);
|
||||
if (!m_penguin_pack_unique_ins.load(dir + PenguinResourceFilename)) {
|
||||
m_last_error = m_penguin_pack_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#include "Resource.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <meojson/json.h>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
bool asst::Resource::load(const std::string& dir)
|
||||
{
|
||||
constexpr static const char* TemplsFilename = "template";
|
||||
constexpr static const char* GeneralCfgFilename = "config.json";
|
||||
constexpr static const char* TaskDataFilename = "tasks.json";
|
||||
constexpr static const char* RecruitCfgFilename = "recruit.json";
|
||||
constexpr static const char* ItemCfgFilename = "item_index.json";
|
||||
constexpr static const char* InfrastCfgFilename = "infrast.json";
|
||||
constexpr static const char* UserCfgFilename = "..\\user.json";
|
||||
constexpr static const char* OcrResourceFilename = "PaddleOCR";
|
||||
constexpr static const char* PenguinResourceFilename = "penguin-stats-recognize";
|
||||
|
||||
/* 加载各个Json配置文件 */
|
||||
if (!m_general_cfg_unique_ins.load(dir + GeneralCfgFilename)) {
|
||||
m_last_error = std::string(GeneralCfgFilename) + ": " + m_general_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (!task.load(dir + TaskDataFilename)) {
|
||||
m_last_error = std::string(TaskDataFilename) + ": " + task.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_recruit_cfg_unique_ins.load(dir + RecruitCfgFilename)) {
|
||||
m_last_error = std::string(RecruitCfgFilename) + ": " + m_recruit_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (!m_item_cfg_unique_ins.load(dir + ItemCfgFilename)) {
|
||||
m_last_error = std::string(ItemCfgFilename) + ": " + m_item_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (!m_infrast_cfg_unique_ins.load(dir + InfrastCfgFilename)) {
|
||||
m_last_error = std::string(InfrastCfgFilename) + ": " + m_infrast_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_user_cfg_unique_ins.load(dir + UserCfgFilename)) {
|
||||
m_last_error = std::string(UserCfgFilename) + ": " + m_user_cfg_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
/* 根据用户配置,覆盖原有的部分配置 */
|
||||
for (const auto& [name, path] : m_user_cfg_unique_ins.get_emulator_path()) {
|
||||
m_general_cfg_unique_ins.set_emulator_path(name, path);
|
||||
}
|
||||
const auto& opt = m_general_cfg_unique_ins.get_options();
|
||||
|
||||
/* 加载模板图片资源 */
|
||||
// task所需要的模板资源
|
||||
m_templ_resource_unique_ins.append_load_required(task.get_templ_required());
|
||||
// 基建所需要的模板资源
|
||||
m_templ_resource_unique_ins.append_load_required(m_infrast_cfg_unique_ins.get_templ_required());
|
||||
|
||||
if (!m_templ_resource_unique_ins.load(dir + TemplsFilename)) {
|
||||
m_last_error = std::string(TemplsFilename) + ": " + m_templ_resource_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 加载OCR库所需要的资源 */
|
||||
//m_ocr_pack_unique_ins.set_param(opt.ocr_gpu_index, opt.ocr_thread_number);
|
||||
if (!m_ocr_pack_unique_ins.load(dir + OcrResourceFilename)) {
|
||||
m_last_error = std::string(OcrResourceFilename) + ": " + m_ocr_pack_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
/* 加载企鹅数据识别库所需要的资源 */
|
||||
m_penguin_pack_unique_ins.set_language(opt.penguin_report.server);
|
||||
if (!m_penguin_pack_unique_ins.load(dir + PenguinResourceFilename)) {
|
||||
m_last_error = std::string(PenguinResourceFilename) + ": " + m_penguin_pack_unique_ins.get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,117 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractResource.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "GeneralConfiger.h"
|
||||
#include "InfrastConfiger.h"
|
||||
#include "ItemConfiger.h"
|
||||
#include "OcrPack.h"
|
||||
#include "PenguinPack.h"
|
||||
#include "RecruitConfiger.h"
|
||||
#include "TaskData.h"
|
||||
#include "TemplResource.h"
|
||||
#include "UserConfiger.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Resource : public AbstractResource
|
||||
{
|
||||
public:
|
||||
virtual ~Resource() = default;
|
||||
|
||||
static Resource& get_instance()
|
||||
{
|
||||
static Resource unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
virtual bool load(const std::string& dir) override;
|
||||
|
||||
TemplResource& templ() noexcept
|
||||
{
|
||||
return m_templ_resource_unique_ins;
|
||||
}
|
||||
GeneralConfiger& cfg() noexcept
|
||||
{
|
||||
return m_general_cfg_unique_ins;
|
||||
}
|
||||
RecruitConfiger& recruit() noexcept
|
||||
{
|
||||
return m_recruit_cfg_unique_ins;
|
||||
}
|
||||
ItemConfiger& item() noexcept
|
||||
{
|
||||
return m_item_cfg_unique_ins;
|
||||
}
|
||||
InfrastConfiger& infrast() noexcept
|
||||
{
|
||||
return m_infrast_cfg_unique_ins;
|
||||
}
|
||||
UserConfiger& user() noexcept
|
||||
{
|
||||
return m_user_cfg_unique_ins;
|
||||
}
|
||||
OcrPack& ocr() noexcept
|
||||
{
|
||||
return m_ocr_pack_unique_ins;
|
||||
}
|
||||
PenguinPack& penguin() noexcept
|
||||
{
|
||||
return m_penguin_pack_unique_ins;
|
||||
}
|
||||
|
||||
const TemplResource& templ() const noexcept
|
||||
{
|
||||
return m_templ_resource_unique_ins;
|
||||
}
|
||||
const GeneralConfiger& cfg() const noexcept
|
||||
{
|
||||
return m_general_cfg_unique_ins;
|
||||
}
|
||||
const RecruitConfiger& recruit() const noexcept
|
||||
{
|
||||
return m_recruit_cfg_unique_ins;
|
||||
}
|
||||
const ItemConfiger& item() const noexcept
|
||||
{
|
||||
return m_item_cfg_unique_ins;
|
||||
}
|
||||
const InfrastConfiger& infrast() const noexcept
|
||||
{
|
||||
return m_infrast_cfg_unique_ins;
|
||||
}
|
||||
const UserConfiger& user() const noexcept
|
||||
{
|
||||
return m_user_cfg_unique_ins;
|
||||
}
|
||||
const OcrPack& ocr() const noexcept
|
||||
{
|
||||
return m_ocr_pack_unique_ins;
|
||||
}
|
||||
const PenguinPack& penguin() const noexcept
|
||||
{
|
||||
return m_penguin_pack_unique_ins;
|
||||
}
|
||||
|
||||
Resource& operator=(const Resource&) = delete;
|
||||
Resource& operator=(Resource&&) noexcept = delete;
|
||||
|
||||
private:
|
||||
Resource() = default;
|
||||
|
||||
TemplResource m_templ_resource_unique_ins;
|
||||
GeneralConfiger m_general_cfg_unique_ins;
|
||||
RecruitConfiger m_recruit_cfg_unique_ins;
|
||||
ItemConfiger m_item_cfg_unique_ins;
|
||||
InfrastConfiger m_infrast_cfg_unique_ins;
|
||||
UserConfiger m_user_cfg_unique_ins;
|
||||
OcrPack m_ocr_pack_unique_ins;
|
||||
PenguinPack m_penguin_pack_unique_ins;
|
||||
};
|
||||
|
||||
//static auto& resource = Resource::get_instance();
|
||||
#define Resrc Resource::get_instance()
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include "AbstractResource.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "GeneralConfiger.h"
|
||||
#include "InfrastConfiger.h"
|
||||
#include "ItemConfiger.h"
|
||||
#include "OcrPack.h"
|
||||
#include "PenguinPack.h"
|
||||
#include "RecruitConfiger.h"
|
||||
#include "TaskData.h"
|
||||
#include "TemplResource.h"
|
||||
#include "UserConfiger.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class Resource : public AbstractResource
|
||||
{
|
||||
public:
|
||||
virtual ~Resource() = default;
|
||||
|
||||
static Resource& get_instance()
|
||||
{
|
||||
static Resource unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
virtual bool load(const std::string& dir) override;
|
||||
|
||||
TemplResource& templ() noexcept
|
||||
{
|
||||
return m_templ_resource_unique_ins;
|
||||
}
|
||||
GeneralConfiger& cfg() noexcept
|
||||
{
|
||||
return m_general_cfg_unique_ins;
|
||||
}
|
||||
RecruitConfiger& recruit() noexcept
|
||||
{
|
||||
return m_recruit_cfg_unique_ins;
|
||||
}
|
||||
ItemConfiger& item() noexcept
|
||||
{
|
||||
return m_item_cfg_unique_ins;
|
||||
}
|
||||
InfrastConfiger& infrast() noexcept
|
||||
{
|
||||
return m_infrast_cfg_unique_ins;
|
||||
}
|
||||
UserConfiger& user() noexcept
|
||||
{
|
||||
return m_user_cfg_unique_ins;
|
||||
}
|
||||
OcrPack& ocr() noexcept
|
||||
{
|
||||
return m_ocr_pack_unique_ins;
|
||||
}
|
||||
PenguinPack& penguin() noexcept
|
||||
{
|
||||
return m_penguin_pack_unique_ins;
|
||||
}
|
||||
|
||||
const TemplResource& templ() const noexcept
|
||||
{
|
||||
return m_templ_resource_unique_ins;
|
||||
}
|
||||
const GeneralConfiger& cfg() const noexcept
|
||||
{
|
||||
return m_general_cfg_unique_ins;
|
||||
}
|
||||
const RecruitConfiger& recruit() const noexcept
|
||||
{
|
||||
return m_recruit_cfg_unique_ins;
|
||||
}
|
||||
const ItemConfiger& item() const noexcept
|
||||
{
|
||||
return m_item_cfg_unique_ins;
|
||||
}
|
||||
const InfrastConfiger& infrast() const noexcept
|
||||
{
|
||||
return m_infrast_cfg_unique_ins;
|
||||
}
|
||||
const UserConfiger& user() const noexcept
|
||||
{
|
||||
return m_user_cfg_unique_ins;
|
||||
}
|
||||
const OcrPack& ocr() const noexcept
|
||||
{
|
||||
return m_ocr_pack_unique_ins;
|
||||
}
|
||||
const PenguinPack& penguin() const noexcept
|
||||
{
|
||||
return m_penguin_pack_unique_ins;
|
||||
}
|
||||
|
||||
Resource& operator=(const Resource&) = delete;
|
||||
Resource& operator=(Resource&&) noexcept = delete;
|
||||
|
||||
private:
|
||||
Resource() = default;
|
||||
|
||||
TemplResource m_templ_resource_unique_ins;
|
||||
GeneralConfiger m_general_cfg_unique_ins;
|
||||
RecruitConfiger m_recruit_cfg_unique_ins;
|
||||
ItemConfiger m_item_cfg_unique_ins;
|
||||
InfrastConfiger m_infrast_cfg_unique_ins;
|
||||
UserConfiger m_user_cfg_unique_ins;
|
||||
OcrPack m_ocr_pack_unique_ins;
|
||||
PenguinPack m_penguin_pack_unique_ins;
|
||||
};
|
||||
|
||||
//static auto& resource = Resource::get_instance();
|
||||
#define Resrc Resource::get_instance()
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
#include "TemplResource.h"
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
|
||||
void asst::TemplResource::append_load_required(std::unordered_set<std::string> required) noexcept
|
||||
{
|
||||
m_templs_filename.insert(
|
||||
std::make_move_iterator(required.begin()),
|
||||
std::make_move_iterator(required.end()));
|
||||
}
|
||||
|
||||
bool asst::TemplResource::load(const std::string& dir)
|
||||
{
|
||||
for (const std::string& filename : m_templs_filename) {
|
||||
std::string filepath = dir + "\\" + filename;
|
||||
if (std::filesystem::exists(filepath)) {
|
||||
cv::Mat templ = cv::imread(filepath);
|
||||
emplace_templ(filename, std::move(templ));
|
||||
}
|
||||
else {
|
||||
m_last_error = filepath + " not exists";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::TemplResource::exist_templ(const std::string& key) const noexcept
|
||||
{
|
||||
return m_templs.find(key) != m_templs.cend();
|
||||
}
|
||||
|
||||
const cv::Mat& asst::TemplResource::get_templ(const std::string& key) const noexcept
|
||||
{
|
||||
if (auto iter = m_templs.find(key);
|
||||
iter != m_templs.cend()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
const static cv::Mat empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
void asst::TemplResource::emplace_templ(std::string key, cv::Mat templ)
|
||||
{
|
||||
m_templs.emplace(std::move(key), std::move(templ));
|
||||
}
|
||||
#include "TemplResource.h"
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
|
||||
void asst::TemplResource::append_load_required(std::unordered_set<std::string> required) noexcept
|
||||
{
|
||||
m_templs_filename.insert(
|
||||
std::make_move_iterator(required.begin()),
|
||||
std::make_move_iterator(required.end()));
|
||||
}
|
||||
|
||||
bool asst::TemplResource::load(const std::string& dir)
|
||||
{
|
||||
for (const std::string& filename : m_templs_filename) {
|
||||
std::string filepath = dir + "/" + filename;
|
||||
if (std::filesystem::exists(filepath)) {
|
||||
cv::Mat templ = cv::imread(filepath);
|
||||
emplace_templ(filename, std::move(templ));
|
||||
}
|
||||
else {
|
||||
m_last_error = filepath + " not exists";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::TemplResource::exist_templ(const std::string& key) const noexcept
|
||||
{
|
||||
return m_templs.find(key) != m_templs.cend();
|
||||
}
|
||||
|
||||
const cv::Mat& asst::TemplResource::get_templ(const std::string& key) const noexcept
|
||||
{
|
||||
if (auto iter = m_templs.find(key);
|
||||
iter != m_templs.cend()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
const static cv::Mat empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
void asst::TemplResource::emplace_templ(std::string key, cv::Mat templ)
|
||||
{
|
||||
m_templs.emplace(std::move(key), std::move(templ));
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import ctypes
|
||||
import os
|
||||
import json
|
||||
import pathlib
|
||||
import platform
|
||||
|
||||
from message import Message
|
||||
|
||||
|
||||
@@ -24,16 +26,20 @@ class Asst:
|
||||
``callback``: 回调函数
|
||||
``arg``: 自定义参数
|
||||
"""
|
||||
self.__dllpath = pathlib.Path(dirname) / 'MeoAssistant.dll'
|
||||
self.__dll = ctypes.WinDLL(str(self.__dllpath))
|
||||
if platform.system().lower() == 'windows':
|
||||
self.__libpath = pathlib.Path(dirname) / 'MeoAssistant.dll'
|
||||
self.__lib = ctypes.WinDLL(str(self.__libpath))
|
||||
else:
|
||||
self.__libpath = pathlib.Path(dirname) / 'libMeoAssistant.so'
|
||||
self.__lib = ctypes.CDLL(str(self.__libpath))
|
||||
|
||||
self.__dll.AsstCreateEx.restype = ctypes.c_void_p
|
||||
self.__dll.AsstCreateEx.argtypes = (ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p,)
|
||||
self.__ptr = self.__dll.AsstCreateEx(dirname.encode('utf-8'), callback, arg)
|
||||
self.__lib.AsstCreateEx.restype = ctypes.c_void_p
|
||||
self.__lib.AsstCreateEx.argtypes = (ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p,)
|
||||
self.__ptr = self.__lib.AsstCreateEx(dirname.encode('utf-8'), callback, arg)
|
||||
|
||||
def __del__(self):
|
||||
self.__dll.AsstDestroy.argtypes = (ctypes.c_void_p,)
|
||||
self.__dll.AsstDestroy(self.__ptr)
|
||||
self.__lib.AsstDestroy.argtypes = (ctypes.c_void_p,)
|
||||
self.__lib.AsstDestroy(self.__ptr)
|
||||
|
||||
def catch_default(self) -> bool:
|
||||
"""
|
||||
@@ -41,8 +47,8 @@ class Asst:
|
||||
|
||||
:return: 是否连接成功
|
||||
"""
|
||||
self.__dll.AsstCatchDefault.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstCatchDefault(self.__ptr)
|
||||
self.__lib.AsstCatchDefault.argtypes = (ctypes.c_void_p,)
|
||||
return self.__lib.AsstCatchDefault(self.__ptr)
|
||||
|
||||
def catch_emulator(self) -> bool:
|
||||
"""
|
||||
@@ -50,8 +56,8 @@ class Asst:
|
||||
|
||||
:return: 是否连接成功
|
||||
"""
|
||||
self.__dll.AsstCatchEmulator.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstCatchEmulator(self.__ptr)
|
||||
self.__lib.AsstCatchEmulator.argtypes = (ctypes.c_void_p,)
|
||||
return self.__lib.AsstCatchEmulator(self.__ptr)
|
||||
|
||||
def catch_custom(self, address: str) -> bool:
|
||||
"""
|
||||
@@ -59,9 +65,9 @@ class Asst:
|
||||
|
||||
:return: 是否连接成功
|
||||
"""
|
||||
self.__dll.AsstCatchCustom.argtypes = (
|
||||
self.__lib.AsstCatchCustom.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_char_p,)
|
||||
return self.__dll.AsstCatchCustom(self.__ptr, address.encode('utf-8'))
|
||||
return self.__lib.AsstCatchCustom(self.__ptr, address.encode('utf-8'))
|
||||
|
||||
def append_fight(self, stage: str, max_medicine: int, max_stone: int, max_times: int) -> bool:
|
||||
"""
|
||||
@@ -74,23 +80,23 @@ class Asst:
|
||||
``max_stone``: 最多吃多少源石
|
||||
``max_times``: 最多刷多少
|
||||
"""
|
||||
self.__dll.AsstAppendFight.argtypes = (
|
||||
self.__lib.AsstAppendFight.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, ctypes.c_int,)
|
||||
return self.__dll.AsstAppendFight(self.__ptr, stage.encode('utf-8'), max_medicine, max_stone, max_times)
|
||||
return self.__lib.AsstAppendFight(self.__ptr, stage.encode('utf-8'), max_medicine, max_stone, max_times)
|
||||
|
||||
def append_award(self) -> bool:
|
||||
"""
|
||||
添加领取每日奖励任务
|
||||
"""
|
||||
self.__dll.AsstAppendAward.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstAppendAward(self.__ptr)
|
||||
self.__lib.AsstAppendAward.argtypes = (ctypes.c_void_p,)
|
||||
return self.__lib.AsstAppendAward(self.__ptr)
|
||||
|
||||
def append_visit(self) -> bool:
|
||||
"""
|
||||
添加访问好友任务
|
||||
"""
|
||||
self.__dll.AsstAppendVisit.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstAppendVisit(self.__ptr)
|
||||
self.__lib.AsstAppendVisit.argtypes = (ctypes.c_void_p,)
|
||||
return self.__lib.AsstAppendVisit(self.__ptr)
|
||||
|
||||
def append_mall(self, with_shopping: bool) -> bool:
|
||||
"""
|
||||
@@ -99,8 +105,8 @@ class Asst:
|
||||
:params:
|
||||
``with_shopping``: 是否信用商店购物
|
||||
"""
|
||||
self.__dll.AsstAppendMall.argtypes = (ctypes.c_void_p, ctypes.c_bool)
|
||||
return self.__dll.AsstAppendMall(self.__ptr, with_shopping)
|
||||
self.__lib.AsstAppendMall.argtypes = (ctypes.c_void_p, ctypes.c_bool)
|
||||
return self.__lib.AsstAppendMall(self.__ptr, with_shopping)
|
||||
|
||||
def append_infrast(self, work_mode: int, order_list: list, uses_of_drones: str, dorm_threshold: float) -> bool:
|
||||
"""
|
||||
@@ -121,11 +127,11 @@ class Asst:
|
||||
order_arr = (ctypes.c_char_p * order_len)()
|
||||
order_arr[:] = order_byte_list
|
||||
|
||||
self.__dll.AsstAppendInfrast.argtypes = (
|
||||
self.__lib.AsstAppendInfrast.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.POINTER(ctypes.c_char_p), ctypes.c_int,
|
||||
ctypes.c_char_p, ctypes.c_double,)
|
||||
return self.__dll.AsstAppendInfrast(self.__ptr, work_mode,
|
||||
return self.__lib.AsstAppendInfrast(self.__ptr, work_mode,
|
||||
order_arr, order_len,
|
||||
uses_of_drones.encode('utf-8'), dorm_threshold)
|
||||
|
||||
@@ -147,11 +153,11 @@ class Asst:
|
||||
confirm_arr = (ctypes.c_int * confirm_len)()
|
||||
confirm_arr[:] = confirm_level
|
||||
|
||||
self.__dll.AsstAppendRecruit.argtypes = (
|
||||
self.__lib.AsstAppendRecruit.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.POINTER(ctypes.c_int), ctypes.c_int,
|
||||
ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_bool,)
|
||||
return self.__dll.AsstAppendRecruit(self.__ptr, max_times,
|
||||
return self.__lib.AsstAppendRecruit(self.__ptr, max_times,
|
||||
select_arr, select_len,
|
||||
confirm_arr, confirm_len, need_refresh)
|
||||
|
||||
@@ -159,8 +165,8 @@ class Asst:
|
||||
"""
|
||||
开始任务
|
||||
"""
|
||||
self.__dll.AsstStart.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstStart(self.__ptr)
|
||||
self.__lib.AsstStart.argtypes = (ctypes.c_void_p,)
|
||||
return self.__lib.AsstStart(self.__ptr)
|
||||
|
||||
def start_recurit_calc(self, select_level: list, set_time: bool) -> bool:
|
||||
"""
|
||||
@@ -174,16 +180,16 @@ class Asst:
|
||||
select_arr = (ctypes.c_int * select_len)()
|
||||
select_arr[:] = select_level
|
||||
|
||||
self.__dll.AsstStartRecruitCalc.argtypes = (
|
||||
self.__lib.AsstStartRecruitCalc.argtypes = (
|
||||
ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_bool,)
|
||||
return self.__dll.AsstStartRecruitCalc(self.__ptr, select_arr, select_len, set_time)
|
||||
return self.__lib.AsstStartRecruitCalc(self.__ptr, select_arr, select_len, set_time)
|
||||
|
||||
def stop(self) -> bool:
|
||||
"""
|
||||
停止并清空所有任务
|
||||
"""
|
||||
self.__dll.AsstStop.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstStop(self.__ptr)
|
||||
self.__lib.AsstStop.argtypes = (ctypes.c_void_p,)
|
||||
return self.__lib.AsstStop(self.__ptr)
|
||||
|
||||
def set_penguin_id(self, id: str) -> bool:
|
||||
"""
|
||||
@@ -192,9 +198,9 @@ class Asst:
|
||||
:params:
|
||||
``id``: 企鹅物流ID,仅数字部分
|
||||
"""
|
||||
self.__dll.AsstSetPenguinId.argtypes = (
|
||||
self.__lib.AsstSetPenguinId.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_char_p)
|
||||
return self.__dll.AsstSetPenguinId(self.__ptr, id.encode('utf-8'))
|
||||
return self.__lib.AsstSetPenguinId(self.__ptr, id.encode('utf-8'))
|
||||
|
||||
def get_version(self) -> str:
|
||||
"""
|
||||
@@ -202,8 +208,8 @@ class Asst:
|
||||
|
||||
:return: 版本号
|
||||
"""
|
||||
self.__dll.AsstGetVersion.restype = ctypes.c_char_p
|
||||
return self.__dll.AsstGetVersion().decode('utf-8')
|
||||
self.__lib.AsstGetVersion.restype = ctypes.c_char_p
|
||||
return self.__lib.AsstGetVersion().decode('utf-8')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -213,16 +219,20 @@ if __name__ == "__main__":
|
||||
d = json.loads(details.decode('gbk'))
|
||||
print(Message(msg), d, arg)
|
||||
|
||||
dirname: str = (pathlib.Path.cwd().parent.parent / 'x64' / 'Release').__str__()
|
||||
if platform.system().lower() == 'windows':
|
||||
dirname: str = (pathlib.Path.cwd().parent.parent / 'x64' / 'Release').__str__()
|
||||
else:
|
||||
dirname: str = (pathlib.Path.cwd().parent.parent / 'build').__str__()
|
||||
|
||||
asst = Asst(dirname=dirname, callback=my_callback)
|
||||
|
||||
print('version', asst.get_version())
|
||||
|
||||
if asst.catch_default():
|
||||
if asst.catch_custom('127.0.0.1:5555'):
|
||||
print('连接成功')
|
||||
else:
|
||||
print('连接失败')
|
||||
os.system.exit()
|
||||
exit()
|
||||
|
||||
asst.append_fight("CE-5", 0, 0, 1)
|
||||
# asst.append_infrast(1, [ "Mfg", "Trade", "Control", "Power", "Reception", "Office", "Dorm"], "Money", 0.3)
|
||||
|
||||
@@ -10,7 +10,7 @@ class Message(Enum):
|
||||
注释部分仅展示常用消息的回调JSON格式,完全的回调JSON请参考C++侧实现代码
|
||||
"""
|
||||
|
||||
PtrIsNull = auto()
|
||||
PtrIsNull = 0
|
||||
"""
|
||||
指针为空
|
||||
"""
|
||||
|
||||
@@ -2,24 +2,23 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
std::string get_cur_dir()
|
||||
{
|
||||
char exepath_buff[_MAX_PATH] = { 0 };
|
||||
::GetModuleFileNameA(NULL, exepath_buff, _MAX_PATH);
|
||||
std::string exepath(exepath_buff);
|
||||
std::string cur_dir = exepath.substr(0, exepath.find_last_of('\\') + 1);
|
||||
return cur_dir;
|
||||
return std::filesystem::current_path().u8string();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
auto ptr = AsstCreate(get_cur_dir().c_str());
|
||||
auto ret = AsstCatchEmulator(ptr);
|
||||
if (ptr == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto ret = AsstCatchCustom(ptr, "127.0.0.1:5555");
|
||||
if (!ret) {
|
||||
getchar();
|
||||
std::cout << "connect failed" << std::endl;
|
||||
if (ptr) {
|
||||
AsstDestroy(ptr);
|
||||
ptr = nullptr;
|
||||
@@ -29,24 +28,24 @@ int main(int argc, char** argv)
|
||||
|
||||
char ch = 0;
|
||||
while (ch != 'q') {
|
||||
//AsstAppendStartUp(ptr);
|
||||
// AsstAppendStartUp(ptr);
|
||||
AsstAppendFight(ptr, "CE-5", 0, 0, 99999);
|
||||
//AsstAppendVisit(ptr, true);
|
||||
// AsstAppendVisit(ptr, true);
|
||||
//{
|
||||
// const int required[] = { 3, 4, 5, 6 };
|
||||
// AsstStartRecruitCalc(ptr, required, sizeof(required) / sizeof(int), true);
|
||||
//}
|
||||
//AsstAppendDebug(ptr);
|
||||
// const int required[] = { 3, 4, 5, 6 };
|
||||
// AsstStartRecruitCalc(ptr, required, sizeof(required) / sizeof(int), true);
|
||||
// }
|
||||
// AsstAppendDebug(ptr);
|
||||
//{
|
||||
// const char* order[] = { "Trade", "Mfg", "Dorm" };
|
||||
// AsstAppendInfrast(ptr, 1, order, 3, 0, 0);
|
||||
//}
|
||||
//AsstAppendProcessTask(ptr, "AwardBegin");
|
||||
// const char* order[] = { "Trade", "Mfg", "Dorm" };
|
||||
// AsstAppendInfrast(ptr, 1, order, 3, 0, 0);
|
||||
// }
|
||||
// AsstAppendProcessTask(ptr, "AwardBegin");
|
||||
//{
|
||||
// const int required[] = { 4 };
|
||||
// const int confirm[] = { 3, 4 };
|
||||
// AsstAppendRecruit(ptr, 2, required, sizeof(required) / sizeof(int), confirm, sizeof(confirm) / sizeof(int));
|
||||
//}
|
||||
// const int required[] = { 4 };
|
||||
// const int confirm[] = { 3, 4 };
|
||||
// AsstAppendRecruit(ptr, 2, required, sizeof(required) / sizeof(int), confirm, sizeof(confirm) / sizeof(int));
|
||||
// }
|
||||
AsstStart(ptr);
|
||||
|
||||
ch = getchar();
|
||||
|
||||
3
tools/update_resource.sh
Normal file
3
tools/update_resource.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
mkdir -p ../build/Resource
|
||||
cp -r ../resource/* ../build/Resource
|
||||
cp -r ../3rdparty/resource/* ../build/Resource
|
||||
Reference in New Issue
Block a user