feat.初步完成跨平台移植的初始化部分

This commit is contained in:
MistEO
2021-12-25 17:48:20 +08:00
parent 077c8fa734
commit 8658395fee
30 changed files with 3774 additions and 3592 deletions

1
.gitignore vendored
View File

@@ -432,3 +432,4 @@ screen.png
adb_screen.png
tools/*.png
resource/infrast
.vscode/settings.json

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;
};
}

View File

@@ -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
};
}

View File

@@ -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;
};
}

View File

@@ -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

View File

@@ -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;
};
}

View File

@@ -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
}

View File

@@ -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;
};
}

View File

@@ -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

View File

@@ -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有些模拟器自带的adbexec-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有些模拟器自带的adbexec-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()
}

View File

@@ -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;
}

View File

@@ -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;
};
}

View 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

View File

@@ -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
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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;
};
}

View File

@@ -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;
}

View File

@@ -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()
}

View File

@@ -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));
}

View File

@@ -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)

View File

@@ -10,7 +10,7 @@ class Message(Enum):
注释部分仅展示常用消息的回调JSON格式完全的回调JSON请参考C++侧实现代码
"""
PtrIsNull = auto()
PtrIsNull = 0
"""
指针为空
"""

View File

@@ -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
View File

@@ -0,0 +1,3 @@
mkdir -p ../build/Resource
cp -r ../resource/* ../build/Resource
cp -r ../3rdparty/resource/* ../build/Resource