Compare commits

..

75 Commits
v2.2 ... v2.5.1

Author SHA1 Message Date
MistEO
1a4ddfee71 fix.修复任务开始后,选关按钮仍可用的问题 2021-12-20 23:32:55 +08:00
MistEO
3c0d91e320 chore.更新版本号 2021-12-20 23:23:59 +08:00
MistEO
a0f317b7c3 opt.更新python的接口 2021-12-20 23:23:41 +08:00
MistEO
08b5d92f6d opt.界面上解耦自动公招与公招识别 2021-12-20 23:13:17 +08:00
MistEO
fb8b323335 perf.降低日志开关文件频率 2021-12-20 22:42:30 +08:00
MistEO
afabb54c42 fix.修复ADB子进程不释放的问题: https://github.com/MistEO/MeoAssistantArknights/issues/53 2021-12-20 22:42:15 +08:00
MistEO
aa89efee15 feat.添加任务全部完成通知 2021-12-20 21:39:30 +08:00
MistEO
0bc224f671 feat.优化选关功能,新增部分关卡 2021-12-20 21:33:27 +08:00
MistEO
d0164a958d chore.更新版本号 2021-12-20 01:35:37 +08:00
MistEO
f165e0b2b2 feat.新增选关-剿灭;新增开始唤醒选项 2021-12-20 01:35:09 +08:00
MistEO
a5f9e55fe2 feat.完成选关功能 2021-12-20 01:02:39 +08:00
MistEO
7fc46c160c fix.修复OCR缓存区域错误的问题 2021-12-19 22:41:51 +08:00
MistEO
481135bcb2 chore.更新版本号 2021-12-18 21:04:33 +08:00
MistEO
a2c49d2feb feat.暂时废弃百度 OCR API 2021-12-18 21:00:24 +08:00
MistEO
02551f62ce Merge branch 'dev' of https://github.com/MistEO/MeoAssistance-Arknights into dev 2021-12-16 12:22:53 +08:00
MistEO
07436c3c70 fix.修复偶现的公招识别错误 2021-12-16 01:32:26 +08:00
MistEO
53c993cd67 chore. Update issue templates 2021-12-16 01:26:39 +08:00
MistEO
d7b21ea307 feat.初步完成百度OCR API的集成 2021-12-16 01:21:11 +08:00
MistEO
d2962f10be fix.修复红云组未精二火神的效率 2021-12-16 00:29:18 +08:00
MistEO
39ffb8e50a chore.Init issue templates 2021-12-15 22:50:53 +08:00
MistEO
d3d81253a4 fix.修复更新检查策略 2021-12-15 12:33:09 +08:00
MistEO
febe7eacd7 merge.合并dev 2021-12-15 11:46:38 +08:00
MistEO
240dee72d5 chore.更新版本号,修改cmake产物名 2021-12-15 11:32:15 +08:00
MistEO
7e5875d213 chore.补上漏了的依赖 2021-12-15 11:23:44 +08:00
MistEO
5e36b493c1 chore.修改接口类型 2021-12-15 01:42:56 +08:00
MistEO
7274f50684 chore.项目重命名 2021-12-15 01:07:10 +08:00
MistEO
d9182694a6 style.代码格式化 2021-12-15 00:29:25 +08:00
MistEO
ad68e046f1 feat.OcrReplace支持正则替换,优化公招识别 2021-12-15 00:29:25 +08:00
MistEO
0d082d1635 perf.更新飞桨为移动端资源,调整部分参数 2021-12-15 00:29:24 +08:00
MistEO
989b96213f opt.优化一些计时方式 2021-12-15 00:29:23 +08:00
MistEO
f2c3129fee opt.优化日志的一些小问题 2021-12-15 00:29:23 +08:00
MistEO
9c20b5da49 style.项目、文件名统一化 2021-12-15 00:29:17 +08:00
MistEO
b516c94512 opt.优化新版本下载出错的情况 2021-12-13 22:19:53 +08:00
MistEO
c233c3ed38 opt.优化新版本下载出错的情况 2021-12-13 00:27:38 +08:00
MistEO
d16b873ddf perf.针对飞桨OCR进行部分优化 2021-12-13 00:11:53 +08:00
MistEO
9f4b98dbac chore.切换OCR库为飞桨OCR 2021-12-12 23:44:54 +08:00
MistEO
cb7f848d5e chore.初步完成cmake,修改一些头文件路径 2021-12-11 22:10:19 +08:00
MistEO
3d3e37687e fix.修复选择干员时无限循环的问题 2021-12-11 13:09:29 +08:00
MistEO
d8829f869c fix.修复路径拼接错误 2021-12-11 11:22:58 +08:00
MistEO
0f7995f69a fix.修修bug,改改界面 2021-12-11 03:57:19 +08:00
MistEO
f6e69cc4ff fix.修复一些有的没的小bug 2021-12-11 03:22:02 +08:00
MistEO
767a667fbe fix.修复一些warning 2021-12-11 01:27:35 +08:00
MistEO
94f0eced1c fix.修复一个傻逼识别bug 2021-12-11 01:19:15 +08:00
MistEO
f000226a8d fix.修复一些小bug 2021-12-11 00:15:55 +08:00
MistEO
410d3c0885 Merge branch 'master' into dev 2021-12-10 16:39:25 +08:00
MistEO
3307838857 fix.再次修复心情不满干员还会去上班的问题 2021-12-10 16:18:21 +08:00
MistEO
54a2127e45 fix.修复会选择低体力干员的问题 2021-12-10 15:47:16 +08:00
MistEO
2ed1d7302f docs.更新README 2021-12-10 01:34:21 +08:00
MistEO
35e5dcf460 chore.更新版本号,更新README 2021-12-10 00:52:31 +08:00
MistEO
36529d9760 perf.开启一些任务的缓存 2021-12-10 00:42:00 +08:00
MistEO
2762ee9a28 refactor.重构缓存逻辑 2021-12-10 00:30:45 +08:00
MistEO
3dc491f762 fix.修复python接口的一些错误 2021-12-09 23:19:55 +08:00
MistEO
24e5f2eb61 refactor.资源路径该由外部传入,解耦文件路径获取 2021-12-09 22:48:16 +08:00
MistEO
c7a5b090eb docs.更新一些格式 2021-12-09 21:33:27 +08:00
MistEO
e636fb1a77 Merge branch 'master' into dev 2021-12-09 21:30:55 +08:00
MistEO
d57a57960b docs.更新Python接口注释 2021-12-09 00:06:49 +08:00
MistEO
42d92ef03d fix.修复某些分辨率下不吃理智药的问题 2021-12-08 22:24:16 +08:00
MistEO
d3490ac2b2 feat.新增Python接口,修改部分接口名 2021-12-08 01:10:49 +08:00
MistEO
4cdaaab27c fix.修复不吃理智药的问题 2021-12-07 20:40:04 +08:00
MistEO
75253107b6 fix.修复热更新资源错误的问题 2021-12-07 18:00:31 +08:00
MistEO
517a9e09ed feat.更新孤岛风云 复刻活动关卡数据 2021-12-07 17:07:02 +08:00
MistEO
5741bc17f1 Merge branch 'dev' 2021-12-07 00:24:24 +08:00
MistEO
09fc9a4622 chore.更新版本号v2.2.2 2021-12-07 00:17:23 +08:00
MistEO
8293343467 perf.优化下载相关功能 2021-12-07 00:16:57 +08:00
MistEO
dba4bf5dd4 fix.修复重新开始后缓存清不掉的问题 2021-12-06 22:21:18 +08:00
MistEO
ed1ec4c7f4 fix.修复一些有的没的小问题 2021-12-06 21:25:34 +08:00
MistEO
ef656e1c87 docs.fix typos 2021-12-06 19:18:39 +08:00
MistEO
f17bb4d814 docs.文档格式修改 2021-12-06 18:01:35 +08:00
MistEO
048dfd3f41 docs.更新标题级 2021-12-06 16:39:39 +08:00
MistEO
9efdc4d6f8 docs.更新README,更新版本号 2021-12-06 16:28:13 +08:00
MistEO
6ba9fc1f8d fix.简单修复设置界面导航栏定位错误问题 2021-12-06 00:30:29 +08:00
MistEO
b46cc97c71 Merge branch 'dev' 2021-12-06 00:01:43 +08:00
MistEO
6e04a670a6 Merge branch 'dev' 2021-11-25 22:37:48 +08:00
MistEO
dcd9e5b8dc Merge branch 'master' of https://github.com/MistEO/MeoAssistance-Arknights 2021-11-25 22:37:43 +08:00
MistEO
10c9fefe47 Merge branch 'Jie-Qiao-master' 2021-11-22 20:15:53 +08:00
204 changed files with 49631 additions and 47621 deletions

View File

@@ -0,0 +1,14 @@
---
name: 问题反馈Bug report
about: 识别错误、操作异常、连接错误等
title: ''
labels: bug
assignees: ''
---
请附上助手软件目录下的`asst.log`日志文件,是可以直接拖拽进来的。
最好再能说明下使用的模拟器、并附上出错时的游戏和软件的截图要是没截到就算啦_(:з」∠)_
Thanks♪(・ω・)ノ

View File

@@ -0,0 +1,10 @@
---
name: 需求建议Feature request
about: 新功能、建议等
title: ''
labels: enhancement
assignees: ''
---

10
.github/ISSUE_TEMPLATE/---others-.md vendored Normal file
View File

@@ -0,0 +1,10 @@
---
name: 其他Others)
about: 其他议题
title: ''
labels: ''
assignees: ''
---

2
.gitignore vendored
View File

@@ -2,6 +2,7 @@
*.d
# Compiled Object files
build
*.slo
*.lo
*.o
@@ -405,6 +406,7 @@ MigrationBackup/
FodyWeavers.xsd
# VS Code files for those working on multiple tools
**/.vscode/*
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json

Binary file not shown.

BIN
3rdparty/bin/libiomp5md.dll vendored Normal file

Binary file not shown.

BIN
3rdparty/bin/mkldnn.dll vendored Normal file

Binary file not shown.

BIN
3rdparty/bin/mklml.dll vendored Normal file

Binary file not shown.

BIN
3rdparty/bin/paddle_inference.dll vendored Normal file

Binary file not shown.

BIN
3rdparty/bin/ppocr.dll vendored Normal file

Binary file not shown.

View File

@@ -1,41 +0,0 @@
#ifndef __OCR_ANGLENET_H__
#define __OCR_ANGLENET_H__
#include "OcrStruct.h"
#include "onnxruntime_cxx_api.h"
#include <opencv2/opencv.hpp>
class AngleNet {
public:
AngleNet();
~AngleNet();
void setNumThread(int numOfThread);
void initModel(const std::string &pathStr);
std::vector<Angle> getAngles(std::vector<cv::Mat> &partImgs, const char *path,
const char *imgName, bool doAngle, bool mostAngle);
private:
bool isOutputAngleImg = false;
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "AngleNet");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
char *inputName;
char *outputName;
const float meanValues[3] = {127.5, 127.5, 127.5};
const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
const int dstWidth = 192;
const int dstHeight = 32;
Angle getAngle(cv::Mat &src);
};
#endif //__OCR_ANGLENET_H__

View File

@@ -1,43 +0,0 @@
#ifndef __OCR_CRNNNET_H__
#define __OCR_CRNNNET_H__
#include "OcrStruct.h"
#include "onnxruntime_cxx_api.h"
#include <opencv2/opencv.hpp>
class CrnnNet {
public:
CrnnNet();
~CrnnNet();
void setNumThread(int numOfThread);
void initModel(const std::string &pathStr, const std::string &keysPath);
std::vector<TextLine> getTextLines(std::vector<cv::Mat> &partImg, const char *path, const char *imgName);
private:
bool isOutputDebugImg = false;
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "CrnnNet");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
char *inputName;
char *outputName;
const float meanValues[3] = {127.5, 127.5, 127.5};
const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
const int dstHeight = 32;
std::vector<std::string> keys;
TextLine scoreToTextLine(const std::vector<float> &outputData, int h, int w);
TextLine getTextLine(const cv::Mat &src);
};
#endif //__OCR_CRNNNET_H__

View File

@@ -1,34 +0,0 @@
#ifndef __OCR_DBNET_H__
#define __OCR_DBNET_H__
#include "OcrStruct.h"
#include "onnxruntime_cxx_api.h"
#include <opencv2/opencv.hpp>
class DbNet {
public:
DbNet();
~DbNet();
void setNumThread(int numOfThread);
void initModel(const std::string &pathStr);
std::vector<TextBox> getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh,
float boxThresh, float unClipRatio);
private:
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "DbNet");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
char *inputName;
char *outputName;
const float meanValues[3] = {0.485 * 255, 0.456 * 255, 0.406 * 255};
const float normValues[3] = {1.0 / 0.229 / 255.0, 1.0 / 0.224 / 255.0, 1.0 / 0.225 / 255.0};
};
#endif //__OCR_DBNET_H__

View File

@@ -1,56 +0,0 @@
#ifndef __OCR_LITE_H__
#define __OCR_LITE_H__
#include "opencv2/core.hpp"
#include "onnxruntime_cxx_api.h"
#include "OcrStruct.h"
#include "DbNet.h"
#include "AngleNet.h"
#include "CrnnNet.h"
class OcrLite {
public:
OcrLite();
~OcrLite();
void setNumThread(int numOfThread);
void initLogger(bool isConsole, bool isPartImg, bool isResultImg);
void enableResultTxt(const char *path, const char *imgName);
void initModels(const std::string &detPath, const std::string &clsPath,
const std::string &recPath, const std::string &keysPath);
void Logger(const char *format, ...);
OcrResult detect(const char *path, const char *imgName,
int padding, int maxSideLen,
float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);
OcrResult detect(const cv::Mat& mat,
int padding, int maxSideLen,
float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);
private:
bool isOutputConsole = false;
bool isOutputPartImg = false;
bool isOutputResultTxt = false;
bool isOutputResultImg = false;
FILE *resultTxt;
DbNet dbNet;
AngleNet angleNet;
CrnnNet crnnNet;
std::vector<cv::Mat> getPartImages(cv::Mat &src, std::vector<TextBox> &textBoxes,
const char *path, const char *imgName);
OcrResult detect(const char *path, const char *imgName,
cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
float boxScoreThresh = 0.6f, float boxThresh = 0.3f,
float unClipRatio = 2.0f, bool doAngle = true, bool mostAngle = true);
};
#endif //__OCR_LITE_H__

View File

@@ -1,39 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include "OcrLitePort.h"
#include "OcrStruct.h"
namespace cv
{
class Mat;
}
class OcrLite;
class OCRLITE_PORT OcrLiteCaller
{
public:
OcrLiteCaller();
~OcrLiteCaller();
OcrLiteCaller(const OcrLite&) = delete;
OcrLiteCaller(OcrLite&&) = delete;
void setNumThread(int numOfThread);
bool initModels(const std::string& detPath, const std::string& clsPath,
const std::string& recPath, const std::string& keysPath);
OcrResult detect(const cv::Mat& mat,
int padding, int maxSideLen,
float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);
OcrResult detect(const std::string& dir, const std::string& file,
int padding, int maxSideLen,
float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle);
OcrLiteCaller& operator=(const OcrLiteCaller&) = delete;
OcrLiteCaller& operator=(OcrLiteCaller&&) = delete;
private:
std::unique_ptr<OcrLite> m_ocrlite_ptr;
};

View File

@@ -1,45 +0,0 @@
#pragma once
#if !defined(__JNI__) && !defined(__EXEC__)
// The way how the function is called
#if !defined(OCRLITE_CALL)
#if defined(_WIN32)
#define OCRLITE_CALL __stdcall
#else
#define OCRLITE_CALL
#endif /* _WIN32 */
#endif /* OCRLITE_CALL */
#if defined _WIN32 || defined __CYGWIN__
#define OCRLITE_EXPORT __declspec(dllexport)
#define OCRLITE_IMPORT __declspec(dllimport)
#define OCRLITE_LOCAL
#else // ! defined _WIN32 || defined __CYGWIN__
#if __GNUC__ >= 4
#define OCRLITE_EXPORT __attribute__ ((visibility ("default")))
#define OCRLITE_IMPORT __attribute__ ((visibility ("default")))
#define OCRLITE_LOCAL __attribute__ ((visibility ("hidden")))
#else // ! __GNUC__ >= 4
#define OCRLITE_EXPORT
#define OCRLITE_IMPORT
#endif // End __GNUC__ >= 4
#endif // End defined _WIN32 || defined __CYGWIN__
#ifdef __CLIB__
#define OCRLITE_PORT OCRLITE_EXPORT
#else
#define OCRLITE_PORT OCRLITE_IMPORT
#endif // OCRLITE_PORT
#define OCR_API OCRLITE_PORT OCRLITE_CALL
#define OCR_LOCAL OCRLITE_LOCAL OCRLITE_CALL
#else // __JNI__ || __EXEC__
#define OCRLITE_PORT
#define OCR_API
#define OCR_LOCAL
#endif // __JNI__ || __EXEC__

View File

@@ -1,35 +0,0 @@
#ifdef __JNI__
#ifndef __OCR_RESULT_UTILS_H__
#define __OCR_RESULT_UTILS_H__
#include <jni.h>
#include "OcrStruct.h"
class OcrResultUtils {
public:
OcrResultUtils(JNIEnv *env, OcrResult &ocrResult);
~OcrResultUtils();
jobject getJObject();
private:
JNIEnv *jniEnv;
jobject jOcrResult;
jclass newJListClass();
jmethodID getListConstructor(jclass clazz);
jobject getTextBlock(TextBlock &textBlock);
jobject getTextBlocks(std::vector<TextBlock> &textBlocks);
jobject newJPoint(cv::Point &point);
jobject newJBoxPoint(std::vector<cv::Point> &boxPoint);
jfloatArray newJScoreArray(std::vector<float> &scores);
};
#endif //__OCR_RESULT_UTILS_H__
#endif

View File

@@ -1,55 +0,0 @@
#ifndef __OCR_STRUCT_H__
#define __OCR_STRUCT_H__
#include "opencv2/core.hpp"
#include <vector>
#include "OcrLitePort.h"
struct ScaleParam {
int srcWidth;
int srcHeight;
int dstWidth;
int dstHeight;
float ratioWidth;
float ratioHeight;
};
struct TextBox {
std::vector<cv::Point> boxPoint;
float score;
};
struct Angle {
int index;
float score;
double time;
};
struct TextLine {
std::string text;
std::vector<float> charScores;
double time;
};
struct OCRLITE_PORT TextBlock {
std::vector<cv::Point> boxPoint;
float boxScore;
int angleIndex;
float angleScore;
double angleTime;
std::string text;
std::vector<float> charScores;
double crnnTime;
double blockTime;
};
struct OCRLITE_PORT OcrResult {
double dbNetTime;
std::vector<TextBlock> textBlocks;
cv::Mat boxImg;
double detectTime;
std::string strRes;
};
#endif //__OCR_STRUCT_H__

View File

@@ -1,103 +0,0 @@
#ifndef __OCR_UTILS_H__
#define __OCR_UTILS_H__
#include <opencv2/core.hpp>
#include "OcrStruct.h"
#include "onnxruntime_cxx_api.h"
#include <numeric>
#include <sys/stat.h>
template<typename T, typename... Ts>
static std::unique_ptr<T> makeUnique(Ts &&... params) {
return std::unique_ptr<T>(new T(std::forward<Ts>(params)...));
}
template<typename T>
static double getMean(std::vector<T> &input) {
auto sum = accumulate(input.begin(), input.end(), 0.0);
return sum / input.size();
}
template<typename T>
static double getStdev(std::vector<T> &input, double mean) {
if (input.size() <= 1) return 0;
double accum = 0.0;
for_each(input.begin(), input.end(), [&](const double d) {
accum += (d - mean) * (d - mean);
});
double stdev = sqrt(accum / (input.size() - 1));
return stdev;
}
double getCurrentTime();
inline bool isFileExists(const std::string &name) {
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
#ifdef _WIN32
#define my_strtol wcstol
#define my_strrchr wcsrchr
#define my_strcasecmp _wcsicmp
#define my_strdup _strdup
#else
#define my_strtol strtol
#define my_strrchr strrchr
#define my_strcasecmp strcasecmp
#define my_strdup strdup
#endif
std::wstring strToWstr(std::string str);
ScaleParam getScaleParam(cv::Mat &src, const float scale);
ScaleParam getScaleParam(cv::Mat &src, const int targetSize);
std::vector<cv::Point2f> getBox(const cv::RotatedRect &rect);
int getThickness(cv::Mat &boxImg);
void drawTextBox(cv::Mat &boxImg, cv::RotatedRect &rect, int thickness);
void drawTextBox(cv::Mat &boxImg, const std::vector<cv::Point> &box, int thickness);
void drawTextBoxes(cv::Mat &boxImg, std::vector<TextBox> &textBoxes, int thickness);
cv::Mat matRotateClockWise180(cv::Mat src);
cv::Mat matRotateClockWise90(cv::Mat src);
cv::Mat getRotateCropImage(const cv::Mat &src, std::vector<cv::Point> box);
cv::Mat adjustTargetImg(cv::Mat &src, int dstWidth, int dstHeight);
std::vector<cv::Point> getMinBoxes(const std::vector<cv::Point> &inVec, float &minSideLen, float &allEdgeSize);
float boxScoreFast(const cv::Mat &inMat, const std::vector<cv::Point> &inBox);
std::vector<cv::Point> unClip(const std::vector<cv::Point> &inBox, float perimeter, float unClipRatio);
std::vector<float> substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals);
std::vector<int> getAngleIndexes(std::vector<Angle> &angles);
std::vector<char *> getInputNames(Ort::Session *session);
std::vector<char *> getOutputNames(Ort::Session *session);
void getInputName(Ort::Session *session, char *&inputName);
void getOutputName(Ort::Session *session, char *&outputName);
void saveImg(cv::Mat &img, const char *imgPath);
std::string getSrcImgFilePath(const char *path, const char *imgName);
std::string getResultTxtFilePath(const char *path, const char *imgName);
std::string getResultImgFilePath(const char *path, const char *imgName);
std::string getDebugImgFilePath(const char *path, const char *imgName, int i, const char *tag);
#endif //__OCR_UTILS_H__

View File

@@ -1,406 +0,0 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.2 *
* Date : 27 February 2017 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2017 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.4.2"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines
//use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated
#include <vector>
#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
//By far the most widely used winding rules for polygon filling are
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
typedef int cInt;
static cInt const loRange = 0x7FFF;
static cInt const hiRange = 0x7FFF;
#else
typedef signed long long cInt;
static cInt const loRange = 0x3FFFFFFF;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
typedef signed long long long64; //used by Int128 class
typedef unsigned long long ulong64;
#endif
struct IntPoint {
cInt X;
cInt Y;
#ifdef use_xyz
cInt Z;
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
#else
IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
#endif
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
{
return a.X == b.X && a.Y == b.Y;
}
friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
{
return a.X != b.X || a.Y != b.Y;
}
};
//------------------------------------------------------------------------------
typedef std::vector< IntPoint > Path;
typedef std::vector< Path > Paths;
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
std::ostream& operator <<(std::ostream &s, const Path &p);
std::ostream& operator <<(std::ostream &s, const Paths &p);
struct DoublePoint
{
double X;
double Y;
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
};
//------------------------------------------------------------------------------
#ifdef use_xyz
typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
class PolyNode
{
public:
PolyNode();
virtual ~PolyNode(){};
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
PolyNode* GetNext() const;
bool IsHole() const;
bool IsOpen() const;
int ChildCount() const;
private:
//PolyNode& operator =(PolyNode& other);
unsigned Index; //node index in Parent.Childs
bool m_IsOpen;
JoinType m_jointype;
EndType m_endtype;
PolyNode* GetNextSiblingUp() const;
void AddChild(PolyNode& child);
friend class Clipper; //to access Index
friend class ClipperOffset;
};
class PolyTree: public PolyNode
{
public:
~PolyTree(){ Clear(); };
PolyNode* GetFirst() const;
void Clear();
int Total() const;
private:
//PolyTree& operator =(PolyTree& other);
PolyNodes AllNodes;
friend class Clipper; //to access AllNodes
};
bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
void CleanPolygon(Path& poly, double distance = 1.415);
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
void ReversePath(Path& p);
void ReversePaths(Paths& p);
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
//enums that are used internally ...
enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;
typedef std::vector < OutRec* > PolyOutList;
typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
//instantiated directly. This class simply abstracts the conversion of sets of
//polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase
{
public:
ClipperBase();
virtual ~ClipperBase();
virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
bool PreserveCollinear() {return m_PreserveCollinear;};
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
void InsertScanbeam(const cInt Y);
bool PopScanbeam(cInt &Y);
bool LocalMinimaPending();
bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
OutRec* CreateOutRec();
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
typedef std::vector<LocalMinimum> MinimaList;
MinimaList::iterator m_CurrentLM;
MinimaList m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
PolyOutList m_PolyOuts;
TEdge *m_ActiveEdges;
typedef std::priority_queue<cInt> ScanbeamList;
ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------
class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType fillType = pftEvenOdd);
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType subjFillType,
PolyFillType clipFillType);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType fillType = pftEvenOdd);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType subjFillType,
PolyFillType clipFillType);
bool ReverseSolution() { return m_ReverseOutput; };
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
virtual bool ExecuteInternal();
private:
JoinList m_Joins;
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
typedef std::list<cInt> MaximaList;
MaximaList m_Maxima;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
PolyFillType m_SubjFillType;
bool m_ReverseOutput;
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
bool PopEdgeFromSEL(TEdge *&edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
void DoMaxima(TEdge *e);
void ProcessHorizontals();
void ProcessHorizontal(TEdge *horzEdge);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
OutPt* GetLastOutPt(TEdge *e);
bool ProcessIntersections(const cInt topY);
void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
void BuildResult2(PolyTree& polytree);
void SetHoleState(TEdge *e, OutRec *outrec);
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
void FixupOutPolyline(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
void ClearJoins();
void ClearGhostJoins();
void AddGhostJoin(OutPt *op, const IntPoint offPt);
bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
};
//------------------------------------------------------------------------------
class ClipperOffset
{
public:
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
~ClipperOffset();
void AddPath(const Path& path, JoinType joinType, EndType endType);
void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
void Execute(Paths& solution, double delta);
void Execute(PolyTree& solution, double delta);
void Clear();
double MiterLimit;
double ArcTolerance;
private:
Paths m_destPolys;
Path m_srcPoly;
Path m_destPoly;
std::vector<DoublePoint> m_normals;
double m_delta, m_sinA, m_sin, m_cos;
double m_miterLim, m_StepsPerRad;
IntPoint m_lowest;
PolyNode m_polyNodes;
void FixOrientations();
void DoOffset(double delta);
void OffsetPoint(int j, int& k, JoinType jointype);
void DoSquare(int j, int k);
void DoMiter(int j, int k, double r);
void DoRound(int j, int k);
};
//------------------------------------------------------------------------------
class clipperException : public std::exception
{
public:
clipperException(const char* description): m_descr(description) {}
virtual ~clipperException() throw() {}
virtual const char* what() const throw() {return m_descr.c_str();}
private:
std::string m_descr;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp

View File

@@ -1,44 +0,0 @@
/*
* getopt - POSIX like getopt for Windows console Application
*
* win-c - Windows Console Library
* Copyright (c) 2015 Koji Takami
* Released under the MIT license
* https://github.com/takamin/win-c/blob/master/LICENSE
*/
#ifndef _GETOPT_H_
#define _GETOPT_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
int getopt(int argc, char *const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
/****************************************************************************
int getopt_long_only(int argc, char* const argv[],
const char* optstring,
const struct option* longopts, int* longindex);
****************************************************************************/
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GETOPT_H_

View File

@@ -1,54 +0,0 @@
#ifndef __MAIN_H__
#define __MAIN_H__
#include "getopt.h"
static const struct option long_options[] = {
{"models", required_argument, NULL, 'd'},
{"det", required_argument, NULL, '1'},
{"cls", required_argument, NULL, '2'},
{"rec", required_argument, NULL, '3'},
{"keys", required_argument, NULL, '4'},
{"image", required_argument, NULL, 'i'},
{"numThread", required_argument, NULL, 't'},
{"padding", required_argument, NULL, 'p'},
{"maxSideLen", required_argument, NULL, 's'},
{"boxScoreThresh", required_argument, NULL, 'b'},
{"boxThresh", required_argument, NULL, 'o'},
{"unClipRatio", required_argument, NULL, 'u'},
{"doAngle", required_argument, NULL, 'a'},
{"mostAngle", required_argument, NULL, 'A'},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{"loopCount", required_argument, NULL, 'l'},
{NULL, no_argument, NULL, 0}
};
const char *usageMsg = "(-d --models) (-1 --det) (-2 --cls) (-3 --rec) (-4 --keys) (-i --image)\n"\
"[-t --numThread] [-p --padding] [-s --maxSideLen]\n" \
"[-b --boxScoreThresh] [-o --boxThresh] [-u --unClipRatio]\n" \
"[-a --noAngle] [-A --mostAngle]\n\n";
const char *requiredMsg = "-d --models: models directory.\n" \
"-1 --det: model file name of det.\n" \
"-2 --cls: model file name of cls.\n" \
"-3 --rec: model file name of rec.\n" \
"-4 --keys: keys file name.\n" \
"-i --image: path of target image.\n\n";
const char *optionalMsg = "-t --numThread: value of numThread(int), default: 4\n" \
"-p --padding: value of padding(int), default: 50\n" \
"-s --maxSideLen: Long side of picture for resize(int), default: 1024\n" \
"-b --boxScoreThresh: value of boxScoreThresh(float), default: 0.6\n" \
"-o --boxThresh: value of boxThresh(float), default: 0.3\n" \
"-u --unClipRatio: value of unClipRatio(float), default: 2.0\n" \
"-a --doAngle: Enable(1)/Disable(0) Angle Net, default: Enable\n" \
"-A --mostAngle: Enable(1)/Disable(0) Most Possible AngleIndex, default: Enable\n\n";
const char *otherMsg = "-v --version: show version\n" \
"-h --help: print this help\n\n";
const char *example1Msg = "Example1: %s --models models --det det.onnx --cls cls.onnx --rec rec.onnx --keys keys.txt --image 1.jpg\n";
const char *example2Msg = "Example2: %s -d models -1 det.onnx -2 cls.onnx -3 rec.onnx -4 keys.txt -i 1.jpg -t 4 -p 50 -s 0 -b 0.6 -o 0.3 -u 2.0 -a 1 -A 1\n";
#endif //__MAIN_H__

View File

@@ -1,6 +0,0 @@
#ifndef __OCR_VERSION_H__
#define __OCR_VERSION_H__
#define VERSION "1.5.1.20210128"
#endif //__OCR_VERSION_H__

37
3rdparty/include/PaddleOCR/exports.h vendored Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
// The way how the function is called
#if !defined(OCR_CALL)
#if defined(_WIN32)
#define OCR_CALL __stdcall
#else
#define OCR_CALL
#endif /* _WIN32 */
#endif /* OCR_CALL */
// The function exported symbols
#if defined _WIN32 || defined __CYGWIN__
#define OCR_IMPORT __declspec(dllimport)
#define OCR_EXPORT __declspec(dllexport)
#define OCR_LOCAL
#else
#if __GNUC__ >= 4
#define OCR_IMPORT __attribute__ ((visibility ("default")))
#define OCR_EXPORT __attribute__ ((visibility ("default")))
#define OCR_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define OCR_IMPORT
#define OCR_EXPORT
#define OCR_LOCAL
#endif
#endif
#ifdef OCR_EXPORTS // defined if we are building the DLL (instead of using it)
#define OCRAPI_PORT OCR_EXPORT
#else
#define OCRAPI_PORT OCR_IMPORT
#endif // OCR_EXPORTS
#define OCRAPI OCRAPI_PORT OCR_CALL
#define OCRLOCAL OCR_LOCAL OCR_CALL

39
3rdparty/include/PaddleOCR/paddle_ocr.h vendored Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include "exports.h"
struct paddle_ocr_t;
typedef int OCR_ERROR;
typedef unsigned char uint8_t;
#define OCR_SUCCESS 0
#define OCR_FAILURE 1
#ifdef __cplusplus
extern "C" {
#endif
OCRAPI_PORT paddle_ocr_t* OCR_CALL PaddleOcrCreate(
const char* det_model_dir, const char* rec_model_dir,
const char* char_list_file, const char* cls_model_dir);
void OCRAPI PaddleOcrDestroy(paddle_ocr_t* ocr_ptr);
OCR_ERROR OCRAPI PaddleOcrDet(
paddle_ocr_t* ocr_ptr, const uint8_t* encode_buf, size_t encode_buf_size,
int* out_boxes, size_t* out_boxes_size,
double* out_times, size_t* out_times_size);
OCR_ERROR OCRAPI PaddleOcrRec(
paddle_ocr_t* ocr_ptr, const uint8_t* encode_buf, size_t encode_buf_size,
char** out_strs, float* out_scores, size_t* out_size,
double* out_times, size_t* out_times_size);
OCR_ERROR OCRAPI PaddleOcrSystem(
paddle_ocr_t* ocr_ptr, const uint8_t* encode_buf, size_t encode_buf_size, bool with_cls,
int* out_boxes, char** out_strs, float* out_scores, size_t* out_size,
double* out_times, size_t* out_times_size);
#ifdef __cplusplus
}
#endif

310
3rdparty/include/cpp-base64/base64.hpp vendored Normal file
View File

@@ -0,0 +1,310 @@
/*
base64.cpp and base64.h
base64 encoding and decoding with C++.
More information at
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
Version: 2.rc.08 (release candidate)
Copyright (C) 2004-2017, 2020, 2021 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#include <string>
#if __cplusplus >= 201703L
#include <string_view>
#endif // __cplusplus >= 201703L
std::string base64_encode (std::string const& s, bool url = false);
std::string base64_encode_pem (std::string const& s);
std::string base64_encode_mime(std::string const& s);
std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
std::string base64_encode(unsigned char const*, size_t len, bool url = false);
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode (std::string_view s, bool url = false);
std::string base64_encode_pem (std::string_view s);
std::string base64_encode_mime(std::string_view s);
std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
#endif // __cplusplus >= 201703L
#include <algorithm>
#include <stdexcept>
//
// Depending on the url parameter in base64_chars, one of
// two sets of base64 characters needs to be chosen.
// They differ in their last two characters.
//
static const char* base64_chars[2] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-_"};
static unsigned int pos_of_char(const unsigned char chr) {
//
// Return the position of chr within base64_encode()
//
if (chr >= 'A' && chr <= 'Z') return chr - 'A';
else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
else
//
// 2020-10-23: Throw std::exception rather than const char*
//(Pablo Martin-Gomez, https://github.com/Bouska)
//
throw std::runtime_error("Input is not valid base64-encoded data.");
}
static std::string insert_linebreaks(std::string str, size_t distance) {
//
// Provided by https://github.com/JomaCorpFX, adapted by me.
//
if (!str.length()) {
return "";
}
size_t pos = distance;
while (pos < str.size()) {
str.insert(pos, "\n");
pos += distance + 1;
}
return str;
}
template <typename String, unsigned int line_length>
static std::string encode_with_line_breaks(String s) {
return insert_linebreaks(base64_encode(s, false), line_length);
}
template <typename String>
static std::string encode_pem(String s) {
return encode_with_line_breaks<String, 64>(s);
}
template <typename String>
static std::string encode_mime(String s) {
return encode_with_line_breaks<String, 76>(s);
}
template <typename String>
static std::string encode(String s, bool url) {
return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
}
std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
size_t len_encoded = (in_len +2) / 3 * 4;
unsigned char trailing_char = url ? '.' : '=';
//
// Choose set of base64 characters. They differ
// for the last two positions, depending on the url
// parameter.
// A bool (as is the parameter url) is guaranteed
// to evaluate to either 0 or 1 in C++ therefore,
// the correct character set is chosen by subscripting
// base64_chars with url.
//
const char* base64_chars_ = base64_chars[url];
std::string ret;
ret.reserve(len_encoded);
unsigned int pos = 0;
while (pos < in_len) {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
if (pos+1 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
if (pos+2 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
ret.push_back(trailing_char);
}
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
ret.push_back(trailing_char);
ret.push_back(trailing_char);
}
pos += 3;
}
return ret;
}
template <typename String>
static std::string decode(String encoded_string, bool remove_linebreaks) {
//
// decode(…) is templated so that it can be used with String = const std::string&
// or std::string_view (requires at least C++17)
//
if (encoded_string.empty()) return std::string();
if (remove_linebreaks) {
std::string copy(encoded_string);
copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
return base64_decode(copy, false);
}
size_t length_of_string = encoded_string.length();
size_t pos = 0;
//
// The approximate length (bytes) of the decoded string might be one or
// two bytes smaller, depending on the amount of trailing equal signs
// in the encoded string. This approximation is needed to reserve
// enough space in the string to be returned.
//
size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
std::string ret;
ret.reserve(approx_length_of_decoded_string);
while (pos < length_of_string) {
//
// Iterate over encoded input string in chunks. The size of all
// chunks except the last one is 4 bytes.
//
// The last chunk might be padded with equal signs or dots
// in order to make it 4 bytes in size as well, but this
// is not required as per RFC 2045.
//
// All chunks except the last one produce three output bytes.
//
// The last chunk produces at least one and up to three bytes.
//
size_t pos_of_char_1 = pos_of_char(encoded_string[pos+1] );
//
// Emit the first output byte that is produced in each chunk:
//
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
encoded_string[pos+2] != '=' &&
encoded_string[pos+2] != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
)
{
//
// Emit a chunk's second byte (which might not be produced in the last chunk).
//
unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] );
ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
if ( ( pos + 3 < length_of_string ) &&
encoded_string[pos+3] != '=' &&
encoded_string[pos+3] != '.'
)
{
//
// Emit a chunk's third byte (which might not be produced in the last chunk).
//
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3]) ));
}
}
pos += 4;
}
return ret;
}
std::string base64_decode(std::string const& s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
std::string base64_encode(std::string const& s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem (std::string const& s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string const& s) {
return encode_mime(s);
}
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode(std::string_view s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem(std::string_view s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string_view s) {
return encode_mime(s);
}
std::string base64_decode(std::string_view s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
#endif // __cplusplus >= 201703L
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */

Binary file not shown.

BIN
3rdparty/lib/ppocr.lib vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
ch_ppocr_mobile_v2.0_det_prune_infer

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
ch_ppocr_mobile_v2.0_rec_slim_infer

File diff suppressed because it is too large Load Diff

24
CMakeLists.txt Normal file
View File

@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 2.8)
project(MeoAssistantArknights)
include_directories(include 3rdparty/include)
aux_source_directory(src/MeoAssistant SRC)
add_definitions(-DASST_DLL_EXPORTS)
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/MP>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/MP>")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
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)
target_link_libraries(MeoAssistant ${Opencv_LIB} ${PaddleOCR_LIB} ${Penguin_LIB} ${MeoJson_LIB})

View File

@@ -1,69 +1,71 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeoAssistance", "src\MeoAssistance\MeoAssistance.vcxproj", "{362D1E30-F5AE-4279-9985-65C27B3BA300}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{6C4B8D52-51D1-45F8-AAEC-808035443FD6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCaller", "tools\TestCaller\TestCaller.vcxproj", "{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeoAsstGui", "src\MeoAsstGui\MeoAsstGui.csproj", "{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TransparentImageCvt", "tools\TransparentImageCvt\TransparentImageCvt.vcxproj", "{093A3174-A27E-4D23-B64E-16F9448AD5AC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
Release|x86 = Release|x86
RelWithDebInfo|x64 = RelWithDebInfo|x64
RelWithDebInfo|x86 = RelWithDebInfo|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.ActiveCfg = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.Build.0 = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x86.ActiveCfg = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x64.ActiveCfg = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x64.Build.0 = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x86.ActiveCfg = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.Build.0 = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x86.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x86.Build.0 = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|Any CPU
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x64.ActiveCfg = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x64.Build.0 = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x86.ActiveCfg = Release|Win32
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x86.Build.0 = Release|Win32
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x64.Build.0 = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64} = {6C4B8D52-51D1-45F8-AAEC-808035443FD6}
{093A3174-A27E-4D23-B64E-16F9448AD5AC} = {6C4B8D52-51D1-45F8-AAEC-808035443FD6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4F2C0E4B-4FE9-47C6-A878-6BD2FAD8B9B2}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{6C4B8D52-51D1-45F8-AAEC-808035443FD6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestCaller", "tools\TestCaller\TestCaller.vcxproj", "{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeoAsstGui", "src\MeoAsstGui\MeoAsstGui.csproj", "{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TransparentImageCvt", "tools\TransparentImageCvt\TransparentImageCvt.vcxproj", "{093A3174-A27E-4D23-B64E-16F9448AD5AC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeoAssistant", "src\MeoAssistant\MeoAssistant.vcxproj", "{362D1E30-F5AE-4279-9985-65C27B3BA300}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
Release|x86 = Release|x86
RelWithDebInfo|x64 = RelWithDebInfo|x64
RelWithDebInfo|x86 = RelWithDebInfo|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x64.ActiveCfg = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x64.Build.0 = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.Release|x86.ActiveCfg = Release|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.Build.0 = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x86.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x86.Build.0 = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|Any CPU
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x64.ActiveCfg = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x64.Build.0 = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x86.ActiveCfg = Release|Win32
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.Release|x86.Build.0 = Release|Win32
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x64.ActiveCfg = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x64.Build.0 = Release|x64
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x86.ActiveCfg = Release|Win32
{093A3174-A27E-4D23-B64E-16F9448AD5AC}.RelWithDebInfo|x86.Build.0 = Release|Win32
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.ActiveCfg = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.Build.0 = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x86.ActiveCfg = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x86.Build.0 = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.RelWithDebInfo|x86.Build.0 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{63B4F1A2-291C-4C85-91E1-A1F6DAE30D64} = {6C4B8D52-51D1-45F8-AAEC-808035443FD6}
{093A3174-A27E-4D23-B64E-16F9448AD5AC} = {6C4B8D52-51D1-45F8-AAEC-808035443FD6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4F2C0E4B-4FE9-47C6-A878-6BD2FAD8B9B2}
EndGlobalSection
EndGlobal

216
README.md
View File

@@ -1,5 +1,8 @@
# MeoAssistance
<div align="center">
# MeoAssistantArknights
<br>
<div>
<img alt="C++" src="https://img.shields.io/badge/c++-17-%2300599C?logo=cplusplus">
<img alt="VS" src="https://img.shields.io/badge/VisualStudio-19-%235C2D91?logo=visualstudio">
@@ -8,18 +11,26 @@
<img alt="platform" src="https://img.shields.io/badge/platform-Windows%2064bit-%230078D6?logo=windows">
</div>
<div>
<img alt="license" src="https://img.shields.io/github/license/MistEO/MeoAssistance-Arknights">
<img alt="commit" src="https://img.shields.io/github/commit-activity/m/MistEO/MeoAssistance-Arknights?color=%23ff69b4">
<img alt="stars" src="https://img.shields.io/github/stars/MistEO/MeoAssistance-Arknights?style=social">
<img alt="license" src="https://img.shields.io/github/license/MistEO/MeoAssistantArknights">
<img alt="commit" src="https://img.shields.io/github/commit-activity/m/MistEO/MeoAssistantArknights?color=%23ff69b4">
<img alt="stars" src="https://img.shields.io/github/stars/MistEO/MeoAssistantArknights?style=social">
</div>
<br>
A game assistance for Arknights
A Game Assistant for Arknights
一款明日方舟的游戏助手,自动刷理智、智能基建换班、公招识别等,一键完成所有日常,全自动长草!!!
一款明日方舟的游戏助手,一键完成所有日常,全自动长草!!!
纯图像识别,非内存挂全图形化界面,兼容模拟器和安卓设备,开罐即食,绝赞开发中!✿✿ヽ(°▽°)ノ✿
<br>
纯图像识别,非内存挂全图形化界面,开罐即食!
并提供 [Python接口](src/Python/interface.py) 供自行DIY~ 绝赞更新中!✿✿ヽ(°▽°)ノ✿
</div>
## 功能介绍
废话不多说,看图!
![界面截图1](images/gui.png)
![界面截图2](images/settings1.png)
@@ -27,119 +38,85 @@ A game assistance for Arknights
## 下载地址
[稳定版](https://github.com/MistEO/MeoAssistance/releases/latest)
[测试版](https://github.com/MistEO/MeoAssistance/releases)
[稳定版](https://github.com/MistEO/MeoAssistantArknights/releases/latest)
[测试版](https://github.com/MistEO/MeoAssistantArknights/releases)
## 功能介绍
## 模拟器支持
- **全自动基建换班(新功能!)**
- 自动识别干员技能,自动计算设施内最优解并换班!
- 支持如`巫恋组``温蒂组`等等所有单设施内组合
- 自动识别干员心情并入驻宿舍
- 可设置自动使用无人机给制造站/贸易站加速
- 可识别赤金、经验书、搓玉,分别使用不同的干员组合
- `迷迭香`等跨设施体系正在开发中!
- 自动刷理智
- 支持刷完自动上传[企鹅物流数据统计](https://penguin-stats.cn/)
- 支持企鹅物流自定义ID
- 界面支持统计掉落数量
- 可设置是否吃完理智药及数量
- 可设置是否吃石头及数量
- 可设置刷的次数(用来刷剿灭啥的)
- 可设置刷完自动关机
- 支持剿灭模式
- 支持打完升级了的情况
- 支持代理失败的情况,会自动放弃本次行动
- 支持刷完自动截图
- 支持掉线后重连,继续刷上次的图
- 支持凌晨4点更新后重连继续刷上次的图
- 公开招募识别
- 自动识别当前招募页所有Tags
- 自动计算可能出的干员组合并显示
- 自动帮你点击最优解Tags
- 自动帮你点击时间9小时
- 出5、6星干员弹窗提示
- 最新版本已支持2.5新增的`阿`等干员
- 自动访问好友
- 访问完了还会贴心的帮你点进信用商店~
- 可设置访问完自动买信用商店的材料
- 其他优势
- 所有点击操作,都是点击按钮内随机位置,并模拟泊松分布(按钮偏中间位置点的概率大,越往旁边点到的概率越小)
- 刷理智及访问好友的点击操作,支持设置随机延时,没有封号风险~
- 底层算法纯C++开发并设计了多重的缓存技术最大限度降低CPU和内存占用
- 模拟器窗口可以被遮挡、可以最小化、甚至可以老板键隐藏!即使全屏看视频、玩游戏,也完全不影响软件运行
- 软件支持自动更新✿✿ヽ(°▽°)ノ✿
- 支持多款主流模拟器
- 兼容安卓手机USB调试、无线调试
- 兼容非16:9分辨率包括宽屏、方屏也兼容在游戏设置中的异形屏适配基建换班功能除外正在适配中。但仍推荐使用16:9分辨率
- 自适应分辨率及屏幕缩放
- 未来更多功能见[Todo](#Todo)
### 模拟器支持
#### 蓝叠模拟器
### 蓝叠模拟器
完美支持。需要在模拟器`设置`-`引擎设置`中打开`允许ADB连接`
#### 蓝叠模拟器国际版
### 蓝叠模拟器国际版
完美支持。需要在模拟器`设定`-`进阶`中打开`Android调试桥`
#### 蓝叠模拟器Hyper-V版本
支持。
1. 需要在模拟器`设定`-`进阶`中打开`Android调试桥`
2. 需要在软件`设置`-`连接设置`中添加蓝叠安装目录下`bluestacks.conf`文件的完整路径
#### 夜神模拟器
### 夜神模拟器
完美支持
#### MuMu模拟器
### MuMu模拟器
完美支持
#### 雷电模拟器
### 雷电模拟器
勉强支持雷电总有莫名其妙的问题,可以试试看,不保证能用(
勉强支持雷电总有莫名其妙的问题,可以试试看,不保证能用(
#### 逍遥模拟器
### 逍遥模拟器
支持
#### 腾讯手游助手
### 腾讯手游助手
不支持新版本的腾讯好像也是自研引擎了没开放ADB端口但是测试是能响应Win32 Api的有需求再做
不支持新版本的腾讯好像也是自研引擎了没开放ADB端口但是测试是能响应Win32 Api的有需求再做
#### MuMu手游助手星云引擎
### MuMu手游助手星云引擎
不支持星云引擎这个版本不支持adb控制甚至不响应Win32 Api鼠标消息无解_(:з」∠)_
不支持星云引擎这个版本不支持adb控制甚至不响应Win32 Api鼠标消息无解_(:з」∠)_
#### 其他模拟器
### Win11 WSA
若有其他需要,欢迎给我提[ISSUE](https://github.com/MistEO/MeoAssistance/issues),会根据情况尽量适配~
不支持WSA 目前没有实现 AOSP screencap 需要的接口,无法进行截图。等微软支持后会尝试适配
#### 安卓手机/平板
### 蓝叠模拟器Hyper-V版本
部分功能支持,正在开发中……
需要下载[谷歌官方ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip),将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
支持
1. 在模拟器`设定`-`进阶`中打开`Android调试桥`
2. 下载 [ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
3. 在软件`设置`-`连接设置`中填写蓝叠安装目录下`bluestacks.conf`文件的完整路径
### 自定义连接
- 下载 [ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip) ,将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
- 进入软件`设置`-`连接设置`填写自定义地址需要填写IP+端口,例如`127.0.0.1:5555`
- **注意 :** 若是使用手机,在非`16:9`分辨率下,部分功能不稳定(但也凑合能用),尤其是基建,几乎是不可用状态,正在进一步适配中。推荐使用`16:9`分辨率,经过的测试验证最多,也最稳定。
## 使用说明
### 基本说明
1. 根据上面模拟器支持情况,进行对应的`ADB`相关操作
1. 根据上面模拟器支持情况,进行对应的操作
2. 解压压缩包,到**没有中文或特殊符号**的文件夹路径
3. 第一次运行软件,**请使用管理员权限**打开`MeoAsstGui.exe`。运行过一次后,后续不再需要管理员权限(之后的版本会尝试完全去掉管理员权限)
3. 第一次运行软件,**请使用管理员权限**打开`MeoAsstGui.exe`。运行过一次后,后续不再需要管理员权限
4. 开始运行后,所有设置均不可再修改
5. 运行期间,模拟器窗口可以最小化,全屏玩游戏、看视频等,完全不影响
目前非16:9分辨率下刷理智、访问好友、公招识别已初步可用基建功能暂不可用后期将逐步优化。但仍推荐使用16:9分辨率经过的测试验证最多也最稳定。
### 刷理智
### Tips
若明日方舟处于**蓝色开始按钮**界面,则会刷当前关卡。否则会前往上一次作战的关卡!(自动选关功能正在开发中
- 若游戏处于**蓝色开始按钮**界面,则会刷当前关卡。否则会前往上次作战的关卡!
- 主界面上的`吃理智``吃石头``指定次数`三个选项为短路开关,即三个选项中的任一条件达到,均会视为任务完成,停止刷理智。
- 举例1设置`吃理智药`:`999``吃石头`:`10``指定次数`:`1`。则在刷完**一次**后,由于满足了`指定次数`:`1`的条件,视为任务完成,停止刷理智。
- 举例2不勾选`吃理智药`、不勾选`吃石头`,设置`指定次数`:`100`。则在当前可用理智全部刷完后(可能只刷了几次),由于满足了`不吃理智药``不吃石头`的条件,视为任务完成,停止刷理智。
- 其他优势
- 支持刷完自动上传 [企鹅物流数据统计](https://penguin-stats.cn/)
- 支持企鹅物流自定义ID
- 支持统计掉落数量
- 支持剿灭模式
- 支持打完升级了的情况
- 支持代理失败的情况,会自动放弃本次行动
- 支持掉线后重连,继续刷上次的图
- 支持凌晨4点更新后重连继续刷上次的图
### 基建换班
@@ -149,37 +126,54 @@ A game assistance for Arknights
#### 宿舍入驻心情阈值
计算心情进度条的百分比;心情小于该阈值的干员,不会再去上班,直接进驻宿舍
识别心情进度条的百分比;心情小于该阈值的干员,不会再去上班,直接进驻宿舍
#### 特殊说明
- 基建换班目前均为单设施最优解,但非跨设施的全局最优解例如`迷迭香`这类多个设施间联动的体系,都是不支持的
- 基建换班目前均为单设施最优解,但非跨设施的全局最优解例如`巫恋 龙舌兰``红云 稀音`等这类单设施内的组合,都是可以正常识别并使用的;`迷迭香``红松骑士团`这类多个设施间联动的体系,目前都是不支持的
- 会客室仅缺一个线索时,会选择对应流派的干员;否则会选择通用干员
- 会客室暂不支持送出线索,当线索满时可能会处理异常。建议自动换班完成后自己再去看下会客室的情况
- 控制中枢策略太过复杂,目前只考虑`阿米娅``诗怀雅``凯尔希``彩虹小队`及其他心情+0.05的干员,后续逐步优化
### 信用商店随缘买
从左到右依次买,但不会买`碳``家具零件`。有需要的同学可自行修改`resource\tasks.json``CreditShop-NotToBuy`.`text`字段,自定义不买的物品。后续版本会尝试开放界面选项
### 公开招募识别
**请注意:公招识别和自动公招是两个独立的功能!**
- 公招识别和自动公招是两个独立的功能!
- 公招识别需要手动打开有公招Tag选择的界面再使用
1. 明日方舟打开公开招募有Tag选择的界面
2. 软件勾选你需要的选项,点击"开始识别"
3. 请检查识别结果是否正确,自行判断是否确定开始招募
### 其他乱七八糟的说明
### 连接自定义模拟器端口,或安卓手机/平板
- 公招出5、6星会有弹窗提示
- 主界面上要执行的任务,是可以拖动改变顺序的。同样设置中基建换班的顺序,也是可以拖动改变的
- 活动关卡掉落识别到的`未知材料`,一般就是活动商店的票据
- 新的活动关卡刚上线的时候可能无法正常识别一般一两天内软件会自动OTA更新资源更新后即可正常识别
- 所有点击操作,都是点击按钮内随机位置,并模拟泊松分布(按钮偏中间位置点的概率大,越往旁边点到的概率越小)
- `resource\config.json`中有一些自定义选项,可以尝试根据自己的需要进行修改
- 底层算法纯C++开发并设计了多重的缓存技术最大限度降低CPU和内存占用
- 软件支持自动更新✿✿ヽ(°▽°)ノ✿ 推荐非杠精的同学使用测试版一般来说更新快且bug少什么MIUI (╯‵□′)╯︵┻━┻
1. 下载[ADB程序](https://dl.google.com/android/repository/platform-tools-latest-windows.zip),将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
2. 使用USB有线连接安卓手机和电脑
3. 请在手机`设置`-`开发者选项`中打开`USB调试``USB调试安全设置`两个选项。具体操作方式不同品牌手机各不相同,请自行百度查询
4. 请手动修改`resource\config.json`文件中:
1. `options`.`connectType`字段值为`1`
2. `emulator`.`Custom`.`adb`.`addresses`字段填写为要连接的地址,请注意这是个数组,会以此尝试所有的(若不填写,或`addresses`中所有的都没连上,则会使用`adb devices`自动查找)
## 常见问题
目前非16:9分辨率下刷理智、访问好友、公招识别已初步可用基建功能暂不可用后期将逐步优化。但仍推荐使用16:9分辨率经过的测试验证最多也最稳定。
### 软件一打开就闪退
- 目前初步怀疑是运行库问题。可以尝试把 [Visual C++ Redistributable](https://docs.microsoft.com/sl-SI/cpp/windows/latest-supported-vc-redist?view=msvc-160)、[.NET Framework 4.8](https://dotnet.microsoft.com/download/dotnet-framework/net48) 都安装一下看看有没有效果
- 若您有一定的开发能力,也可使用 [Python接口](src/Python/interface.py) 自行调用
### 连接错误/捕获模拟器窗口错误
- 方法1: 使用 [自定义连接](#自定义连接) 的方式连接模拟器
- 方法2: 换模拟器,推荐 [蓝叠国际版](https://www.bluestacks.com/download.html)
- 方法3: _根本解决方法_ 编辑`resource/config.json`修改最好是新增模拟器窗口句柄名并修改对应的adb设置。若您修改后可以提PR给我我会感激不尽的_(:з」∠)_
###
## Todo
- [x] 任务队列功能
- [ ] 常用关卡选关
- [x] 常用关卡选关
- [x] 自动收任务功能
- [x] 基建智能换班功能
- [x] 图形化界面
@@ -196,7 +190,7 @@ A game assistance for Arknights
- [x] `激进换班模式`
- [ ] 自定义换班(手动修改配置文件)
- [ ] 宿舍换班支持加速心情的干员识别
- [ ] 贸易站无人机支持设置给经验书还是赤金
- [x] 贸易站无人机支持设置给经验书还是赤金
- [ ] 使用GPU进行识别的版本
- [x] 企鹅物流汇报自定义ID
- [ ] 指定刷某种材料xx个
@@ -206,7 +200,7 @@ A game assistance for Arknights
- [x] 后台自动更新
- [x] 忽略当前版本更新
- [ ] 提供log接口以及界面log
- [ ] 更换OCR库提高公开招募识别率
- [x] 更换OCR库提高公开招募识别率
- [x] 终极目标!全自动长草机!!!
## 致谢
@@ -214,13 +208,16 @@ A game assistance for Arknights
### 开源库
- 图像识别库:[opencv](https://github.com/opencv/opencv.git)
- 文字识别库:[chineseocr_lite](https://github.com/DayBreak-u/chineseocr_lite.git)
- ~~文字识别库:[chineseocr_lite](https://github.com/DayBreak-u/chineseocr_lite.git)~~
- 文字识别库:[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR)
- 关卡掉落识别:[企鹅物流识别](https://github.com/KumoSiunaus/penguin-stats-recognize-v3)
- C++ JSON库[meojson](https://github.com/MistEO/meojson.git)
- C++ 运算符解析器:[calculator](https://github.com/kimwalisch/calculator)
- C++ base64编解码[cpp-base64](https://github.com/ReneNyffenegger/cpp-base64)
- WPF MVVW框架[Stylet](https://github.com/canton7/Stylet)
- WPF控件库[HandyControl](https://github.com/HandyOrg/HandyControl)
- C# JSON库: [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json)
- 下载器:[aria2](https://github.com/aria2/aria2)
### 数据源
@@ -233,13 +230,16 @@ A game assistance for Arknights
- 非常感谢 [tcyh035](https://github.com/tcyh035) 帮忙设计重构图形界面
- 非常感谢 [GengGode](https://github.com/GengGode) 和 [DbgDebug](https://github.com/DbgDebug) 提供图像算法思路并协助验证
- 非常感谢 [LoveLoliii](https://github.com/LoveLoliii) 提供公开招募算法及数据、部分功能逻辑思路
- 感谢[AAH](https://github.com/ninthDevilHAUNSTER/ArknightsAutoHelper)的大佬们协助提供部分图像、操作思路
- 感谢 [内卷地狱](https://jq.qq.com/?_wv=1027&k=ypbzXcA2) 的大佬们提供的各种协助支持
- 感谢 [LmeSzinc](https://github.com/LmeSzinc) 提供的界面样式参考,~~虽然我抄了个四不像orz~~
- 感谢参与软件测试、提bug的小伙伴们~
- ~~感谢[B站直播间](https://live.bilibili.com/2808861)的小伙伴们陪我弹幕吹水~~
- ~~感谢 [B站直播间](https://live.bilibili.com/2808861) 的小伙伴们陪我弹幕吹水~~
## 广告
[B站直播间](https://live.bilibili.com/2808861):每晚直播敲代码,近期很长一段时间应该都是在写本助手软件
[QQ群](https://jq.qq.com/?_wv=1027&k=ypbzXcA2):欢迎加入~
[QQ群:内卷地狱](https://jq.qq.com/?_wv=1027&k=ypbzXcA2):欢迎加入~
作者前端苦手寻大佬帮忙一起写界面继续现在的WPF也行用electron或者别的重写也行球球了QAQ
如果觉得软件对你有帮助帮忙点个Star吧~(网页最上方右上角的小星星),这就是对我最大的支持了!
PS作者前端苦手现在的界面WPF基本是现学现卖的写得很烂希望有大佬能帮忙提点PR修改修改感激不尽_(:з」∠)_

View File

@@ -7,7 +7,7 @@ clone_depth: 1
before_build:
- ps: nuget restore
build:
project: MeoAssistance.sln
project: MeoAssistantArknights.sln
parallel: true
verbosity: minimal
notifications:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -2,37 +2,42 @@
#include "AsstPort.h"
namespace asst {
class Assistant;
}
#ifdef __cplusplus
extern "C" {
#endif
typedef void (MEO_CALL* AsstCallback)(int msg, const char* detail_json, void* custom_arg);
typedef void (ASST_CALL* AsstCallback)(int msg, const char* detail_json, void* custom_arg);
MEOAPI_PORT void* MEO_CALL AsstCreate();
MEOAPI_PORT void* MEO_CALL AsstCreateEx(AsstCallback callback, void* custom_arg);
void MEOAPI AsstDestory(void* p_asst);
ASSTAPI_PORT asst::Assistant* ASST_CALL AsstCreate(const char* dirname);
ASSTAPI_PORT asst::Assistant* ASST_CALL AsstCreateEx(const char* dirname, AsstCallback callback, void* custom_arg);
void ASSTAPI AsstDestroy(asst::Assistant* p_asst);
bool MEOAPI AsstCatchDefault(void* p_asst);
bool MEOAPI AsstCatchEmulator(void* p_asst);
bool MEOAPI AsstCatchCustom(void* p_asst, const char* address);
bool MEOAPI AsstCatchFake(void* p_asst);
bool ASSTAPI AsstCatchDefault(asst::Assistant* p_asst);
bool ASSTAPI AsstCatchEmulator(asst::Assistant* p_asst);
bool ASSTAPI AsstCatchCustom(asst::Assistant* p_asst, const char* address);
bool ASSTAPI AsstCatchFake(asst::Assistant* p_asst);
bool MEOAPI AsstAppendFight(void* p_asst, int max_mecidine, int max_stone, int max_times);
bool MEOAPI AsstAppendAward(void* p_asst);
bool MEOAPI AsstAppendVisit(void* p_asst);
bool MEOAPI AsstAppendMall(void* p_asst, bool with_shopping);
//bool MEOAPI AsstAppendProcessTask(void* p_asst, const char* task);
bool MEOAPI AsstAppendInfrast(void* p_asst, int work_mode, const char** order, int order_size, const char* uses_of_drones, double dorm_threshold);
bool MEOAPI AsstAppendRecruit(void* p_asst, int max_times, const int required_level[], int required_len, const int confirm_level[], int confirm_len, bool need_refresh);
bool MEOAPI AsstAppendDebug(void* p_asst);
bool ASSTAPI AsstAppendStartUp(asst::Assistant* p_asst);
bool ASSTAPI AsstAppendFight(asst::Assistant* p_asst, const char* stage, int max_mecidine, int max_stone, int max_times);
bool ASSTAPI AsstAppendAward(asst::Assistant* p_asst);
bool ASSTAPI AsstAppendVisit(asst::Assistant* p_asst);
bool ASSTAPI AsstAppendMall(asst::Assistant* p_asst, bool with_shopping);
//bool ASSTAPI AsstAppendProcessTask(asst::Assistant* p_asst, const char* task);
bool ASSTAPI AsstAppendInfrast(asst::Assistant* p_asst, int work_mode, const char** order, int order_size, const char* uses_of_drones, double dorm_threshold);
bool ASSTAPI 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);
bool ASSTAPI AsstAppendDebug(asst::Assistant* p_asst);
bool MEOAPI AsstStartRecruitCalc(void* p_asst, const int required_level[], int required_len, bool set_time);
bool MEOAPI AsstStart(void* p_asst);
bool MEOAPI AsstStop(void* p_asst);
bool ASSTAPI AsstStartRecruitCalc(asst::Assistant* p_asst, const int select_level[], int required_len, bool set_time);
bool ASSTAPI AsstStart(asst::Assistant* p_asst);
bool ASSTAPI AsstStop(asst::Assistant* p_asst);
bool MEOAPI AsstSetPenguinId(void* p_asst, const char* id);
//bool MEOAPI AsstSetParam(void* p_asst, const char* type, const char* param, const char* value);
bool ASSTAPI AsstSetPenguinId(asst::Assistant* p_asst, const char* id);
//bool ASSTAPI AsstSetParam(asst::Assistant* p_asst, const char* type, const char* param, const char* value);
MEOAPI_PORT const char* MEO_CALL AsstGetVersion();
ASSTAPI_PORT const char* ASST_CALL AsstGetVersion();
#ifdef __cplusplus
}
#endif

View File

@@ -1,37 +1,37 @@
#pragma once
// The way how the function is called
#if !defined(MEO_CALL)
#if !defined(ASST_CALL)
#if defined(_WIN32)
#define MEO_CALL __stdcall
#define ASST_CALL __stdcall
#else
#define MEO_CALL
#define ASST_CALL
#endif /* _WIN32 */
#endif /* MEO_CALL */
#endif /* ASST_CALL */
// The function exported symbols
#if defined _WIN32 || defined __CYGWIN__
#define MEO_DLL_IMPORT __declspec(dllimport)
#define MEO_DLL_EXPORT __declspec(dllexport)
#define MEO_DLL_LOCAL
#define ASST_DLL_IMPORT __declspec(dllimport)
#define ASST_DLL_EXPORT __declspec(dllexport)
#define ASST_DLL_LOCAL
#else
#if __GNUC__ >= 4
#define MEO_DLL_IMPORT __attribute__ ((visibility ("default")))
#define MEO_DLL_EXPORT __attribute__ ((visibility ("default")))
#define MEO_DLL_LOCAL __attribute__ ((visibility ("hidden")))
#define ASST_DLL_IMPORT __attribute__ ((visibility ("default")))
#define ASST_DLL_EXPORT __attribute__ ((visibility ("default")))
#define ASST_DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define MEO_DLL_IMPORT
#define MEO_DLL_EXPORT
#define MEO_DLL_LOCAL
#define ASST_DLL_IMPORT
#define ASST_DLL_EXPORT
#define ASST_DLL_LOCAL
#endif
#endif
#ifdef MEO_DLL_EXPORTS // defined if we are building the DLL (instead of using it)
#define MEOAPI_PORT MEO_DLL_EXPORT
#ifdef ASST_DLL_EXPORTS // defined if we are building the DLL (instead of using it)
#define ASSTAPI_PORT ASST_DLL_EXPORT
#else
#define MEOAPI_PORT MEO_DLL_IMPORT
#endif // MEO_DLL_EXPORTS
#define ASSTAPI_PORT ASST_DLL_IMPORT
#endif // ASST_DLL_EXPORTS
#define MEOAPI MEOAPI_PORT MEO_CALL
#define ASSTAPI ASSTAPI_PORT ASST_CALL
#define MEOLOCAL MEO_DLL_LOCAL MEO_CALL
#define ASSTLOCAL ASST_DLL_LOCAL ASST_CALL

View File

@@ -5,23 +5,21 @@
"connectType_Doc": "连接类型0-连接电脑上的模拟器1-连接自定义端口,请手动修改'emulator.Custom'中的相关字段。默认0",
"taskDelay": 2000,
"taskDelay_Doc": "识别的延迟越快识别频率越快但会增加CPU消耗。单位毫秒默认2000",
"printWindow": false,
"printWindow_Doc": "截图功能开启后每次结算界面会截图到screenshot目录下。true-开启false-关闭默认false",
"penguinReport": true,
"penguinReport_Doc": "企鹅数据汇报:每次到结算界面,是否汇报掉落数据至企鹅数据 https://penguin-stats.cn/。true-开启false-关闭默认true",
"penguinReportCmdLine": "curl -H \"Content-Type: application/json\" -d \"[body]\" \"https://penguin-stats.cn/PenguinStats/api/v2/report\" [extra]",
"penguinReportCmdLine_Doc": "企鹅数据汇报的命令,想打印详细信息可以尝试添加 -v -i",
"controlDelayRange": [
0,
0
],
"controlDelayRange_Doc": "点击随机延时:每次点击操作会进行随机延时,降低封号风险(好像也没听说过谁被封号的)。格式为 [ 最小延时, 最大延时 ]单位为毫秒。例如想设置3~5秒延时即修改为[ 3000, 5000 ]默认0~0",
"ocrThreadNumber": 4,
"ocrThreadNumber_Doc": "文字识别库OcrLite的线程数量理论上开的高点识别会快点但是会更卡。默认4",
"adbExtraSwipeDist": 50,
"adbExtraSwipeDist_Doc": "额外的滑动距离adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来",
"adbExtraSwipeDuration": 1000,
"adbExtraSwipeDuration_Doc": "额外的滑动持续时间adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来。若小于0则关闭额外滑动功能"
"adbExtraSwipeDuration_Doc": "额外的滑动持续时间adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来。若小于0则关闭额外滑动功能",
"penguinReport": {
"Doc": "企鹅数据汇报:每次到结算界面,汇报掉落数据至企鹅数据 https://penguin-stats.cn/。true-开启false-关闭默认true",
"enable": true,
"cmdFormat": "curl -H \"Content-Type: application/json\" -d \"[body]\" \"https://penguin-stats.cn/PenguinStats/api/v2/report\" [extra]",
"cmdFormat_Doc": "命令格式,想打印详细信息可以尝试添加 -v -i"
}
},
"emulator_Doc": "下面的和模拟器窗口捕获逻辑有关,不需要修改",
"emulator": {
@@ -40,7 +38,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayFormat": "cur=%dx%d",
"screencap": "[Adb] -s [Address] exec-out screencap -p"
"screencap": "[Adb] -s [Address] exec-out screencap -p",
"release": "[Adb] kill-server"
}
},
"BlueStacksInternational": {
@@ -58,7 +57,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayFormat": "cur=%dx%d",
"screencap": "[Adb] -s [Address] exec-out screencap -p"
"screencap": "[Adb] -s [Address] exec-out screencap -p",
"release": "[Adb] kill-server"
}
},
"MuMuEmulator": {
@@ -76,7 +76,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayFormat": "cur=%dx%d",
"screencap": "[Adb] -s [Address] exec-out screencap -p"
"screencap": "[Adb] -s [Address] exec-out screencap -p",
"release": "[Adb] kill-server"
}
},
"LDPlayer": {
@@ -94,7 +95,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayFormat": "cur=%dx%d",
"screencap": "[Adb] -s [Address] shell screencap -p"
"screencap": "[Adb] -s [Address] shell screencap -p",
"release": "[Adb] kill-server"
}
},
"Nox": {
@@ -112,7 +114,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayFormat": "cur=%dx%d",
"screencap": "[Adb] -s [Address] exec-out screencap -p"
"screencap": "[Adb] -s [Address] exec-out screencap -p",
"release": "[Adb] kill-server"
}
},
"XYAZ": {
@@ -130,7 +133,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init=",
"displayFormat": " init=%dx%d",
"screencap": "[Adb] -s [Address] shell screencap -p"
"screencap": "[Adb] -s [Address] shell screencap -p",
"release": "[Adb] kill-server"
}
},
"Custom": {
@@ -150,7 +154,8 @@
"swipe": "[Adb] -s [Address] shell input swipe [x1] [y1] [x2] [y2] [duration]",
"display": "[Adb] -s [Address] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayFormat": "cur=%dx%d",
"screencap": "[Adb] -s [Address] exec-out screencap -p"
"screencap": "[Adb] -s [Address] exec-out screencap -p",
"release": "[Adb] kill-server"
}
}
}

View File

@@ -482,6 +482,15 @@
"all": 30
}
},
{
"desc": "火神-1",
"skills": [
"Bskill_man_spd&limit&cost1"
],
"efficient": {
"all": 27
}
},
{
"desc": "米格鲁、卡缇",
"skills": [

View File

@@ -1,10 +1,168 @@
{
"SanityBegin": {
"StartUp": {
"algorithm": "justreturn",
"action": "doNothing",
"next": [
"GameStart",
"StartToWakeUp",
"Terminal",
"CloseAnno",
"TodaysSupplies",
"ReturnToTerminal",
"OfflineConfirm"
]
},
"LS-5": {
"algorithm": "justreturn",
"action": "doNothing",
"next": [
"StageResourceToLS5",
"StageLS",
"StageLS5"
]
},
"StageResourceToLS5": {
"template": "StageResource.png",
"roi": [
790,
640,
60,
60
],
"action": "clickSelf",
"next": [
"SwipeToStageLS"
]
},
"SwipeToStageLS": {
"algorithm": "justReturn",
"action": "swipeToTheLeft",
"next": [
"StageLS"
]
},
"StageLS": {
"action": "clickSelf",
"next": [
"StageLS5"
]
},
"StageLS5": {
"action": "clickSelf",
"roi": [
850,
140,
250,
80
]
},
"AP-5": {
"algorithm": "justreturn",
"action": "doNothing",
"next": [
"StageResourceToAP5",
"StageAP",
"StageAP5"
]
},
"StageResourceToAP5": {
"template": "StageResource.png",
"roi": [
790,
640,
60,
60
],
"action": "clickSelf",
"next": [
"SwipeToStageAP"
]
},
"SwipeToStageAP": {
"algorithm": "justReturn",
"action": "swipeToTheLeft",
"next": [
"StageAP"
]
},
"StageAP": {
"action": "clickSelf",
"next": [
"StageAP5"
]
},
"StageAP5": {
"action": "clickSelf",
"roi": [
850,
140,
250,
80
]
},
"CE-5": {
"algorithm": "justreturn",
"action": "doNothing",
"next": [
"StageResourceToCE5",
"StageCE",
"StageCE5"
]
},
"StageResourceToCE5": {
"template": "StageResource.png",
"roi": [
790,
640,
60,
60
],
"action": "clickSelf",
"next": [
"SwipeToStageCE"
]
},
"SwipeToStageCE": {
"algorithm": "justReturn",
"action": "swipeToTheLeft",
"next": [
"StageCE"
]
},
"StageCE": {
"action": "clickSelf",
"next": [
"StageCE5"
]
},
"StageCE5": {
"action": "clickSelf",
"roi": [
850,
140,
250,
80
]
},
"Annihilation": {
"doc": "剿灭作战一般本周的满了也不会有人再刷的所以只识别右上角ToDoList里的剿灭就可以了",
"template": "StageAnnihilation.png",
"action": "clickSelf",
"roi": [
900,
70,
380,
400
],
"maskRange": [
1,
255
]
},
"StageBegin": {
"algorithm": "justreturn",
"action": "doNothing",
"next": [
"UsePrts",
"StartButton1",
"ReturnToTerminal",
"PRTS",
"EndOfAction",
@@ -16,6 +174,15 @@
"GameStart"
]
},
"FightBegin": {
"algorithm": "justreturn",
"action": "doNothing",
"next": [
"UsePrts",
"StartButton1",
"LastBattle"
]
},
"GameStart": {
"action": "clickSelf",
"roi": [
@@ -24,7 +191,6 @@
200,
120
],
"cache": false,
"rearDelay": 5000,
"maskRange": [
1,
@@ -113,14 +279,14 @@
"PRTS": {
"algorithm": "OcrDetect",
"text": [
"剩余可放置角色",
"接管作战"
"剩余可放置角色"
],
"roi": [
0,
530,
1280,
190
900,
500,
380,
150
],
"action": "doNothing",
"rearDelay": 5000,
@@ -200,10 +366,11 @@
},
"UseMedicine": {
"action": "doNothing",
"templThreshold": 0.7,
"roi": [
580,
50,
700,
400,
100
],
"next": [
@@ -212,7 +379,6 @@
},
"MedicineConfirm": {
"action": "clickSelf",
"cache": false,
"maxTimes": 0,
"roi": [
1000,
@@ -245,7 +411,6 @@
"StoneConfirm": {
"template": "MedicineConfirm.png",
"action": "clickSelf",
"cache": false,
"maxTimes": 0,
"roi": [
1000,
@@ -277,7 +442,6 @@
]
},
"PrtsErrorConfirm": {
"cache": false,
"roi": [
0,
120,
@@ -292,7 +456,6 @@
},
"AbandonAction": {
"action": "clickSelf",
"cache": false,
"reduceOtherTimes": [
"StartButton1",
"StartButton2"
@@ -312,7 +475,6 @@
"OfflineConfirmAfterBattle": {
"template": "PopupConfirm.png",
"action": "clickSelf",
"cache": false,
"roi": [
630,
400,
@@ -328,7 +490,6 @@
},
"OfflineConfirm": {
"action": "clickSelf",
"cache": false,
"roi": [
0,
400,
@@ -387,7 +548,8 @@
"LastBattle",
"Terminal",
"CloseAnno",
"TodaysSupplies"
"TodaysSupplies",
"Stop"
]
},
"TodaysSupplies": {
@@ -416,8 +578,8 @@
"LastBattle": {
"algorithm": "OcrDetect",
"text": [
"上一次作战",
"前往上一次"
"前往",
"作战"
],
"roi": [
900,
@@ -427,6 +589,7 @@
],
"action": "clickSelf",
"next": [
"UsePrts",
"StartButton1"
]
},
@@ -473,7 +636,6 @@
},
"Recruit": {
"action": "clickSelf",
"cache": false,
"roi": [
900,
450,
@@ -507,7 +669,6 @@
},
"RecruitSkip": {
"action": "clickSelf",
"cache": false,
"rearDelay": 3000,
"roi": [
1100,
@@ -538,7 +699,6 @@
"StartRecruit": {
"algorithm": "OcrDetect",
"action": "clickSelf",
"cache": false,
"rearDelay": 1000,
"text": [
"开始招"
@@ -591,7 +751,6 @@
]
},
"ReceiveAward": {
"cache": false,
"action": "clickSelf",
"roi": [
950,
@@ -793,7 +952,6 @@
},
"VisitNext": {
"action": "clickSelf",
"cache": false,
"rearDelay": 2000,
"roi": [
1080,
@@ -879,6 +1037,7 @@
640,
360
],
"rearDelay": 1000,
"next": [
"CreditStoreOcr",
"Mall"
@@ -1008,7 +1167,6 @@
},
"HomeFlag": {
"template": "Terminal.png",
"cache": false,
"action": "stop",
"roi": [
880,
@@ -1019,7 +1177,6 @@
},
"CreditShop-Commoditys": {
"template": "CreditPoint.png",
"cache": false,
"rectMove": [
-60,
-180,
@@ -1028,7 +1185,6 @@
]
},
"CreditShop-SoldOut": {
"cache": false,
"template": "SoldOut.png"
},
"CreditShop-BuyIt": {
@@ -1039,7 +1195,6 @@
250,
150
],
"cache": false,
"preDelay": 1000,
"rearDelay": 1000
},
@@ -1077,7 +1232,6 @@
"RecruitTime": {
"template": "RecruitTimeReduce.png",
"templThreshold": 0.89,
"cache": false,
"action": "clickSelf",
"roi": [
350,
@@ -1096,53 +1250,24 @@
"algorithm": "OcrDetect",
"text": [],
"roi": [
200,
200,
800,
500
375,
360,
480,
120
],
"ocrReplace": [
[
"沮击",
"狙击"
"千员",
"干员"
],
[
"犯击",
"狙击"
],
[
"泪击",
"狙击"
],
[
"都出",
"输出"
],
[
"都乐",
"输出"
],
[
"抓出",
"输出"
],
[
"都任",
"输出"
],
[
"新于",
"新手"
],
[
"防拍",
"防护"
".+击干员",
"狙击干员"
]
]
},
"RecruitRefresh": {
"action": "clickSelf",
"cache": false,
"roi": [
850,
340,
@@ -1155,7 +1280,6 @@
},
"RecruitNoRefresh": {
"action": "doNothing",
"cache": false,
"roi": [
850,
340,
@@ -1166,18 +1290,38 @@
"RecruitRefreshConfirm": {
"template": "PopupConfirm.png",
"action": "clickSelf",
"cache": false,
"rearDelay": 3000,
"roi": [
630,
400,
650,
160
],
"next": [
"RecruitLoading",
"Stop"
]
},
"RecruitLoading": {
"algorithm": "OcrDetect",
"action": "doNothing",
"text": [
"正在提交",
"反馈至神经"
],
"roi": [
700,
600,
300,
120
],
"next": [
"RecruitLoading",
"Stop"
]
},
"RecruitConfirm": {
"action": "clickSelf",
"cache": false,
"roi": [
860,
540,
@@ -1247,7 +1391,6 @@
},
"EnterInfrast": {
"rearDelay": 3000,
"cache": false,
"roi": [
900,
540,
@@ -1325,7 +1468,6 @@
},
"DroneAssistMfg": {
"action": "clickSelf",
"cache": false,
"roi": [
1180,
500,
@@ -1341,7 +1483,6 @@
},
"DroneAssistTrade": {
"action": "clickSelf",
"cache": false,
"roi": [
250,
430,
@@ -1381,13 +1522,12 @@
]
},
"DeliverableOrder": {
"cache": false,
"action": "clickSelf",
"roi": [
250,
130,
300,
230,
420
250
],
"next": [
"DeliverableOrder",
@@ -1398,8 +1538,7 @@
"DroneAssist-Trade-Stop": {
"Doc": "如果找到了“无人机加速”按钮却没有找到订单交付说明上一次无人机没有把一个订单加速完成也说明没有更多的无人机了所以直接stop",
"template": "DroneAssistTrade.png",
"action": "stop",
"cache": false
"action": "stop"
},
"InfrastSkillsUpper": {
"algorithm": "justReturn",
@@ -1449,7 +1588,6 @@
100,
255
],
"cache": false,
"templThreshold": 0.8
},
"InfrastSmileyOnWork": {
@@ -1458,7 +1596,6 @@
100,
255
],
"cache": false,
"templThreshold": 0.8
},
"InfrastSmileyOnDistract": {
@@ -1467,15 +1604,13 @@
100,
255
],
"cache": false,
"templThreshold": 0.8
},
"InfrastSkills": {
"template": "empty.png",
"templThreshold": 0.9,
"histThreshold": 95,
"histThreshold_Doc": "该任务里的Hist阈值是特化了拿来做灰度图平均值的懒得重新写个字段了",
"cache": false,
"specialThreshold": 95,
"specialThreshold_Doc": "用于做灰度图平均值",
"rectMove_Doc": "基于笑脸的位置移动",
"rectMove": [
-8,
@@ -1538,9 +1673,8 @@
"InfrastOperMoodProgressBar": {
"template": "empty.png",
"templThreshold": 160,
"histThreshold": 20,
"Doc": "这里的templThreshold作为进度条最小灰度阈值使用histThreshold作为进度条相邻点最大变化阈值使用。懒得重新弄个字段了",
"cache": false,
"specialThreshold": 20,
"Doc": "这里的templThreshold作为进度条最小灰度阈值使用specialThreshold作为进度条相邻点最大变化阈值使用。懒得重新弄个字段了",
"rectMove_Doc": "基于笑脸的位置移动",
"rectMove": [
21,
@@ -1551,7 +1685,6 @@
},
"InfrastMfg": {
"template": "Manufacturing.png",
"cache": false,
"templThreshold": 0.9,
"maskRange": [
1,
@@ -1567,7 +1700,6 @@
"InfrastMfgMini": {
"template": "ManufacturingMini.png",
"templThreshold": 0.9,
"cache": false,
"roi": [
0,
240,
@@ -1582,7 +1714,6 @@
"InfrastTrade": {
"template": "Trade.png",
"templThreshold": 0.9,
"cache": false,
"maskRange": [
1,
255
@@ -1597,7 +1728,6 @@
"InfrastTradeMini": {
"template": "TradeMini.png",
"templThreshold": 0.9,
"cache": false,
"roi": [
0,
240,
@@ -1611,7 +1741,6 @@
},
"InfrastPower": {
"template": "Power.png",
"cache": false,
"maskRange": [
1,
255
@@ -1626,7 +1755,6 @@
},
"InfrastPowerMini": {
"template": "PowerMini.png",
"cache": false,
"roi": [
0,
240,
@@ -1641,7 +1769,6 @@
},
"InfrastDorm": {
"template": "Dorm.png",
"cache": false,
"maskRange": [
1,
255
@@ -1656,7 +1783,6 @@
},
"InfrastDormMini": {
"template": "DormMini.png",
"cache": false,
"maskRange": [
1,
255
@@ -1671,7 +1797,6 @@
},
"InfrastOffice": {
"template": "Office.png",
"cache": false,
"maskRange": [
1,
255
@@ -1686,7 +1811,6 @@
},
"InfrastOfficeMini": {
"template": "OfficeMini.png",
"cache": false,
"maskRange": [
1,
255
@@ -1701,7 +1825,6 @@
},
"InfrastReception": {
"template": "Reception.png",
"cache": false,
"maskRange": [
1,
255
@@ -1716,7 +1839,6 @@
},
"InfrastReceptionMini": {
"template": "ReceptionMini.png",
"cache": false,
"maskRange": [
1,
255
@@ -1731,7 +1853,6 @@
},
"InfrastControl": {
"template": "ControlCenter.png",
"cache": false,
"maskRange": [
1,
255
@@ -1746,7 +1867,6 @@
},
"InfrastControlMini": {
"template": "ControlCenterMini.png",
"cache": false,
"maskRange": [
1,
255
@@ -1761,7 +1881,6 @@
},
"InfrastStationedInfo": {
"algorithm": "OcrDetect",
"cache": false,
"text": [
"进驻信息"
],
@@ -1775,7 +1894,6 @@
},
"InfrastEnterOperList": {
"algorithm": "OcrDetect",
"cache": false,
"text": [
"心情",
"休息中",
@@ -1812,7 +1930,6 @@
"rearDelay": 500,
"Doc": "这个任务复用了,上半部分用来检测确认按钮点击成功没;下部部分用来点击",
"algorithm": "ocrDetect",
"cache": false,
"text": [
"正在提交",
"反馈至神经"
@@ -1852,7 +1969,6 @@
},
"InfrastFacilityListTabMfg": {
"template": "FacilityListTabMfg.png",
"cache": false,
"roi": [
0,
0,
@@ -1867,7 +1983,6 @@
},
"InfrastFacilityListTabTrade": {
"template": "FacilityListTabTrade.png",
"cache": false,
"roi": [
0,
0,
@@ -1882,7 +1997,6 @@
},
"InfrastOperLockedMfg": {
"template": "OperLockedMfg.png",
"cache": false,
"roi": [
200,
500,
@@ -1892,7 +2006,6 @@
},
"InfrastOperLockedTrade": {
"template": "OperLockedTrade.png",
"cache": false,
"roi": [
200,
500,
@@ -1902,7 +2015,6 @@
},
"InfrastFlagCombatRecord": {
"template": "InfrastMfgDogFoodFlag.png",
"cache": false,
"roi": [
1000,
0,
@@ -1912,7 +2024,6 @@
},
"InfrastFlagPureGold": {
"template": "InfrastMfgPureGoldFlag.png",
"cache": false,
"roi": [
1000,
0,
@@ -1922,7 +2033,6 @@
},
"InfrastFlagOriginStone": {
"template": "InfrastMfgOriginStoneFlag.png",
"cache": false,
"roi": [
1000,
0,
@@ -1932,7 +2042,6 @@
},
"InfrastFlagChip": {
"template": "InfrastMfgChipFlag.png",
"cache": false,
"roi": [
1000,
0,
@@ -1942,7 +2051,6 @@
},
"InfrastFlagMoney": {
"template": "InfrastTradeMoneyFlag.png",
"cache": false,
"roi": [
900,
500,
@@ -1952,7 +2060,6 @@
},
"InfrastFlagSyntheticJade": {
"template": "InfrastTradeSyntheticJadeFlag.png",
"cache": false,
"roi": [
900,
500,
@@ -1963,7 +2070,6 @@
"InfrastAddOperatorMfgGentle": {
"template": "AddOperatorMfgGentle.png",
"templThreshold": 0.8,
"cache": false,
"roi": [
200,
500,
@@ -1975,7 +2081,6 @@
"InfrastAddOperatorMfgAggressive": {
"template": "AddOperatorMfgAggressive.png",
"templThreshold": 0.8,
"cache": false,
"roi": [
200,
500,
@@ -1993,7 +2098,6 @@
"InfrastAddOperatorTradeGentle": {
"template": "AddOperatorTradeGentle.png",
"templThreshold": 0.8,
"cache": false,
"roi": [
200,
500,
@@ -2005,7 +2109,6 @@
"InfrastAddOperatorTradeAggressive": {
"template": "AddOperatorTradeAggressive.png",
"templThreshold": 0.8,
"cache": false,
"roi": [
200,
500,
@@ -2023,7 +2126,6 @@
"InfrastAddOperatorReceptionGentle": {
"template": "AddOperatorReceptionGentle.png",
"templThreshold": 0.8,
"cache": false,
"roi": [
0,
0,
@@ -2045,7 +2147,6 @@
},
"InfrastOperSelected": {
"template": "empty.png",
"cache": false,
"templThreshold": 8000,
"templThreshold_Doc": "这个任务中作为符合range的像素点数量阈值",
"maskRange": [
@@ -2061,7 +2162,6 @@
},
"InfrastOperOnShift": {
"template": "OnShift.png",
"cache": false,
"templThreshold": 0.8,
"rectMove": [
0,
@@ -2156,7 +2256,6 @@
},
"InfrastClue": {
"template": "Clue.png",
"cache": false,
"maskRange": [
1,
255

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -1 +0,0 @@
#include "AbstractResource.h"

View File

@@ -1,252 +0,0 @@
#include "AsstCaller.h"
#include <string.h>
#include <json_value.h>
#include "Assistance.h"
#include "AsstDef.h"
#include "AsstUtils.hpp"
#include "Version.h"
#if 0
#if _MSC_VER
// Win32平台下Dll的入口
BOOL APIENTRY DllMain(HANDLE 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);
}
void* AsstCreate()
{
try {
return new asst::Assistance();
}
catch (...) {
return nullptr;
}
}
void* AsstCreateEx(AsstCallback callback, void* custom_arg)
{
try {
// 创建多实例回调会有问题,有空再慢慢整
_callback = callback;
return new asst::Assistance(CallbackTrans, custom_arg);
}
catch (...) {
return nullptr;
}
}
void AsstDestory(void* p_asst)
{
if (p_asst == nullptr) {
return;
}
delete p_asst;
p_asst = nullptr;
}
bool AsstCatchDefault(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->catch_default();
}
bool AsstCatchEmulator(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->catch_emulator();
}
bool AsstCatchCustom(void* p_asst, const char* address)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->catch_custom(address);
}
bool AsstCatchFake(void* p_asst)
{
#ifdef LOG_TRACE
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->catch_fake();
#else
return false;
#endif // LOG_TRACE
}
bool AsstAppendFight(void* p_asst, int max_mecidine, int max_stone, int max_times)
{
if (p_asst == nullptr) {
return false;
}
asst::Assistance* ptr = (asst::Assistance*)p_asst;
return ptr->append_fight(max_mecidine, max_stone, max_times);
}
bool AsstAppendAward(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->append_award();
}
bool AsstAppendVisit(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->append_visit();
}
bool AsstAppendMall(void* p_asst, bool with_shopping)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->append_mall(with_shopping);
}
//bool AsstAppendProcessTask(void* p_asst, const char* task)
//{
// if (p_asst == nullptr) {
// return false;
// }
//
// return ((asst::Assistance*)p_asst)->append_process_task(task);
//}
bool AsstStartRecruitCalc(void* p_asst, const int required_level[], int required_len, bool set_time)
{
if (p_asst == nullptr) {
return false;
}
std::vector<int> level_vector;
level_vector.assign(required_level, required_level + required_len);
return ((asst::Assistance*)p_asst)->start_recruit_calc(level_vector, set_time);
}
bool AsstAppendInfrast(void* 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 ((asst::Assistance*)p_asst)->
append_infrast(
static_cast<asst::infrast::WorkMode>(work_mode),
order_vector,
uses_of_drones,
dorm_threshold);
}
bool AsstAppendRecruit(void* p_asst, int max_times, const int required_level[], int required_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(required_level, required_level + required_len);
std::vector<int> confirm_vector;
confirm_vector.assign(confirm_level, confirm_level + confirm_len);
return ((asst::Assistance*)p_asst)->append_recruit(max_times, required_vector, confirm_vector, need_refresh);
}
bool AsstStart(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->start();
}
bool AsstStop(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
return ((asst::Assistance*)p_asst)->stop();
}
bool MEOAPI AsstSetPenguinId(void* p_asst, const char* id)
{
if (p_asst == nullptr) {
return false;
}
auto ptr = (asst::Assistance*)p_asst;
ptr->set_penguin_id(id);
return true;
}
//bool AsstSetParam(void* p_asst, const char* type, const char* param, const char* value)
//{
// if (p_asst == nullptr) {
// return false;
// }
//
// return ((asst::Assistance*)p_asst)->set_param(type, param, value);
//}
const char* AsstGetVersion()
{
return asst::Version;
}
bool AsstAppendDebug(void* p_asst)
{
if (p_asst == nullptr) {
return false;
}
#if LOG_TRACE
return ((asst::Assistance*)p_asst)->append_debug();
#else
return false;
#endif // LOG_TRACE
}

View File

@@ -1,109 +0,0 @@
#include "MatchImageAnalyzer.h"
#include "AsstUtils.hpp"
#include "Logger.hpp"
#include "Resource.h"
asst::MatchImageAnalyzer::MatchImageAnalyzer(const cv::Mat& image, const Rect& roi, std::string templ_name, double templ_thres, double hist_thres)
: AbstractImageAnalyzer(image, roi),
m_templ_name(std::move(templ_name)),
m_templ_thres(templ_thres),
m_hist_thres(hist_thres)
{
;
}
bool asst::MatchImageAnalyzer::analyze()
{
if (m_use_cache) {
auto&& [hist, roi] = resource.templ().get_hist(m_templ_name);
if (!hist.empty()) {
return comp_hist(hist, roi);
}
}
const cv::Mat& templ = resource.templ().get_templ(m_templ_name);
if (templ.empty()) {
log.error("templ is empty!");
return false;
}
if (match_templ(templ)) {
if (m_use_cache) {
resource.templ().emplace_hist(m_templ_name, to_hist(templ), utils::make_rect<cv::Rect>(m_result.rect));
}
return true;
}
return false;
}
cv::Mat asst::MatchImageAnalyzer::to_hist(const cv::Mat& src)
{
constexpr int histSize[] = { 50, 60 };
constexpr float h_ranges[] = { 0, 180 };
constexpr float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
constexpr int channels[] = { 0, 1 };
cv::MatND hist;
cv::calcHist(&src, 1, channels, cv::Mat(), hist, 2, histSize, ranges);
cv::normalize(hist, hist, 0, 1, cv::NORM_MINMAX);
return hist;
}
bool asst::MatchImageAnalyzer::match_templ(const cv::Mat& templ)
{
cv::Mat matched;
cv::Mat image_roi = m_image(utils::make_rect<cv::Rect>(m_roi));
if (templ.cols > image_roi.cols || templ.rows > image_roi.rows) {
log.error("templ size is too large", m_templ_name,
"image_roi size:", image_roi.cols, image_roi.rows,
"templ size:", templ.cols, templ.rows);
return false;
}
if (m_mask_range.first == m_mask_range.second) {
cv::matchTemplate(image_roi, templ, matched, cv::TM_CCOEFF_NORMED);
}
else {
cv::Mat mask;
cv::cvtColor(templ, mask, cv::COLOR_BGR2GRAY);
cv::inRange(mask, m_mask_range.first, m_mask_range.second, mask);
cv::matchTemplate(image_roi, templ, matched, cv::TM_CCOEFF_NORMED, mask);
}
double min_val = 0.0, max_val = 0.0;
cv::Point min_loc, max_loc;
cv::minMaxLoc(matched, &min_val, &max_val, &min_loc, &max_loc);
Rect rect(max_loc.x + m_roi.x, max_loc.y + m_roi.y, templ.cols, templ.rows);
if (max_val > m_templ_thres * 0.7) { // 得分太低的肯定不对,没必要打印
log.trace("match_templ |", m_templ_name, "score:", max_val, "rect:", rect.to_string());
}
if (max_val >= m_templ_thres) {
m_result = { AlgorithmType::MatchTemplate, max_val, rect };
return true;
}
else {
return false;
}
}
bool asst::MatchImageAnalyzer::comp_hist(const cv::Mat& hist, const cv::Rect roi)
{
cv::Mat image_roi = m_image(utils::make_rect<cv::Rect>(roi));
double score = 1.0 - cv::compareHist(to_hist(image_roi), hist, cv::HISTCMP_BHATTACHARYYA);
if (score > 0.7) { // 得分太低的肯定不对,没必要打印
log.trace("comp_hist |", m_templ_name, "score:", score);
}
if (score >= m_hist_thres) {
Rect rect(roi.x, roi.y, hist.cols, hist.rows);
m_result = { AlgorithmType::CompareHist, score, rect };
return true;
}
else {
return false;
}
}

View File

@@ -1,86 +0,0 @@
#include "OcrPack.h"
#include <OcrLiteOnnx/OcrLiteCaller.h>
#include <opencv2/opencv.hpp>
#include "AsstUtils.hpp"
#include "Logger.hpp"
asst::OcrPack::OcrPack()
: m_ocr_ptr(std::make_unique<OcrLiteCaller>())
{}
asst::OcrPack::~OcrPack() = default;
bool asst::OcrPack::load(const std::string & dir)
{
constexpr static const char* DetName = "\\models\\dbnet.onnx";
constexpr static const char* ClsName = "\\models\\angle_net.onnx";
constexpr static const char* RecName = "\\models\\crnn_lite_lstm.onnx";
constexpr static const char* KeysName = "\\models\\keys.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;
return m_ocr_ptr->initModels(dst_filename, cls_filename, rec_filename, keys_filename);
}
void asst::OcrPack::set_param(int /*gpu_index*/, int thread_number)
{
// gpu_index是ncnn的参数onnx架构的没有预留参数接口
m_ocr_ptr->setNumThread(thread_number);
}
std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat & image, const asst::TextRectProc & pred)
{
constexpr int padding = 50;
constexpr int maxSideLen = 0;
constexpr float boxScoreThresh = 0.2f;
constexpr float boxThresh = 0.3f;
constexpr float unClipRatio = 2.0f;
constexpr bool doAngle = false;
constexpr bool mostAngle = false;
OcrResult ocr_results = m_ocr_ptr->detect(image,
padding, maxSideLen,
boxScoreThresh, boxThresh,
unClipRatio, doAngle, mostAngle);
std::vector<TextRect> result;
std::string log_str_raw;
std::string log_str_proc;
for (TextBlock& text_block : ocr_results.textBlocks) {
if (text_block.boxPoint.size() != 4) {
continue;
}
// the rect like ↓
// 0 - 1
// 3 - 2
int x = text_block.boxPoint.at(0).x;
int y = text_block.boxPoint.at(0).y;
int width = text_block.boxPoint.at(1).x - x;
int height = text_block.boxPoint.at(3).y - y;
TextRect tr{ std::move(text_block.text), Rect(x, y, width, height) };
log_str_raw += (std::string)tr + ", ";
if (!pred || pred(tr)) {
log_str_proc += tr.to_string() + ", ";
result.emplace_back(std::move(tr));
}
}
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)
{
auto rect_cor = [&roi, &pred](TextRect& tr) -> bool {
tr.rect.x += roi.x;
tr.rect.y += roi.y;
return pred(tr);
};
return recognize(image(utils::make_rect<cv::Rect>(roi)), rect_cor);
}

View File

@@ -1,99 +0,0 @@
#include "PenguinUploader.h"
#include <Windows.h>
#include <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 = resource.cfg().get_options();
body["server"] = opt.penguin_report_server;
body["stageId"] = rec["stage"]["stageId"];
// To fix: https://github.com/MistEO/MeoAssistance-Arknights/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"] = "MeoAssistance";
body["version"] = Version;
return body.to_string();
}
bool asst::PenguinUploader::request_penguin(const std::string& body)
{
auto& opt = resource.cfg().get_options();
std::string body_escape = utils::string_replace_all(body, "\"", "\\\"");
std::string cmd_line = utils::string_replace_all(opt.penguin_report_cmd_line, "[body]", body_escape);
cmd_line = utils::string_replace_all(cmd_line, "[extra]", opt.penguin_report_extra_param);
log.trace("request_penguin |", cmd_line);
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>(cmd_line.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
if (p_ret) {
std::string pipe_str;
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);
log.trace("curl say:", pipe_str);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
::CloseHandle(pipe_read);
::CloseHandle(pipe_child_write);
return true;
}

View File

@@ -1,146 +0,0 @@
#include "ProcessTaskImageAnalyzer.h"
#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);
m_match_analyzer->correct_roi();
if (m_match_analyzer->analyze()) {
m_result = match_task_ptr;
m_result_rect = m_match_analyzer->get_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& [old_str, new_str] : ocr_task_ptr->replace_map) {
temp.text = utils::string_replace_all(temp.text, old_str, 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;
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_required(ocr_task_ptr->text);
m_ocr_analyzer->set_replace(ocr_task_ptr->replace_map);
// 识别区域文字,并加入缓存
auto analyze_roi = [&](const Rect& roi, bool is_appeared = false) -> bool {
m_ocr_analyzer->set_roi(roi);
m_ocr_analyzer->correct_roi();
bool ret = m_ocr_analyzer->analyze();
const auto& ocr_result = m_ocr_analyzer->get_result();
m_ocr_cache.insert(m_ocr_cache.end(), ocr_result.begin(), ocr_result.end());
if (ret) {
auto& res = ocr_result.front();
m_result = ocr_task_ptr;
m_result_rect = res.rect;
if (!is_appeared) {
ocr_task_ptr->region_of_appeared.emplace(res.rect);
}
log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found", res.to_string(), "roi :", roi.to_string());
return true;
}
return false;
};
// 在曾经识别到过的历史区域里识别
for (const Rect& region : ocr_task_ptr->region_of_appeared) {
static auto& max_width = WindowWidthDefault;
static auto& max_height = WindowHeightDefault;
bool ret = analyze_roi(region.center_zoom(2.0, max_width, max_height), true);
if (ret) {
log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found in appeared");
return true;
}
}
// 都没有的话再完整的识别整个ROI
return analyze_roi(ocr_task_ptr->roi);
}
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,6 +0,0 @@
#pragma once
namespace asst
{
constexpr static const char* Version = "v2.2";
}

View File

@@ -1,6 +1,6 @@
#include "AbstractConfiger.h"
#include <json.h>
#include <meojson/json.h>
#include "AsstUtils.hpp"

View File

@@ -43,7 +43,7 @@ void asst::AbstractImageAnalyzer::set_roi(const Rect& roi) noexcept
void asst::AbstractImageAnalyzer::correct_roi() noexcept
{
m_roi = ctrler.shaped_correct(m_roi);
m_roi = Ctrler.shaped_correct(m_roi);
}
asst::Rect asst::AbstractImageAnalyzer::empty_rect_to_full(const Rect& rect, const cv::Mat& image) noexcept

View File

@@ -0,0 +1 @@
#include "AbstractResource.h"

View File

@@ -29,7 +29,7 @@ bool asst::AbstractTask::run()
if (need_exit()) {
return false;
}
int delay = resource.cfg().get_options().task_delay;
int delay = Resrc.cfg().get_options().task_delay;
sleep(delay);
if (!on_run_fails()) {
@@ -47,7 +47,7 @@ bool AbstractTask::sleep(unsigned millisecond)
if (millisecond == 0) {
return true;
}
auto start = std::chrono::system_clock::now();
auto start = std::chrono::steady_clock::now();
long long duration = 0;
json::value callback_json;
@@ -56,7 +56,7 @@ bool AbstractTask::sleep(unsigned millisecond)
while (!need_exit() && duration < millisecond) {
duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now() - start)
std::chrono::steady_clock::now() - start)
.count();
std::this_thread::yield();
}
@@ -94,6 +94,6 @@ void asst::AbstractTask::click_return_button()
Rect ReturnButtonRect = return_task_ptr->specific_rect;
ctrler.click(ReturnButtonRect);
Ctrler.click(ReturnButtonRect);
sleep(return_task_ptr->rear_delay);
}

View File

@@ -25,7 +25,7 @@ namespace asst
void set_retry_times(int times) noexcept { m_retry_times = times; }
void set_task_chain(std::string name) noexcept { m_task_chain = std::move(name); }
const std::string& get_task_chain() const noexcept { return m_task_chain; }
constexpr static int RetryTimesDefault = 20;
protected:
virtual bool _run() = 0;

145
src/MeoAssistant/AipOcr.cpp Normal file
View File

@@ -0,0 +1,145 @@
#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;
}

43
src/MeoAssistant/AipOcr.h Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include <iostream>
#include "AsstDef.h"
namespace cv
{
class Mat;
}
namespace json
{
class value;
}
namespace asst
{
class AipOcr
{
public:
~AipOcr() = default;
static AipOcr& get_instance()
{
static AipOcr unique_instance;
return unique_instance;
}
bool request_access_token(const std::string& client_id, const std::string& client_secret);
bool request_ocr_general(const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred = nullptr);
bool request_ocr_accurate(const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred = nullptr);
private:
AipOcr() = default;
AipOcr(const AipOcr&) = default;
AipOcr(AipOcr&&) noexcept = default;
bool request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, std::vector<TextRect>& out_result, const TextRectProc& pred = nullptr);
bool parse_response(const json::value& json, std::vector<TextRect>& out_result, const TextRectProc& pred = nullptr);
std::string m_access_token;
};
}

View File

@@ -23,11 +23,11 @@ namespace asst
class Controller;
class Identify;
class Assistance
class Assistant
{
public:
Assistance(AsstCallback callback = nullptr, void* callback_arg = nullptr);
~Assistance();
Assistant(std::string dirname, AsstCallback callback = nullptr, void* callback_arg = nullptr);
~Assistant();
// 根据配置文件决定捕获模拟器、USB 还是远程设备
bool catch_default();
@@ -38,8 +38,10 @@ namespace asst
// 不实际进行捕获,调试用接口
bool catch_fake();
// 添加开始游戏的任务(进入到主界面)
bool append_start_up(bool only_append = true);
// 添加刷理智任务
bool append_fight(int mecidine = 0, int stone = 0, int times = INT_MAX, 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);
// 添加访问好友任务
@@ -52,9 +54,9 @@ namespace asst
// 添加自动公招任务
// 参数max_times: 最多进行几次公招
// 参数required_level: 需要的选择Tags的等级
// 参数select_level: 需要的选择Tags的等级
// 参数confirm_level: 需要点击确认按钮的等级
bool append_recruit(unsigned max_times, const std::vector<int>& required_level, const std::vector<int>& confirm_level, bool need_refresh);
bool append_recruit(unsigned max_times, const std::vector<int>& select_level, const std::vector<int>& confirm_level, bool need_refresh);
#ifdef LOG_TRACE
// 调试用
@@ -62,7 +64,7 @@ namespace asst
#endif
// 开始公开招募计算
bool start_recruit_calc(const std::vector<int>& required_level, bool set_time);
bool start_recruit_calc(const std::vector<int>& select_level, bool set_time);
// 开始执行任务队列
bool start(bool block = true);
@@ -76,6 +78,7 @@ namespace asst
static constexpr int ProcessTaskRetryTimesDefault = 20;
static constexpr int OpenRecruitTaskRetryTimesDefault = 10;
static constexpr int AutoRecruitTaskRetryTimesDefault = 5;
private:
void working_proc();
@@ -88,6 +91,7 @@ namespace asst
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;

View File

@@ -0,0 +1,259 @@
#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
}

View File

@@ -20,7 +20,6 @@ namespace asst
constexpr static int WindowHeightDefault = 720;
constexpr static double TemplThresholdDefault = 0.8;
constexpr static double HistThresholdDefault = 0.8;
struct Point
{
@@ -46,6 +45,10 @@ namespace asst
{
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);
@@ -98,7 +101,7 @@ namespace asst
explicit operator Rect() const noexcept { return rect; }
std::string to_string() const
{
return text + " : " + rect.to_string();
return text + " : " + rect.to_string() + ", score: " + std::to_string(score);
}
TextRect& operator=(const TextRect&) = default;
TextRect& operator=(TextRect&&) noexcept = default;
@@ -109,6 +112,7 @@ namespace asst
std::string text;
Rect rect;
float score;
};
using TextRectProc = std::function<bool(TextRect&)>;
@@ -196,6 +200,8 @@ namespace asst
int retry_times = INT_MAX; // 未找到图像时的重试次数
Rect roi; // 要识别的区域若为0则全图识别
Rect rect_move; // 识别结果移动有些结果识别到的和要点击的不是同一个位置。即识别到了res点击res + result_move的位置
bool cache = false; // 是否使用缓存区域
Rect region_of_appeared; // 缓存区域上次识别成功过本次只在这个rect里识别省点性能
};
// 文字识别任务的信息
@@ -206,8 +212,6 @@ namespace asst
bool need_full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
std::unordered_map<std::string, std::string>
replace_map; // 部分文字容易识别错字符串强制replace之后再进行匹配
bool cache = false; // 是否使用历史区域
std::unordered_set<Rect> region_of_appeared; // 曾经出现过的区域上次处理该任务时在一些rect里识别到过text这次优先在这些rect里识别省点性能
};
// 图片匹配任务的信息
@@ -216,9 +220,8 @@ namespace asst
virtual ~MatchTaskInfo() = default;
std::string templ_name; // 匹配模板图片文件名
double templ_threshold = 0; // 模板匹配阈值
double hist_threshold = 0; // 直方图比较阈值
double special_threshold = 0; // 某些任务使用的特殊的阈值
std::pair<int, int> mask_range; // 掩码的二值化范围
bool cache = false; // 是否使用缓存直方图false时就一直用模板匹配。默认为true
};
struct HandleInfo
@@ -239,6 +242,7 @@ namespace asst
std::string display;
std::string display_format;
std::string screencap;
std::string release;
//std::string pullscreen;
int display_width = 0;
int display_height = 0;

View File

@@ -5,7 +5,7 @@
#include <ostream>
#include <unordered_map>
#include <json.h>
#include <meojson/json.h>
namespace asst
{
@@ -24,8 +24,8 @@ namespace asst
ReachedLimit, // 单个原子任务达到次数上限
ReadyToSleep, // 准备开始睡眠
EndOfSleep, // 睡眠结束
AppendProcessTask, // [已弃用] 新增流程任务Assistance内部消息,外部不需要处理
AppendTask, // [已弃用] 新增任务Assistance内部消息,外部不需要处理
AppendProcessTask, // [已弃用] 新增流程任务Assistant内部消息,外部不需要处理
AppendTask, // [已弃用] 新增任务Assistant内部消息,外部不需要处理
TaskCompleted, // 单个原子任务完成
PrintWindow, // 截图消息
ProcessTaskStopAction, // 流程任务执行到了Stop的动作
@@ -43,6 +43,7 @@ namespace asst
RecruitSpecialTag, // 公招识别到了特殊的Tag
RecruitResult, // 公开招募结果
RecruitSelected, // 选择了Tags
RecruitError, // 公招错误
/* Infrast Msg */
InfrastSkillsDetected = 4000, // 识别到了基建技能(当前页面)
InfrastSkillsResult, // 识别到的所有可用技能
@@ -64,6 +65,7 @@ namespace asst
{ AsstMsg::ImageMatched, "ImageMatched" },
{ AsstMsg::StageDrops, "StageDrops" },
{ AsstMsg::TaskMatched, "TaskMatched" },
{ AsstMsg::RecruitError, "RecruitError" },
{ AsstMsg::ReachedLimit, "ReachedLimit" },
{ AsstMsg::ReadyToSleep, "ReadyToSleep" },
{ AsstMsg::EndOfSleep, "EndOfSleep" },

View File

@@ -10,24 +10,6 @@ namespace asst
{
namespace utils
{
static std::string get_cur_dir()
{
static std::string cur_dir;
if (cur_dir.empty()) {
char exepath_buff[_MAX_PATH] = { 0 };
::GetModuleFileNameA(NULL, exepath_buff, _MAX_PATH);
std::string exepath(exepath_buff);
cur_dir = exepath.substr(0, exepath.find_last_of('\\') + 1);
}
return cur_dir;
}
static std::string get_resource_dir()
{
static std::string res_dir = get_cur_dir() + "resource\\";
return res_dir;
}
static std::string string_replace_all(const std::string& src, const std::string& old_value, const std::string& new_value)
{
std::string str = src;
@@ -153,6 +135,56 @@ namespace asst
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) {

View File

@@ -2,93 +2,95 @@
#include "Resource.h"
#include "OcrImageAnalyzer.h"
#include "Controller.h"
#include "RecruitImageAnalyzer.h"
#include "ProcessTask.h"
#include "Controller.h"
#include "RecruitImageAnalyzer.h"
#include "ProcessTask.h"
#include "RecruitTask.h"
void asst::AutoRecruitTask::set_required_level(std::vector<int> required_level) noexcept
{
m_required_level = std::move(required_level);
}
void asst::AutoRecruitTask::set_confirm_level(std::vector<int> confirm_level) noexcept
{
m_confirm_level = std::move(confirm_level);
}
void asst::AutoRecruitTask::set_need_refresh(bool need_refresh) noexcept
{
m_need_refresh = need_refresh;
}
void asst::AutoRecruitTask::set_select_level(std::vector<int> select_level) noexcept
{
m_select_level = std::move(select_level);
}
void asst::AutoRecruitTask::set_confirm_level(std::vector<int> confirm_level) noexcept
{
m_confirm_level = std::move(confirm_level);
}
void asst::AutoRecruitTask::set_need_refresh(bool need_refresh) noexcept
{
m_need_refresh = need_refresh;
}
void asst::AutoRecruitTask::set_max_times(int max_times) noexcept
{
m_max_times = max_times;
}
bool asst::AutoRecruitTask::_run()
{
}
bool asst::AutoRecruitTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "RecruitTask" },
{ "task_chain", m_task_chain },
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
int delay = resource.cfg().get_options().task_delay;
auto image = ctrler.get_image();
int delay = Resrc.cfg().get_options().task_delay;
auto image = Ctrler.get_image();
OcrImageAnalyzer start_analyzer(image);
const auto start_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(task.get("StartRecruit"));
start_analyzer.set_task_info(*start_task_ptr);
if (!start_analyzer.analyze()) {
return false;
if (!start_analyzer.analyze()) {
return false;
}
const auto& start_res = start_analyzer.get_result();
for (; m_cur_times < start_res.size() && m_cur_times < m_max_times; ++m_cur_times) {
if (need_exit()) {
return false;
}
Rect start_rect = start_res.at(m_cur_times).rect;
ctrler.click(start_rect);
sleep(delay);
while (true) {
RecruitTask recurit_task(m_callback, m_callback_arg);
recurit_task.set_retry_times(10);
recurit_task.set_param(m_required_level, true);
recurit_task.set_task_chain(m_task_chain);
// 识别错误,放弃这个公招位,直接返回
if (!recurit_task.run()) {
click_return_button();
break;
}
int maybe_level = recurit_task.get_maybe_level();
// 尝试刷新
if (m_need_refresh && maybe_level == 3
&& !recurit_task.get_has_special_tag()
&& recurit_task.get_has_refresh()) {
ProcessTask refresh_task(*this, { "RecruitRefresh" });
if (refresh_task.run()) {
continue;
}
}
if (std::find(m_confirm_level.cbegin(), m_confirm_level.cend(), maybe_level) != m_confirm_level.cend()) {
ProcessTask confirm_task(*this, { "RecruitConfirm" });
if (!confirm_task.run()) {
return false;
}
break;
}
else {
click_return_button();
break;
}
}
}
Rect start_rect = start_res.at(m_cur_times).rect;
Ctrler.click(start_rect);
sleep(delay);
while (true) {
RecruitTask recurit_task(m_callback, m_callback_arg);
recurit_task.set_retry_times(10);
recurit_task.set_param(m_select_level, true);
recurit_task.set_task_chain(m_task_chain);
// 识别错误,放弃这个公招位,直接返回
if (!recurit_task.run()) {
m_callback(AsstMsg::RecruitError, json::value(), m_callback_arg);
click_return_button();
break;
}
int maybe_level = recurit_task.get_maybe_level();
// 尝试刷新
if (m_need_refresh && maybe_level == 3
&& !recurit_task.get_has_special_tag()
&& recurit_task.get_has_refresh()) {
ProcessTask refresh_task(*this, { "RecruitRefresh" });
if (refresh_task.run()) {
continue;
}
}
if (std::find(m_confirm_level.cbegin(), m_confirm_level.cend(), maybe_level) != m_confirm_level.cend()) {
ProcessTask confirm_task(*this, { "RecruitConfirm" });
if (!confirm_task.run()) {
return false;
}
break;
}
else {
click_return_button();
break;
}
}
}
}
return true;
}

View File

@@ -9,7 +9,7 @@ namespace asst
using AbstractTask::AbstractTask;
virtual ~AutoRecruitTask() = default;
void set_required_level(std::vector<int> required_level) noexcept;
void set_select_level(std::vector<int> select_level) noexcept;
void set_confirm_level(std::vector<int> confirm_level) noexcept;
void set_need_refresh(bool need_refresh) noexcept;
void set_max_times(int max_times) noexcept;
@@ -17,7 +17,7 @@ namespace asst
protected:
virtual bool _run() override;
std::vector<int> m_required_level;
std::vector<int> m_select_level;
std::vector<int> m_confirm_level;
bool m_need_refresh = false;
int m_max_times = 0;

View File

@@ -98,6 +98,7 @@ bool asst::Controller::connect_adb(const std::string& address)
m_emulator_info.adb.click = utils::string_replace_all(utils::string_replace_all(m_emulator_info.adb.click, "[Adb]", m_adb_path), "[Address]", address);
m_emulator_info.adb.swipe = utils::string_replace_all(utils::string_replace_all(m_emulator_info.adb.swipe, "[Adb]", m_adb_path), "[Address]", address);
m_emulator_info.adb.screencap = utils::string_replace_all(utils::string_replace_all(m_emulator_info.adb.screencap, "[Adb]", m_adb_path), "[Address]", address);
m_emulator_info.adb.release = utils::string_replace_all(m_emulator_info.adb.release, "[Adb]", m_adb_path);
return true;
}
@@ -115,6 +116,10 @@ asst::Controller::~Controller()
m_cmd_thread.join();
}
if (!m_emulator_info.adb.release.empty()) {
call_command(m_emulator_info.adb.release);
}
::CloseHandle(m_pipe_read);
::CloseHandle(m_pipe_write);
::CloseHandle(m_pipe_child_read);
@@ -194,7 +199,7 @@ void asst::Controller::pipe_working_proc()
}
//else if (!m_thread_idle) { // 队列中没有任务,又不是闲置的时候,就去截图
// cmd_queue_lock.unlock();
// auto start_time = std::chrono::system_clock::now();
// auto start_time = std::chrono::steady_clock::now();
// screencap();
// cmd_queue_lock.lock();
// if (!m_cmd_queue.empty()) {
@@ -211,14 +216,23 @@ void asst::Controller::pipe_working_proc()
}
}
void asst::Controller::set_dirname(std::string dirname) noexcept
{
m_dirname = std::move(dirname);
}
bool asst::Controller::try_capture(const EmulatorInfo& info, bool without_handle)
{
LogTraceScope("try_capture | " + info.name);
if (!m_emulator_info.adb.release.empty()) {
call_command(m_emulator_info.adb.release);
}
const HandleInfo& handle_info = info.handle;
if (!without_handle) { // 使用模拟器自带的adb
// 转成宽字符的
// 转成宽字符的
wchar_t* class_wbuff = nullptr;
if (!handle_info.class_name.empty()) {
size_t class_len = (handle_info.class_name.size() + 1) * 2;
@@ -268,8 +282,8 @@ bool asst::Controller::try_capture(const EmulatorInfo& info, bool without_handle
if (emulator_path.empty()) {
return false;
}
resource.cfg().set_emulator_path(info.name, emulator_path);
resource.user().set_emulator_path(info.name, emulator_path);
Resrc.cfg().set_emulator_path(info.name, emulator_path);
Resrc.user().set_emulator_path(info.name, emulator_path);
}
else {
emulator_path = info.path;
@@ -278,16 +292,16 @@ bool asst::Controller::try_capture(const EmulatorInfo& info, bool without_handle
// 到这一步说明句柄和权限没问题了接下来就是adb的事情了
m_emulator_info = info;
m_handle = window_handle;
log.trace("Handle:", m_handle, "Name:", m_emulator_info.name);
Log.trace("Handle:", m_handle, "Name:", m_emulator_info.name);
std::string adb_path = emulator_path.substr(0, emulator_path.find_last_of('\\') + 1);
adb_path = '"' + utils::string_replace_all(m_emulator_info.adb.path, "[EmulatorPath]", adb_path) + '"';
adb_path = utils::string_replace_all(adb_path, "[ExecDir]", utils::get_cur_dir());
adb_path = utils::string_replace_all(adb_path, "[ExecDir]", m_dirname);
m_adb_path = std::move(adb_path);
}
else { // 使用辅助自带的标准adb
m_emulator_info = info;
m_adb_path = '"' + utils::string_replace_all(m_emulator_info.adb.path, "[ExecDir]", utils::get_cur_dir()) + '"';
m_adb_path = '"' + utils::string_replace_all(m_emulator_info.adb.path, "[ExecDir]", m_dirname) + '"';
}
// 优先使用addresses里指定的地址
@@ -316,7 +330,7 @@ bool asst::Controller::try_capture(const EmulatorInfo& info, bool without_handle
address = smatch[1];
}
}
log.trace("device address", address);
Log.trace("device address", address);
if (address.empty()) {
return false;
}
@@ -372,9 +386,9 @@ std::pair<bool, std::vector<unsigned char>> asst::Controller::call_command(const
::CloseHandle(process_info.hProcess);
::CloseHandle(process_info.hThread);
log.trace("Call", cmd, "ret", exit_ret, ", output size:", pipe_data.size());
Log.trace("Call", cmd, "ret", exit_ret, ", output size:", pipe_data.size());
if (!pipe_data.empty() && pipe_data.size() < 4096) {
log.trace("output:", std::string(pipe_data.cbegin(), pipe_data.cend()));
Log.trace("output:", std::string(pipe_data.cbegin(), pipe_data.cend()));
}
return make_pair(!exit_ret, std::move(pipe_data));
@@ -438,18 +452,18 @@ asst::Point asst::Controller::rand_point_in_rect(const Rect& rect)
void asst::Controller::random_delay() const
{
auto& opt = resource.cfg().get_options();
auto& opt = Resrc.cfg().get_options();
if (opt.control_delay_upper != 0) {
LogTraceFunction;
static std::default_random_engine rand_engine(
std::chrono::system_clock::now().time_since_epoch().count());
std::chrono::steady_clock::now().time_since_epoch().count());
static std::uniform_int_distribution<unsigned> rand_uni(
opt.control_delay_lower,
opt.control_delay_upper);
unsigned rand_delay = rand_uni(rand_engine);
log.trace("random_delay |", rand_delay, "ms");
Log.trace("random_delay |", rand_delay, "ms");
std::this_thread::sleep_for(std::chrono::milliseconds(rand_delay));
}
}
@@ -482,12 +496,12 @@ bool asst::Controller::screencap()
}
m_cache_image = cv::imdecode(data, cv::IMREAD_COLOR);
if (m_cache_image.empty()) {
log.info("Data is not empty, but image is empty, try to convert lf");
Log.info("Data is not empty, but image is empty, try to convert lf");
convert_lf(data);
m_cache_image = cv::imdecode(data, cv::IMREAD_COLOR);
if (m_cache_image.empty()) {
m_image_convert_lf = false;
log.error("convert lf and retry decode falied!");
Log.error("convert lf and retry decode falied!");
return false;
}
m_image_convert_lf = true;
@@ -496,7 +510,7 @@ bool asst::Controller::screencap()
return true;
}
else {
log.error("Data is empty!");
Log.error("Data is empty!");
return false;
}
@@ -522,7 +536,7 @@ int asst::Controller::click(const Rect& rect, bool block)
int asst::Controller::click_without_scale(const Point& p, bool block)
{
if (p.x < 0 || p.x >= m_emulator_info.adb.display_width || p.y < 0 || p.y >= m_emulator_info.adb.display_height) {
log.error("click point out of range");
Log.error("click point out of range");
}
std::string cur_cmd = utils::string_replace_all(m_emulator_info.adb.click, "[x]", std::to_string(p.x));
cur_cmd = utils::string_replace_all(cur_cmd, "[y]", std::to_string(p.y));
@@ -557,7 +571,7 @@ int asst::Controller::swipe(const Rect& r1, const Rect& r2, int duration, bool b
int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay, bool extra_swipe)
{
if (p1.x < 0 || p1.x >= m_emulator_info.adb.display_width || p1.y < 0 || p1.y >= m_emulator_info.adb.display_height || p2.x < 0 || p2.x >= m_emulator_info.adb.display_width || p2.y < 0 || p2.y >= m_emulator_info.adb.display_height) {
log.error("swipe point out of range");
Log.error("swipe point out of range");
}
std::string cur_cmd = utils::string_replace_all(m_emulator_info.adb.swipe, "[x1]", std::to_string(p1.x));
cur_cmd = utils::string_replace_all(cur_cmd, "[y1]", std::to_string(p1.y));
@@ -572,8 +586,8 @@ int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int
int id = 0;
int extra_swipe_dist = resource.cfg().get_options().adb_extra_swipe_dist /* * m_control_scale*/;
int extra_swipe_duration = resource.cfg().get_options().adb_extra_swipe_duration;
int extra_swipe_dist = Resrc.cfg().get_options().adb_extra_swipe_dist /* * m_control_scale*/;
int extra_swipe_duration = Resrc.cfg().get_options().adb_extra_swipe_duration;
// 额外的滑动adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来
if (extra_swipe && extra_swipe_duration >= 0) {

View File

@@ -32,6 +32,8 @@ namespace asst
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);
@@ -72,6 +74,8 @@ namespace asst
// 转换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;
@@ -101,5 +105,6 @@ namespace asst
double m_control_scale = 1.0;
};
static auto& ctrler = Controller::get_instance();
//static auto& ctrler = Controller::get_instance();
#define Ctrler Controller::get_instance()
}

View File

@@ -98,4 +98,4 @@ bool asst::CreditShopImageAnalyzer::sold_out_analyze()
}
return !m_result.empty();
}
}

View File

@@ -19,7 +19,7 @@ bool asst::CreditShoppingTask::_run()
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
const cv::Mat& image = ctrler.get_image();
const cv::Mat& image = Ctrler.get_image();
CreditShopImageAnalyzer shop_analyzer(image);
if (!shop_analyzer.analyze()) {
@@ -31,7 +31,7 @@ bool asst::CreditShoppingTask::_run()
if (need_exit()) {
return false;
}
ctrler.click(commodity);
Ctrler.click(commodity);
static int pre_delay = 1000;
static int rare_delay = 1000;
@@ -44,7 +44,7 @@ bool asst::CreditShoppingTask::_run()
const auto buy_it_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
task.get("CreditShop-BuyIt"));
const cv::Mat& buy_image = ctrler.get_image();
const cv::Mat& buy_image = Ctrler.get_image();
MatchImageAnalyzer buy_it_analyzer(buy_image);
buy_it_analyzer.set_task_info(*buy_it_task_ptr);
if (!buy_it_analyzer.analyze()) {
@@ -59,11 +59,11 @@ bool asst::CreditShoppingTask::_run()
if (need_exit()) {
return false;
}
ctrler.click(buy_it_rect);
Ctrler.click(buy_it_rect);
sleep(rare_delay);
// 识别是否信用不足无法购买
const cv::Mat& prompt_image = ctrler.get_image();
const cv::Mat& prompt_image = Ctrler.get_image();
const auto no_money_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
task.get("CreditShop-NoMoney"));
@@ -75,7 +75,7 @@ bool asst::CreditShoppingTask::_run()
}
// 这里随便点一下都行,把购买完弹出来物品的界面取消掉
ctrler.click(buy_it_rect);
Ctrler.click(buy_it_rect);
sleep(rare_delay);
}

View File

@@ -1,27 +1,33 @@
#include "GeneralConfiger.h"
#include <json.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");
{
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.penguin_report = options_json.at("penguinReport").as_boolean();
m_options.penguin_report_cmd_line = options_json.at("penguinReportCmdLine").as_string();
m_options.penguin_report_server = options_json.get("penguinReportServer", "CN");
m_options.ocr_gpu_index = options_json.get("ocrGpuIndex", -1);
m_options.ocr_thread_number = options_json.at("ocrThreadNumber").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);
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());
m_options.penguin_report.server = penguin_report.get("server", "CN");
if (options_json.exist("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()) {
@@ -46,10 +52,11 @@ bool asst::GeneralConfiger::parse(const json::value& json)
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

@@ -14,23 +14,35 @@ namespace asst
{
Emulator,
Custom
};
struct AipOcrCfg // 百度 OCR API 的配置
{
bool enable = false;
bool accurate = false; // 是否使用高精度识别
std::string client_id;
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 connect_type = ConnectType::Emulator; // 连接类型
int task_delay = 0; // 任务间延时越快操作越快但会增加CPU消耗
int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时
int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时
bool print_window = false; // 截图功能开启后每次结算界面会截图到screenshot目录下
bool penguin_report = false; // 企鹅数据汇报:每次到结算界面,是否汇报掉落数据至企鹅数据 https://penguin-stats.cn/
std::string penguin_report_cmd_line; // 企鹅数据汇报的命令
std::string penguin_report_extra_param; // 企鹅数据汇报的命令
std::string penguin_report_server; // 企鹅数据汇报接口"server"字段,"CN", "US", "JP" and "KR".
int ocr_gpu_index = -1; // OcrLite使用GPU编号-1(使用CPU)/0(使用GPU0)/1(使用GPU1)/...
int ocr_thread_number = 0; // OcrLite线程数量
//bool print_window = false; // 截图功能开启后每次结算界面会截图到screenshot目录下
int adb_extra_swipe_dist = 0; // 额外的滑动距离adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来
int adb_extra_swipe_duration = -1; // 额外的滑动持续时间adb有bug同样的参数偶尔会划得非常远。额外做一个短程滑动把之前的停下来。若小于0则关闭额外滑动功能
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

View File

@@ -67,21 +67,21 @@ bool asst::InfrastAbstractTask::enter_facility(const std::string& facility, int
};
m_callback(AsstMsg::EnterFacility, enter_json, m_callback_arg);
const auto& image = ctrler.get_image();
const auto& image = Ctrler.get_image();
InfrastFacilityImageAnalyzer analyzer(image);
analyzer.set_to_be_analyzed({ facility });
if (!analyzer.analyze()) {
log.trace("result is empty");
Log.trace("result is empty");
return false;
}
Rect rect = analyzer.get_rect(facility, index);
if (rect.empty()) {
log.trace("facility index is out of range");
Log.trace("facility index is out of range");
return false;
}
ctrler.click(rect);
Ctrler.click(rect);
const auto enter_task_ptr = task.get("InfrastEnterFacility");
sleep(enter_task_ptr->rear_delay);
@@ -93,9 +93,9 @@ bool asst::InfrastAbstractTask::enter_oper_list_page()
{
LogTraceFunction;
auto image = ctrler.get_image();
auto image = Ctrler.get_image();
// 识别边的“进驻”按钮
// 识别边的“进驻”按钮
const auto enter_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
task.get("InfrastEnterOperList"));
OcrImageAnalyzer enter_analyzer(image);
@@ -103,31 +103,31 @@ bool asst::InfrastAbstractTask::enter_oper_list_page()
// 如果没找到,说明“进驻信息”这个按钮没有被点开,那就点开它
if (!enter_analyzer.analyze()) {
log.trace("ready to analyze the stationed info button");
Log.trace("ready to analyze the stationed info button");
OcrImageAnalyzer station_analyzer(image);
const auto stationedinfo_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
task.get("InfrastStationedInfo"));
station_analyzer.set_task_info(*stationedinfo_task_ptr);
if (station_analyzer.analyze()) {
log.trace("the stationed info button found");
ctrler.click(station_analyzer.get_result().front().rect);
Log.trace("the stationed info button found");
Ctrler.click(station_analyzer.get_result().front().rect);
sleep(stationedinfo_task_ptr->rear_delay);
// 点开了按钮之后,再识别一次右边的
image = ctrler.get_image();
image = Ctrler.get_image();
enter_analyzer.set_image(image);
if (!enter_analyzer.analyze()) {
log.error("no enterlist button");
Log.error("no enterlist button");
return false;
}
}
else {
log.error("no stationed info button");
Log.error("no stationed info button");
return false;
}
}
log.trace("ready to click the enterlist button");
ctrler.click(enter_analyzer.get_result().front().rect);
Log.trace("ready to click the enterlist button");
Ctrler.click(enter_analyzer.get_result().front().rect);
sleep(enter_task_ptr->rear_delay);
return true;
@@ -141,10 +141,10 @@ void asst::InfrastAbstractTask::async_swipe_of_operlist(bool reverse)
static int duration = task.get("InfrastOperListSwipeBegin")->pre_delay;
if (!reverse) {
m_last_swipe_id = ctrler.swipe(begin_rect, end_rect, duration, false, 0, true);
m_last_swipe_id = Ctrler.swipe(begin_rect, end_rect, duration, false, 0, true);
}
else {
m_last_swipe_id = ctrler.swipe(end_rect, begin_rect, duration, false, 0, true);
m_last_swipe_id = Ctrler.swipe(end_rect, begin_rect, duration, false, 0, true);
}
}
@@ -153,7 +153,7 @@ void asst::InfrastAbstractTask::await_swipe()
LogTraceFunction;
static int extra_delay = task.get("InfrastOperListSwipeBegin")->rear_delay;
ctrler.wait(m_last_swipe_id);
Ctrler.wait(m_last_swipe_id);
sleep(extra_delay);
}
@@ -161,7 +161,7 @@ bool asst::InfrastAbstractTask::click_bottomleft_tab()
{
LogTraceFunction;
const auto task_ptr = task.get("InfrastBottomLeftTab");
ctrler.click(task_ptr->specific_rect);
Ctrler.click(task_ptr->specific_rect);
sleep(task_ptr->rear_delay);
return true;
}
@@ -170,7 +170,7 @@ bool asst::InfrastAbstractTask::click_clear_button()
{
LogTraceFunction;
const auto task_ptr = task.get("InfrastClearButton");
ctrler.click(task_ptr->specific_rect);
Ctrler.click(task_ptr->specific_rect);
sleep(task_ptr->rear_delay);
return true;
}
@@ -180,7 +180,7 @@ bool asst::InfrastAbstractTask::click_confirm_button()
LogTraceFunction;
const auto task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
task.get("InfrastConfirmButton"));
ctrler.click(task_ptr->specific_rect);
Ctrler.click(task_ptr->specific_rect);
sleep(task_ptr->rear_delay);
// 识别“正在提交反馈至神经”,如果网不好一直确认不了,就多等一会
@@ -190,7 +190,7 @@ bool asst::InfrastAbstractTask::click_confirm_button()
if (need_exit()) {
return false;
}
const auto& image = ctrler.get_image();
const auto& image = Ctrler.get_image();
analyzer.set_image(image);
if (!analyzer.analyze()) {
sleep(task_ptr->rear_delay);
@@ -201,26 +201,26 @@ bool asst::InfrastAbstractTask::click_confirm_button()
return false;
}
void asst::InfrastAbstractTask::sync_swipe_of_operlist(bool reverse)
void asst::InfrastAbstractTask::swipe_of_operlist(bool reverse)
{
async_swipe_of_operlist(reverse);
await_swipe();
}
void asst::InfrastAbstractTask::swipe_to_the_left_of_operlist()
void asst::InfrastAbstractTask::swipe_to_the_left_of_operlist(int loop_times)
{
LogTraceFunction;
static Rect begin_rect = task.get("InfrastOperListSwipeToTheLeftBegin")->specific_rect;
static Rect end_rect = task.get("InfrastOperListSwipeToTheLeftEnd")->specific_rect;
static int duration = task.get("InfrastOperListSwipeToTheLeftBegin")->pre_delay;
static int extra_delay = task.get("InfrastOperListSwipeToTheLeftBegin")->rear_delay;
static int loop_times = task.get("InfrastOperListSwipeToTheLeftBegin")->max_times;
static int cfg_loop_times = task.get("InfrastOperListSwipeToTheLeftBegin")->max_times;
for (int i = 0; i != loop_times; ++i) {
for (int i = 0; i != cfg_loop_times * loop_times; ++i) {
if (need_exit()) {
return;
}
ctrler.swipe(end_rect, begin_rect, duration, true, 0, false);
Ctrler.swipe(end_rect, begin_rect, duration, true, 0, false);
}
sleep(extra_delay);
}
@@ -233,7 +233,7 @@ void asst::InfrastAbstractTask::swipe_to_the_left_of_main_ui()
static int duration = task.get("InfrastOperListSwipeToTheLeftBegin")->pre_delay;
static int extra_delay = task.get("InfrastOperListSwipeToTheLeftBegin")->rear_delay;
ctrler.swipe(end_rect, begin_rect, duration, true, extra_delay, false);
Ctrler.swipe(end_rect, begin_rect, duration, true, extra_delay, false);
}
void asst::InfrastAbstractTask::swipe_to_the_right_of_main_ui()
@@ -244,5 +244,5 @@ void asst::InfrastAbstractTask::swipe_to_the_right_of_main_ui()
static int duration = task.get("InfrastOperListSwipeToTheLeftBegin")->pre_delay;
static int extra_delay = task.get("InfrastOperListSwipeToTheLeftBegin")->rear_delay;
ctrler.swipe(begin_rect, end_rect, duration, true, extra_delay, false);
Ctrler.swipe(begin_rect, end_rect, duration, true, extra_delay, false);
}

View File

@@ -15,16 +15,17 @@ namespace asst
virtual void set_work_mode(infrast::WorkMode work_mode) noexcept;
virtual void set_mood_threshold(double mood_thres) noexcept;
constexpr static int OperSelectRetryTimes = 3;
protected:
virtual bool on_run_fails() override;
virtual bool enter_facility(const std::string& facility, int index = 0);
virtual bool enter_oper_list_page(); // 从刚点进基建的界面,到干员列表页
virtual void swipe_to_the_left_of_operlist(); // 滑动到干员列表的最左侧
virtual void swipe_to_the_left_of_operlist(int loop_times = 1); // 滑动到干员列表的最左侧
virtual void swipe_to_the_left_of_main_ui(); // 滑动基建的主界面到最左侧
virtual void swipe_to_the_right_of_main_ui(); // 滑动基建的主界面到最右侧
virtual void sync_swipe_of_operlist(bool reverse = false);
virtual void swipe_of_operlist(bool reverse = false);
virtual void async_swipe_of_operlist(bool reverse = false);
virtual void await_swipe();

View File

@@ -35,4 +35,4 @@ bool asst::InfrastClueImageAnalyzer::clue_analyze()
{
// todo
return false;
}
}

View File

@@ -15,11 +15,11 @@ bool asst::InfrastClueVacancyImageAnalyzer::analyze()
task.get(clue_vacancy + suffix));
analyzer.set_task_info(*task_ptr);
if (!analyzer.analyze()) {
log.trace("no", clue_vacancy, suffix);
Log.trace("no", clue_vacancy, suffix);
continue;
}
Rect rect = analyzer.get_result().rect;
log.trace("has", clue_vacancy, suffix);
Log.trace("has", clue_vacancy, suffix);
#ifdef LOG_TRACE
cv::rectangle(m_image_draw, utils::make_rect<cv::Rect>(rect), cv::Scalar(0, 0, 255), 2);
cv::putText(m_image_draw, suffix, cv::Point(rect.x, rect.y + 1), 0, 1, cv::Scalar(0, 0, 255), 2);

Some files were not shown because too many files have changed in this diff Show More