mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-12 16:00:25 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35e5dcf460 | ||
|
|
36529d9760 | ||
|
|
2762ee9a28 | ||
|
|
3dc491f762 | ||
|
|
24e5f2eb61 | ||
|
|
c7a5b090eb | ||
|
|
e636fb1a77 | ||
|
|
d57a57960b | ||
|
|
42d92ef03d | ||
|
|
d3490ac2b2 | ||
|
|
4cdaaab27c | ||
|
|
75253107b6 | ||
|
|
517a9e09ed | ||
|
|
5741bc17f1 | ||
|
|
ef656e1c87 | ||
|
|
f17bb4d814 |
87382
3rdparty/resource/penguin-stats-recognize/json/stages.json
vendored
87382
3rdparty/resource/penguin-stats-recognize/json/stages.json
vendored
File diff suppressed because it is too large
Load Diff
34
README.md
34
README.md
@@ -1,3 +1,5 @@
|
||||
<div align="center">
|
||||
|
||||
# MeoAssistance
|
||||
|
||||
<div>
|
||||
@@ -14,11 +16,16 @@
|
||||
</div>
|
||||
<br>
|
||||
|
||||
A game assistance for Arknights
|
||||
A game assistant for Arknights
|
||||
|
||||
一款明日方舟的游戏助手,自动刷理智、智能基建换班、公招识别等,一键完成所有日常,全自动长草!!!
|
||||
一款明日方舟的游戏小助手,一键完成所有日常,全自动长草!!!
|
||||
|
||||
纯图像识别,非内存挂!全图形化界面,开罐即食!
|
||||
|
||||
并提供 [Python接口](src/Python/interface.py) 供自行DIY~ 绝赞更新中!✿✿ヽ(°▽°)ノ✿
|
||||
|
||||
</div>
|
||||
|
||||
纯图像识别,非内存挂,全图形化界面,兼容模拟器和安卓设备,开罐即食,绝赞开发中!✿✿ヽ(°▽°)ノ✿
|
||||
<br>
|
||||
|
||||
## 功能介绍
|
||||
@@ -77,16 +84,15 @@ A game assistance for Arknights
|
||||
支持
|
||||
|
||||
1. 在模拟器`设定`-`进阶`中打开`Android调试桥`
|
||||
2. 下载[ADB](https://dl.google.com/android/repository/platform-tools-latest-windows.zip),将`platform-tools`文件夹解压到`MeoAsstGui.exe`的同级目录
|
||||
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`的同级目录
|
||||
- 下载 [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分辨率,经过的测试验证最多,也最稳定。
|
||||
- **注意 :** 目前非`16:9`分辨率下,刷理智、访问好友、信用商店、公招识别、领任务等功能已初步可用;基建功能暂不可用,正在进一步适配中。但仍推荐使用16:9分辨率,经过的测试验证最多,也最稳定。
|
||||
|
||||
## 使用说明
|
||||
|
||||
@@ -104,7 +110,7 @@ A game assistance for Arknights
|
||||
- 举例1:设置`吃理智药`:`999`、`吃石头`:`10`、`指定次数`:`1`。则在刷完**一次**后,由于满足了`指定次数`:`1`的条件,视为任务完成,停止刷理智。
|
||||
- 举例2:不勾选`吃理智药`、不勾选`吃石头`,设置`指定次数`:`100`。则在当前可用理智全部刷完后(可能只刷了几次),由于满足了`不吃理智药`、`不吃石头`的条件,视为任务完成,停止刷理智。
|
||||
- 其他优势
|
||||
- 支持刷完自动上传[企鹅物流数据统计](https://penguin-stats.cn/)
|
||||
- 支持刷完自动上传 [企鹅物流数据统计](https://penguin-stats.cn/)
|
||||
- 支持企鹅物流自定义ID
|
||||
- 支持统计掉落数量
|
||||
- 支持剿灭模式
|
||||
@@ -149,7 +155,7 @@ A game assistance for Arknights
|
||||
- `resource\config.json`中有一些自定义选项,可以尝试根据自己的需要进行修改
|
||||
- 底层算法纯C++开发,并设计了多重的缓存技术,最大限度降低CPU和内存占用
|
||||
- 软件支持自动更新✿✿ヽ(°▽°)ノ✿ 推荐非杠精的同学使用测试版,一般来说更新快且bug少(什么MIUI (╯‵□′)╯︵┻━┻
|
||||
- [反馈问题](https://github.com/MistEO/MeoAssistance-Arknights/issues)最好可以带上目录下的`asst.log`日志文件,并说下使用的模拟器版本,感谢!
|
||||
- [反馈问题](https://github.com/MistEO/MeoAssistance-Arknights/issues) 最好可以带上目录下的`asst.log`日志文件,并说下使用的模拟器版本,感谢!
|
||||
|
||||
## Todo
|
||||
|
||||
@@ -209,16 +215,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) 提供公开招募算法及数据、部分功能逻辑思路
|
||||
- 感谢[内卷地狱](https://jq.qq.com/?_wv=1027&k=ypbzXcA2)的大佬们提供的各种协助支持
|
||||
- 感谢[LmeSzinc](https://github.com/LmeSzinc)提供的界面样式参考,~~虽然我抄了个四不像orz~~
|
||||
- 感谢 [内卷地狱](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):欢迎加入~
|
||||
|
||||
如果觉得软件对你有帮助,点个Star吧!~(网页最上方右上角的小星星),这就是对我最大的支持了!
|
||||
如果觉得软件对你有帮助,帮忙点个Star吧!~(网页最上方右上角的小星星),这就是对我最大的支持了!
|
||||
|
||||
PS:作者前端苦手,现在的界面(WPF)基本是现学现卖的,写得很烂,希望有大佬能帮忙提点PR修改修改,感激不尽_(:з」∠)_
|
||||
|
||||
@@ -7,9 +7,9 @@ extern "C" {
|
||||
#endif
|
||||
typedef void (MEO_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);
|
||||
MEOAPI_PORT void* MEO_CALL AsstCreate(const char* dirname);
|
||||
MEOAPI_PORT void* MEO_CALL AsstCreateEx(const char* dirname, AsstCallback callback, void* custom_arg);
|
||||
void MEOAPI AsstDestroy(void* p_asst);
|
||||
|
||||
bool MEOAPI AsstCatchDefault(void* p_asst);
|
||||
bool MEOAPI AsstCatchEmulator(void* p_asst);
|
||||
@@ -22,10 +22,10 @@ extern "C" {
|
||||
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 AsstAppendRecruit(void* p_asst, int max_times, const int select_level[], int select_len, const int confirm_level[], int confirm_len, bool need_refresh);
|
||||
bool MEOAPI AsstAppendDebug(void* p_asst);
|
||||
|
||||
bool MEOAPI AsstStartRecruitCalc(void* p_asst, const int required_level[], int required_len, bool set_time);
|
||||
bool MEOAPI AsstStartRecruitCalc(void* p_asst, const int select_level[], int required_len, bool set_time);
|
||||
bool MEOAPI AsstStart(void* p_asst);
|
||||
bool MEOAPI AsstStop(void* p_asst);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
200,
|
||||
120
|
||||
],
|
||||
"cache": false,
|
||||
"rearDelay": 5000,
|
||||
"maskRange": [
|
||||
1,
|
||||
@@ -114,14 +113,17 @@
|
||||
"algorithm": "OcrDetect",
|
||||
"text": [
|
||||
"剩余可放置角色",
|
||||
"接管作战"
|
||||
"接管作战",
|
||||
"代理指挥",
|
||||
"运行中"
|
||||
],
|
||||
"roi": [
|
||||
0,
|
||||
300,
|
||||
530,
|
||||
1280,
|
||||
980,
|
||||
190
|
||||
],
|
||||
"cache": false,
|
||||
"action": "doNothing",
|
||||
"rearDelay": 5000,
|
||||
"next": [
|
||||
@@ -200,10 +202,11 @@
|
||||
},
|
||||
"UseMedicine": {
|
||||
"action": "doNothing",
|
||||
"templThreshold": 0.7,
|
||||
"roi": [
|
||||
580,
|
||||
50,
|
||||
700,
|
||||
400,
|
||||
100
|
||||
],
|
||||
"next": [
|
||||
@@ -212,7 +215,6 @@
|
||||
},
|
||||
"MedicineConfirm": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"maxTimes": 0,
|
||||
"roi": [
|
||||
1000,
|
||||
@@ -245,7 +247,6 @@
|
||||
"StoneConfirm": {
|
||||
"template": "MedicineConfirm.png",
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"maxTimes": 0,
|
||||
"roi": [
|
||||
1000,
|
||||
@@ -277,7 +278,6 @@
|
||||
]
|
||||
},
|
||||
"PrtsErrorConfirm": {
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
120,
|
||||
@@ -292,7 +292,6 @@
|
||||
},
|
||||
"AbandonAction": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"reduceOtherTimes": [
|
||||
"StartButton1",
|
||||
"StartButton2"
|
||||
@@ -312,7 +311,6 @@
|
||||
"OfflineConfirmAfterBattle": {
|
||||
"template": "PopupConfirm.png",
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
630,
|
||||
400,
|
||||
@@ -328,7 +326,6 @@
|
||||
},
|
||||
"OfflineConfirm": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
400,
|
||||
@@ -362,7 +359,6 @@
|
||||
},
|
||||
"CloseAnno": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
1100,
|
||||
0,
|
||||
@@ -473,7 +469,6 @@
|
||||
},
|
||||
"Recruit": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
900,
|
||||
450,
|
||||
@@ -507,7 +502,6 @@
|
||||
},
|
||||
"RecruitSkip": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"rearDelay": 3000,
|
||||
"roi": [
|
||||
1100,
|
||||
@@ -538,7 +532,6 @@
|
||||
"StartRecruit": {
|
||||
"algorithm": "OcrDetect",
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"rearDelay": 1000,
|
||||
"text": [
|
||||
"开始招"
|
||||
@@ -591,7 +584,6 @@
|
||||
]
|
||||
},
|
||||
"ReceiveAward": {
|
||||
"cache": false,
|
||||
"action": "clickSelf",
|
||||
"roi": [
|
||||
950,
|
||||
@@ -793,7 +785,6 @@
|
||||
},
|
||||
"VisitNext": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"rearDelay": 2000,
|
||||
"roi": [
|
||||
1080,
|
||||
@@ -1009,7 +1000,6 @@
|
||||
},
|
||||
"HomeFlag": {
|
||||
"template": "Terminal.png",
|
||||
"cache": false,
|
||||
"action": "stop",
|
||||
"roi": [
|
||||
880,
|
||||
@@ -1020,7 +1010,6 @@
|
||||
},
|
||||
"CreditShop-Commoditys": {
|
||||
"template": "CreditPoint.png",
|
||||
"cache": false,
|
||||
"rectMove": [
|
||||
-60,
|
||||
-180,
|
||||
@@ -1029,7 +1018,6 @@
|
||||
]
|
||||
},
|
||||
"CreditShop-SoldOut": {
|
||||
"cache": false,
|
||||
"template": "SoldOut.png"
|
||||
},
|
||||
"CreditShop-BuyIt": {
|
||||
@@ -1040,7 +1028,6 @@
|
||||
250,
|
||||
150
|
||||
],
|
||||
"cache": false,
|
||||
"preDelay": 1000,
|
||||
"rearDelay": 1000
|
||||
},
|
||||
@@ -1078,7 +1065,6 @@
|
||||
"RecruitTime": {
|
||||
"template": "RecruitTimeReduce.png",
|
||||
"templThreshold": 0.89,
|
||||
"cache": false,
|
||||
"action": "clickSelf",
|
||||
"roi": [
|
||||
350,
|
||||
@@ -1143,7 +1129,6 @@
|
||||
},
|
||||
"RecruitRefresh": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
850,
|
||||
340,
|
||||
@@ -1156,7 +1141,6 @@
|
||||
},
|
||||
"RecruitNoRefresh": {
|
||||
"action": "doNothing",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
850,
|
||||
340,
|
||||
@@ -1167,7 +1151,6 @@
|
||||
"RecruitRefreshConfirm": {
|
||||
"template": "PopupConfirm.png",
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"rearDelay": 3000,
|
||||
"roi": [
|
||||
630,
|
||||
@@ -1200,7 +1183,6 @@
|
||||
},
|
||||
"RecruitConfirm": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
860,
|
||||
540,
|
||||
@@ -1270,7 +1252,6 @@
|
||||
},
|
||||
"EnterInfrast": {
|
||||
"rearDelay": 3000,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
900,
|
||||
540,
|
||||
@@ -1348,7 +1329,6 @@
|
||||
},
|
||||
"DroneAssistMfg": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
1180,
|
||||
500,
|
||||
@@ -1364,7 +1344,6 @@
|
||||
},
|
||||
"DroneAssistTrade": {
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
250,
|
||||
430,
|
||||
@@ -1404,13 +1383,12 @@
|
||||
]
|
||||
},
|
||||
"DeliverableOrder": {
|
||||
"cache": false,
|
||||
"action": "clickSelf",
|
||||
"roi": [
|
||||
250,
|
||||
130,
|
||||
300,
|
||||
230,
|
||||
420
|
||||
250
|
||||
],
|
||||
"next": [
|
||||
"DeliverableOrder",
|
||||
@@ -1421,8 +1399,7 @@
|
||||
"DroneAssist-Trade-Stop": {
|
||||
"Doc": "如果找到了“无人机加速”按钮,却没有找到订单交付:说明上一次无人机没有把一个订单加速完成,也说明没有更多的无人机了,所以直接stop",
|
||||
"template": "DroneAssistTrade.png",
|
||||
"action": "stop",
|
||||
"cache": false
|
||||
"action": "stop"
|
||||
},
|
||||
"InfrastSkillsUpper": {
|
||||
"algorithm": "justReturn",
|
||||
@@ -1472,7 +1449,6 @@
|
||||
100,
|
||||
255
|
||||
],
|
||||
"cache": false,
|
||||
"templThreshold": 0.8
|
||||
},
|
||||
"InfrastSmileyOnWork": {
|
||||
@@ -1481,7 +1457,6 @@
|
||||
100,
|
||||
255
|
||||
],
|
||||
"cache": false,
|
||||
"templThreshold": 0.8
|
||||
},
|
||||
"InfrastSmileyOnDistract": {
|
||||
@@ -1490,15 +1465,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,
|
||||
@@ -1561,9 +1534,8 @@
|
||||
"InfrastOperMoodProgressBar": {
|
||||
"template": "empty.png",
|
||||
"templThreshold": 160,
|
||||
"histThreshold": 20,
|
||||
"Doc": "这里的templThreshold,作为进度条最小灰度阈值使用;histThreshold作为进度条相邻点最大变化阈值使用。懒得重新弄个字段了",
|
||||
"cache": false,
|
||||
"specialThreshold": 20,
|
||||
"Doc": "这里的templThreshold,作为进度条最小灰度阈值使用;specialThreshold作为进度条相邻点最大变化阈值使用。懒得重新弄个字段了",
|
||||
"rectMove_Doc": "基于笑脸的位置移动",
|
||||
"rectMove": [
|
||||
21,
|
||||
@@ -1574,7 +1546,6 @@
|
||||
},
|
||||
"InfrastMfg": {
|
||||
"template": "Manufacturing.png",
|
||||
"cache": false,
|
||||
"templThreshold": 0.9,
|
||||
"maskRange": [
|
||||
1,
|
||||
@@ -1590,7 +1561,6 @@
|
||||
"InfrastMfgMini": {
|
||||
"template": "ManufacturingMini.png",
|
||||
"templThreshold": 0.9,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
240,
|
||||
@@ -1605,7 +1575,6 @@
|
||||
"InfrastTrade": {
|
||||
"template": "Trade.png",
|
||||
"templThreshold": 0.9,
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1620,7 +1589,6 @@
|
||||
"InfrastTradeMini": {
|
||||
"template": "TradeMini.png",
|
||||
"templThreshold": 0.9,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
240,
|
||||
@@ -1634,7 +1602,6 @@
|
||||
},
|
||||
"InfrastPower": {
|
||||
"template": "Power.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1649,7 +1616,6 @@
|
||||
},
|
||||
"InfrastPowerMini": {
|
||||
"template": "PowerMini.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
240,
|
||||
@@ -1664,7 +1630,6 @@
|
||||
},
|
||||
"InfrastDorm": {
|
||||
"template": "Dorm.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1679,7 +1644,6 @@
|
||||
},
|
||||
"InfrastDormMini": {
|
||||
"template": "DormMini.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1694,7 +1658,6 @@
|
||||
},
|
||||
"InfrastOffice": {
|
||||
"template": "Office.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1709,7 +1672,6 @@
|
||||
},
|
||||
"InfrastOfficeMini": {
|
||||
"template": "OfficeMini.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1724,7 +1686,6 @@
|
||||
},
|
||||
"InfrastReception": {
|
||||
"template": "Reception.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1739,7 +1700,6 @@
|
||||
},
|
||||
"InfrastReceptionMini": {
|
||||
"template": "ReceptionMini.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1754,7 +1714,6 @@
|
||||
},
|
||||
"InfrastControl": {
|
||||
"template": "ControlCenter.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1769,7 +1728,6 @@
|
||||
},
|
||||
"InfrastControlMini": {
|
||||
"template": "ControlCenterMini.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
@@ -1784,7 +1742,6 @@
|
||||
},
|
||||
"InfrastStationedInfo": {
|
||||
"algorithm": "OcrDetect",
|
||||
"cache": false,
|
||||
"text": [
|
||||
"进驻信息"
|
||||
],
|
||||
@@ -1798,7 +1755,6 @@
|
||||
},
|
||||
"InfrastEnterOperList": {
|
||||
"algorithm": "OcrDetect",
|
||||
"cache": false,
|
||||
"text": [
|
||||
"心情",
|
||||
"休息中",
|
||||
@@ -1835,7 +1791,6 @@
|
||||
"rearDelay": 500,
|
||||
"Doc": "这个任务复用了,上半部分用来检测确认按钮点击成功没;下部部分用来点击",
|
||||
"algorithm": "ocrDetect",
|
||||
"cache": false,
|
||||
"text": [
|
||||
"正在提交",
|
||||
"反馈至神经"
|
||||
@@ -1875,7 +1830,6 @@
|
||||
},
|
||||
"InfrastFacilityListTabMfg": {
|
||||
"template": "FacilityListTabMfg.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
0,
|
||||
@@ -1890,7 +1844,6 @@
|
||||
},
|
||||
"InfrastFacilityListTabTrade": {
|
||||
"template": "FacilityListTabTrade.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
0,
|
||||
@@ -1905,7 +1858,6 @@
|
||||
},
|
||||
"InfrastOperLockedMfg": {
|
||||
"template": "OperLockedMfg.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
200,
|
||||
500,
|
||||
@@ -1915,7 +1867,6 @@
|
||||
},
|
||||
"InfrastOperLockedTrade": {
|
||||
"template": "OperLockedTrade.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
200,
|
||||
500,
|
||||
@@ -1925,7 +1876,6 @@
|
||||
},
|
||||
"InfrastFlagCombatRecord": {
|
||||
"template": "InfrastMfgDogFoodFlag.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
1000,
|
||||
0,
|
||||
@@ -1935,7 +1885,6 @@
|
||||
},
|
||||
"InfrastFlagPureGold": {
|
||||
"template": "InfrastMfgPureGoldFlag.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
1000,
|
||||
0,
|
||||
@@ -1945,7 +1894,6 @@
|
||||
},
|
||||
"InfrastFlagOriginStone": {
|
||||
"template": "InfrastMfgOriginStoneFlag.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
1000,
|
||||
0,
|
||||
@@ -1955,7 +1903,6 @@
|
||||
},
|
||||
"InfrastFlagChip": {
|
||||
"template": "InfrastMfgChipFlag.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
1000,
|
||||
0,
|
||||
@@ -1965,7 +1912,6 @@
|
||||
},
|
||||
"InfrastFlagMoney": {
|
||||
"template": "InfrastTradeMoneyFlag.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
900,
|
||||
500,
|
||||
@@ -1975,7 +1921,6 @@
|
||||
},
|
||||
"InfrastFlagSyntheticJade": {
|
||||
"template": "InfrastTradeSyntheticJadeFlag.png",
|
||||
"cache": false,
|
||||
"roi": [
|
||||
900,
|
||||
500,
|
||||
@@ -1986,7 +1931,6 @@
|
||||
"InfrastAddOperatorMfgGentle": {
|
||||
"template": "AddOperatorMfgGentle.png",
|
||||
"templThreshold": 0.8,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
200,
|
||||
500,
|
||||
@@ -1998,7 +1942,6 @@
|
||||
"InfrastAddOperatorMfgAggressive": {
|
||||
"template": "AddOperatorMfgAggressive.png",
|
||||
"templThreshold": 0.8,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
200,
|
||||
500,
|
||||
@@ -2016,7 +1959,6 @@
|
||||
"InfrastAddOperatorTradeGentle": {
|
||||
"template": "AddOperatorTradeGentle.png",
|
||||
"templThreshold": 0.8,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
200,
|
||||
500,
|
||||
@@ -2028,7 +1970,6 @@
|
||||
"InfrastAddOperatorTradeAggressive": {
|
||||
"template": "AddOperatorTradeAggressive.png",
|
||||
"templThreshold": 0.8,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
200,
|
||||
500,
|
||||
@@ -2046,7 +1987,6 @@
|
||||
"InfrastAddOperatorReceptionGentle": {
|
||||
"template": "AddOperatorReceptionGentle.png",
|
||||
"templThreshold": 0.8,
|
||||
"cache": false,
|
||||
"roi": [
|
||||
0,
|
||||
0,
|
||||
@@ -2068,7 +2008,6 @@
|
||||
},
|
||||
"InfrastOperSelected": {
|
||||
"template": "empty.png",
|
||||
"cache": false,
|
||||
"templThreshold": 8000,
|
||||
"templThreshold_Doc": "这个任务中作为符合range的像素点数量阈值",
|
||||
"maskRange": [
|
||||
@@ -2084,7 +2023,6 @@
|
||||
},
|
||||
"InfrastOperOnShift": {
|
||||
"template": "OnShift.png",
|
||||
"cache": false,
|
||||
"templThreshold": 0.8,
|
||||
"rectMove": [
|
||||
0,
|
||||
@@ -2179,7 +2117,6 @@
|
||||
},
|
||||
"InfrastClue": {
|
||||
"template": "Clue.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 8.8 KiB |
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
#include "AbstractResource.h"
|
||||
#include "AbstractResource.h"
|
||||
|
||||
@@ -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()) {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -27,15 +27,20 @@
|
||||
|
||||
using namespace asst;
|
||||
|
||||
Assistance::Assistance(AsstCallback callback, void* callback_arg)
|
||||
: m_callback(callback), m_callback_arg(callback_arg)
|
||||
Assistance::Assistance(std::string dirname, AsstCallback callback, void* callback_arg)
|
||||
: m_dirname(std::move(dirname)),
|
||||
m_callback(callback),
|
||||
m_callback_arg(callback_arg)
|
||||
{
|
||||
Logger::set_dirname(m_dirname);
|
||||
Controller::set_dirname(m_dirname);
|
||||
|
||||
LogTraceFunction;
|
||||
|
||||
bool resource_ret = resource.load(utils::get_resource_dir());
|
||||
bool resource_ret = Resrc.load(m_dirname + "\\Resource\\");
|
||||
if (!resource_ret) {
|
||||
const std::string& error = resource.get_last_error();
|
||||
log.error("resource broken", error);
|
||||
const std::string& error = Resrc.get_last_error();
|
||||
Log.error("resource broken", error);
|
||||
if (m_callback == nullptr) {
|
||||
throw error;
|
||||
}
|
||||
@@ -71,7 +76,7 @@ bool asst::Assistance::catch_default()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
auto& opt = resource.cfg().get_options();
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
switch (opt.connect_type) {
|
||||
case ConnectType::Emulator:
|
||||
return catch_emulator();
|
||||
@@ -90,14 +95,14 @@ bool Assistance::catch_emulator(const std::string& emulator_name)
|
||||
|
||||
bool ret = false;
|
||||
//std::string cor_name = emulator_name;
|
||||
auto& cfg = resource.cfg();
|
||||
auto& cfg = Resrc.cfg();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
// 自动匹配模拟器,逐个找
|
||||
if (emulator_name.empty()) {
|
||||
for (const auto& [name, info] : cfg.get_emulators_info()) {
|
||||
ret = ctrler.try_capture(info);
|
||||
ret = Ctrler.try_capture(info);
|
||||
if (ret) {
|
||||
//cor_name = name;
|
||||
break;
|
||||
@@ -106,7 +111,7 @@ bool Assistance::catch_emulator(const std::string& emulator_name)
|
||||
}
|
||||
else { // 指定的模拟器
|
||||
auto& info = cfg.get_emulators_info().at(emulator_name);
|
||||
ret = ctrler.try_capture(info);
|
||||
ret = Ctrler.try_capture(info);
|
||||
}
|
||||
|
||||
m_inited = ret;
|
||||
@@ -120,7 +125,7 @@ bool asst::Assistance::catch_custom(const std::string& address)
|
||||
stop();
|
||||
|
||||
bool ret = false;
|
||||
auto& cfg = resource.cfg();
|
||||
auto& cfg = Resrc.cfg();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
@@ -129,7 +134,7 @@ bool asst::Assistance::catch_custom(const std::string& address)
|
||||
remote_info.adb.addresses.push_back(address);
|
||||
}
|
||||
|
||||
ret = ctrler.try_capture(remote_info, true);
|
||||
ret = Ctrler.try_capture(remote_info, true);
|
||||
|
||||
m_inited = ret;
|
||||
return ret;
|
||||
@@ -233,7 +238,7 @@ bool Assistance::append_process_task(const std::string& task, std::string task_c
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::Assistance::append_recruit(unsigned max_times, const std::vector<int>& required_level, const std::vector<int>& confirm_level, bool need_refresh)
|
||||
bool asst::Assistance::append_recruit(unsigned max_times, const std::vector<int>& select_level, const std::vector<int>& confirm_level, bool need_refresh)
|
||||
{
|
||||
LogTraceFunction;
|
||||
if (!m_inited) {
|
||||
@@ -246,7 +251,7 @@ bool asst::Assistance::append_recruit(unsigned max_times, const std::vector<int>
|
||||
auto recruit_task_ptr = std::make_shared<AutoRecruitTask>(task_callback, (void*)this);
|
||||
recruit_task_ptr->set_max_times(max_times);
|
||||
recruit_task_ptr->set_need_refresh(need_refresh);
|
||||
recruit_task_ptr->set_required_level(required_level);
|
||||
recruit_task_ptr->set_select_level(select_level);
|
||||
recruit_task_ptr->set_confirm_level(confirm_level);
|
||||
recruit_task_ptr->set_task_chain(TaskChain);
|
||||
recruit_task_ptr->set_retry_times(AutoRecruitTaskRetryTimesDefault);
|
||||
@@ -280,7 +285,7 @@ bool Assistance::append_debug()
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Assistance::start_recruit_calc(const std::vector<int>& required_level, bool set_time)
|
||||
bool Assistance::start_recruit_calc(const std::vector<int>& select_level, bool set_time)
|
||||
{
|
||||
LogTraceFunction;
|
||||
if (!m_inited) {
|
||||
@@ -290,9 +295,9 @@ bool Assistance::start_recruit_calc(const std::vector<int>& required_level, bool
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto task_ptr = std::make_shared<RecruitTask>(task_callback, (void*)this);
|
||||
task_ptr->set_param(required_level, set_time);
|
||||
task_ptr->set_param(select_level, set_time);
|
||||
task_ptr->set_retry_times(OpenRecruitTaskRetryTimesDefault);
|
||||
task_ptr->set_task_chain("OpenRecruit");
|
||||
task_ptr->set_task_chain("RecruitCalc");
|
||||
m_tasks_queue.emplace(task_ptr);
|
||||
|
||||
return start(false);
|
||||
@@ -381,7 +386,7 @@ bool asst::Assistance::append_infrast(infrast::WorkMode work_mode, const std::ve
|
||||
m_tasks_queue.emplace(control_task_ptr);
|
||||
}
|
||||
else {
|
||||
log.error("append_infrast | Unknown facility", facility);
|
||||
Log.error("append_infrast | Unknown facility", facility);
|
||||
}
|
||||
append_infrast_begin();
|
||||
}
|
||||
@@ -395,7 +400,7 @@ bool asst::Assistance::append_infrast(infrast::WorkMode work_mode, const std::ve
|
||||
|
||||
void asst::Assistance::set_penguin_id(const std::string& id)
|
||||
{
|
||||
auto& opt = resource.cfg().get_options();
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
if (id.empty()) {
|
||||
opt.penguin_report_extra_param.clear();
|
||||
}
|
||||
@@ -407,7 +412,7 @@ void asst::Assistance::set_penguin_id(const std::string& id)
|
||||
bool asst::Assistance::start(bool block)
|
||||
{
|
||||
LogTraceFunction;
|
||||
log.trace("Start |", block ? "block" : "non block");
|
||||
Log.trace("Start |", block ? "block" : "non block");
|
||||
|
||||
if (!m_thread_idle || !m_inited) {
|
||||
return false;
|
||||
@@ -426,7 +431,7 @@ bool asst::Assistance::start(bool block)
|
||||
bool Assistance::stop(bool block)
|
||||
{
|
||||
LogTraceFunction;
|
||||
log.trace("Stop |", block ? "block" : "non block");
|
||||
Log.trace("Stop |", block ? "block" : "non block");
|
||||
|
||||
m_thread_idle = true;
|
||||
|
||||
@@ -483,7 +488,7 @@ void Assistance::working_proc()
|
||||
|
||||
//clear_cache();
|
||||
|
||||
auto& delay = resource.cfg().get_options().task_delay;
|
||||
auto& delay = Resrc.cfg().get_options().task_delay;
|
||||
m_condvar.wait_until(lock, start_time + std::chrono::milliseconds(delay),
|
||||
[&]() -> bool { return m_thread_idle; });
|
||||
}
|
||||
@@ -523,7 +528,7 @@ void Assistance::msg_proc()
|
||||
|
||||
void Assistance::task_callback(AsstMsg msg, const json::value& detail, void* custom_arg)
|
||||
{
|
||||
log.trace("Assistance::task_callback |", msg, detail.to_string());
|
||||
Log.trace("Assistance::task_callback |", msg, detail.to_string());
|
||||
|
||||
Assistance* p_this = (Assistance*)custom_arg;
|
||||
json::value more_detail = detail;
|
||||
@@ -553,15 +558,14 @@ void asst::Assistance::append_callback(AsstMsg msg, json::value detail)
|
||||
|
||||
void Assistance::clear_cache()
|
||||
{
|
||||
resource.templ().clear_hists();
|
||||
resource.item().clear_drop_count();
|
||||
Resrc.item().clear_drop_count();
|
||||
task.clear_cache();
|
||||
}
|
||||
|
||||
json::value asst::Assistance::organize_stage_drop(const json::value& rec)
|
||||
{
|
||||
json::value dst = rec;
|
||||
auto& item = resource.item();
|
||||
auto& item = Resrc.item();
|
||||
for (json::value& drop : dst["drops"].as_array()) {
|
||||
std::string id = drop["itemId"].as_string();
|
||||
int quantity = drop["quantity"].as_integer();
|
||||
@@ -586,7 +590,7 @@ json::value asst::Assistance::organize_stage_drop(const json::value& rec)
|
||||
|
||||
dst["statistics"] = json::array(std::move(statistics_vec));
|
||||
|
||||
log.trace("organize_stage_drop | ", dst.to_string());
|
||||
Log.trace("organize_stage_drop | ", dst.to_string());
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace asst
|
||||
class Assistance
|
||||
{
|
||||
public:
|
||||
Assistance(AsstCallback callback = nullptr, void* callback_arg = nullptr);
|
||||
Assistance(std::string dirname, AsstCallback callback = nullptr, void* callback_arg = nullptr);
|
||||
~Assistance();
|
||||
|
||||
// 根据配置文件,决定捕获模拟器、USB 还是远程设备
|
||||
@@ -52,9 +52,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 +62,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);
|
||||
@@ -89,6 +89,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;
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
#include "Assistance.h"
|
||||
#include "AsstDef.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Version.h"
|
||||
|
||||
#include "Version.h"
|
||||
|
||||
#if 0
|
||||
#if _MSC_VER
|
||||
// Win32平台下Dll的入口
|
||||
BOOL APIENTRY DllMain(HANDLE hModule,
|
||||
BOOL APIENTRY DllMain(HINSTANCE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
@@ -30,7 +30,7 @@ BOOL APIENTRY DllMain(HANDLE hModule,
|
||||
}
|
||||
#elif VA_GNUC
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
AsstCallback _callback = nullptr;
|
||||
@@ -40,29 +40,29 @@ 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()
|
||||
void* AsstCreate(const char* dirname)
|
||||
{
|
||||
try {
|
||||
return new asst::Assistance();
|
||||
return new asst::Assistance(dirname);
|
||||
}
|
||||
catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* AsstCreateEx(AsstCallback callback, void* custom_arg)
|
||||
void* AsstCreateEx(const char* dirname, AsstCallback callback, void* custom_arg)
|
||||
{
|
||||
try {
|
||||
// 创建多实例回调会有问题,有空再慢慢整
|
||||
_callback = callback;
|
||||
return new asst::Assistance(CallbackTrans, custom_arg);
|
||||
return new asst::Assistance(dirname, CallbackTrans, custom_arg);
|
||||
}
|
||||
catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AsstDestory(void* p_asst)
|
||||
void AsstDestroy(void* p_asst)
|
||||
{
|
||||
if (p_asst == nullptr) {
|
||||
return;
|
||||
@@ -158,13 +158,13 @@ bool AsstAppendMall(void* p_asst, bool with_shopping)
|
||||
// return ((asst::Assistance*)p_asst)->append_process_task(task);
|
||||
//}
|
||||
|
||||
bool AsstStartRecruitCalc(void* p_asst, const int required_level[], int required_len, bool set_time)
|
||||
bool AsstStartRecruitCalc(void* 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(required_level, required_level + required_len);
|
||||
level_vector.assign(select_level, select_level + required_len);
|
||||
return ((asst::Assistance*)p_asst)->start_recruit_calc(level_vector, set_time);
|
||||
}
|
||||
|
||||
@@ -184,13 +184,13 @@ bool AsstAppendInfrast(void* p_asst, int work_mode, const char** order, int orde
|
||||
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)
|
||||
bool AsstAppendRecruit(void* 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(required_level, required_level + required_len);
|
||||
required_vector.assign(select_level, select_level + select_len);
|
||||
std::vector<int> confirm_vector;
|
||||
confirm_vector.assign(confirm_level, confirm_level + confirm_len);
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -196,6 +199,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 +211,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 +219,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
|
||||
|
||||
@@ -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;
|
||||
@@ -194,4 +176,4 @@ namespace asst
|
||||
// return str;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "ProcessTask.h"
|
||||
#include "RecruitTask.h"
|
||||
|
||||
void asst::AutoRecruitTask::set_required_level(std::vector<int> required_level) noexcept
|
||||
void asst::AutoRecruitTask::set_select_level(std::vector<int> select_level) noexcept
|
||||
{
|
||||
m_required_level = std::move(required_level);
|
||||
m_select_level = std::move(select_level);
|
||||
}
|
||||
|
||||
void asst::AutoRecruitTask::set_confirm_level(std::vector<int> confirm_level) noexcept
|
||||
@@ -35,9 +35,9 @@ bool asst::AutoRecruitTask::_run()
|
||||
};
|
||||
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
|
||||
|
||||
int delay = resource.cfg().get_options().task_delay;
|
||||
int delay = Resrc.cfg().get_options().task_delay;
|
||||
|
||||
auto image = ctrler.get_image();
|
||||
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);
|
||||
@@ -52,13 +52,13 @@ bool asst::AutoRecruitTask::_run()
|
||||
return false;
|
||||
}
|
||||
Rect start_rect = start_res.at(m_cur_times).rect;
|
||||
ctrler.click(start_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_param(m_select_level, true);
|
||||
recurit_task.set_task_chain(m_task_chain);
|
||||
|
||||
// 识别错误,放弃这个公招位,直接返回
|
||||
@@ -90,5 +90,6 @@ bool asst::AutoRecruitTask::_run()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -211,6 +211,11 @@ 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);
|
||||
@@ -268,8 +273,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 +283,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 +321,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 +377,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,7 +443,7 @@ 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(
|
||||
@@ -449,7 +454,7 @@ void asst::Controller::random_delay() const
|
||||
|
||||
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 +487,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 +501,7 @@ bool asst::Controller::screencap()
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
log.error("Data is empty!");
|
||||
Log.error("Data is empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -522,7 +527,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 +562,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 +577,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) {
|
||||
|
||||
@@ -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:有些模拟器自带的adb,exec-out输出的\n,会被替换成\r\n,导致解码错误,所以这里转一下回来(点名批评mumu)
|
||||
static void convert_lf(std::vector<unsigned char>& data);
|
||||
|
||||
inline static std::string m_dirname;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
//bool m_thread_idle = true;
|
||||
std::thread m_cmd_thread;
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -98,4 +98,4 @@ bool asst::CreditShopImageAnalyzer::sold_out_analyze()
|
||||
}
|
||||
|
||||
return !m_result.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +93,7 @@ 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>(
|
||||
@@ -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);
|
||||
@@ -220,7 +220,7 @@ void asst::InfrastAbstractTask::swipe_to_the_left_of_operlist()
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -35,4 +35,4 @@ bool asst::InfrastClueImageAnalyzer::clue_analyze()
|
||||
{
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -42,12 +42,12 @@ bool asst::InfrastDormTask::_run()
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
InfrastOperImageAnalyzer oper_analyzer(image);
|
||||
const int without_skill = InfrastOperImageAnalyzer::All ^ InfrastOperImageAnalyzer::Skill;
|
||||
oper_analyzer.set_to_be_calced(without_skill);
|
||||
if (!oper_analyzer.analyze()) {
|
||||
log.error("mood analyze faild!");
|
||||
Log.error("mood analyze faild!");
|
||||
return false;
|
||||
}
|
||||
oper_analyzer.sort_by_mood();
|
||||
@@ -59,7 +59,7 @@ bool asst::InfrastDormTask::_run()
|
||||
return false;
|
||||
}
|
||||
if (num_of_selected >= MaxNumOfOpers) {
|
||||
log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
Log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
if (!random_select) {
|
||||
@@ -68,7 +68,7 @@ bool asst::InfrastDormTask::_run()
|
||||
// 如果当前页面休息完成的人数超过5个,说明已经已经把所有心情不满的滑过一遍、没有更多的了
|
||||
// 从这时候开始,随机选人,尽量把宿舍填满(游戏机制,可以加信赖,还有些别的加成什么的)
|
||||
if (++num_of_resting > MaxNumOfOpers) {
|
||||
log.trace("num_of_resting:", num_of_resting, ", enable random");
|
||||
Log.trace("num_of_resting:", num_of_resting, ", enable random");
|
||||
random_select = true;
|
||||
continue;
|
||||
}
|
||||
@@ -77,9 +77,9 @@ bool asst::InfrastDormTask::_run()
|
||||
case infrast::SmileyType::Distract:
|
||||
// 干员没有被选择的情况下,且不在工作,就进驻宿舍
|
||||
if (oper.selected == false && oper.doing != infrast::Doing::Working) {
|
||||
ctrler.click(oper.rect);
|
||||
Ctrler.click(oper.rect);
|
||||
if (++num_of_selected >= MaxNumOfOpers) {
|
||||
log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
Log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -90,16 +90,16 @@ bool asst::InfrastDormTask::_run()
|
||||
}
|
||||
else {
|
||||
if (oper.doing != infrast::Doing::Working) {
|
||||
ctrler.click(oper.rect);
|
||||
Ctrler.click(oper.rect);
|
||||
if (++num_of_selected >= MaxNumOfOpers) {
|
||||
log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
Log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_of_selected >= MaxNumOfOpers) {
|
||||
log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
Log.trace("num_of_selected:", num_of_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
sync_swipe_of_operlist();
|
||||
@@ -116,17 +116,17 @@ bool asst::InfrastDormTask::click_confirm_button()
|
||||
|
||||
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);
|
||||
|
||||
// 宿舍在把正在工作的干员换下来的时候,会有个二次确认的按钮
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
MatchImageAnalyzer cfm_analyzer(image);
|
||||
const auto sec_cfm_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
task.get("InfrastDormConfirmButton"));
|
||||
cfm_analyzer.set_task_info(*sec_cfm_task_ptr);
|
||||
if (cfm_analyzer.analyze()) {
|
||||
ctrler.click(cfm_analyzer.get_result().rect);
|
||||
Ctrler.click(cfm_analyzer.get_result().rect);
|
||||
sleep(sec_cfm_task_ptr->rear_delay);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ bool asst::InfrastDormTask::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(sec_cfm_task_ptr->rear_delay);
|
||||
|
||||
@@ -36,7 +36,7 @@ bool asst::InfrastFacilityImageAnalyzer::analyze()
|
||||
for (const auto& key : m_to_be_analyzed) {
|
||||
auto find_iter = facility_task_name.find(key);
|
||||
if (find_iter == facility_task_name.cend()) {
|
||||
log.error("facility name error", key);
|
||||
Log.error("facility name error", key);
|
||||
continue;
|
||||
}
|
||||
std::string task_name = find_iter->second;
|
||||
|
||||
@@ -15,7 +15,7 @@ bool asst::InfrastInfoTask::_run()
|
||||
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
|
||||
|
||||
swipe_to_the_left_of_main_ui();
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
|
||||
InfrastFacilityImageAnalyzer analyzer(image);
|
||||
analyzer.set_to_be_analyzed({ "Mfg", "Trade", "Power", "Dorm" });
|
||||
@@ -26,7 +26,7 @@ bool asst::InfrastInfoTask::_run()
|
||||
std::string key = "NumOf" + name;
|
||||
//int size = static_cast<int>(res.size());
|
||||
status.set(key, res.size());
|
||||
log.trace("InfrastInfoTask | ", key, res.size());
|
||||
Log.trace("InfrastInfoTask | ", key, res.size());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -51,7 +51,7 @@ bool asst::InfrastOfficeTask::_run()
|
||||
need_shift = true;
|
||||
// TODO,这里有个bug,全部干员中的selected,和当前的,不一定是同一个页面
|
||||
// 不过目前没影响,反正滑动到最前面了,selected的一定是在最前面
|
||||
//ctrler.click(find_iter->rect);
|
||||
//Ctrler.click(find_iter->rect);
|
||||
//sleep(300);
|
||||
break;
|
||||
case infrast::WorkMode::Extreme: // TODO
|
||||
|
||||
@@ -132,7 +132,7 @@ void asst::InfrastOperImageAnalyzer::mood_analyze()
|
||||
const auto prg_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
task.get("InfrastOperMoodProgressBar"));
|
||||
int prg_lower_limit = prg_task_ptr->templ_threshold;
|
||||
int prg_diff_thres = prg_task_ptr->hist_threshold;
|
||||
int prg_diff_thres = prg_task_ptr->special_threshold;
|
||||
Rect rect_move = prg_task_ptr->rect_move;
|
||||
|
||||
for (auto&& oper : m_result) {
|
||||
@@ -268,7 +268,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
|
||||
const auto task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
task.get("InfrastSkills"));
|
||||
const auto bright_thres = task_ptr->hist_threshold;
|
||||
const auto bright_thres = task_ptr->special_threshold;
|
||||
|
||||
MatchImageAnalyzer skill_analyzer(m_image);
|
||||
skill_analyzer.set_mask_range(task_ptr->mask_range);
|
||||
@@ -316,7 +316,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
|
||||
std::vector<std::pair<infrast::Skill, MatchRect>> possible_skills;
|
||||
// 逐个该设施内所有可能的技能,取得分最高的
|
||||
for (const auto& [id, skill] : resource.infrast().get_skills(m_facility)) {
|
||||
for (const auto& [id, skill] : Resrc.infrast().get_skills(m_facility)) {
|
||||
skill_analyzer.set_templ_name(skill.templ_name);
|
||||
|
||||
if (!skill_analyzer.analyze()) {
|
||||
@@ -325,7 +325,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
possible_skills.emplace_back(std::make_pair(skill, skill_analyzer.get_result()));
|
||||
}
|
||||
if (possible_skills.empty()) {
|
||||
log.error("skill has no recognition result");
|
||||
Log.error("skill has no recognition result");
|
||||
continue;
|
||||
}
|
||||
// 可能的结果多于1个,只可能是同一个技能不同等级的结果
|
||||
@@ -367,7 +367,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
} // 这里对应的else就是上述的其他技能混进来了的情况
|
||||
}
|
||||
}
|
||||
log.trace(most_confident_skills.id, most_confident_skills.names.front());
|
||||
Log.trace(most_confident_skills.id, most_confident_skills.names.front());
|
||||
std::string skill_id = most_confident_skills.id;
|
||||
log_str += skill_id + " - " + most_confident_skills.names.front() + "; ";
|
||||
#ifdef LOG_TRACE
|
||||
@@ -378,7 +378,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze()
|
||||
if (!oper.skills.empty()) {
|
||||
++m_num_of_opers_with_skills;
|
||||
}
|
||||
log.trace(log_str, "]");
|
||||
Log.trace(log_str, "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ void asst::InfrastOperImageAnalyzer::selected_analyze()
|
||||
}
|
||||
}
|
||||
}
|
||||
log.trace("selected_analyze |", count);
|
||||
Log.trace("selected_analyze |", count);
|
||||
oper.selected = count >= selected_task_ptr->templ_threshold;
|
||||
oper.rect = selected_rect; // 先凑合用(
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ bool asst::InfrastPowerTask::_run()
|
||||
need_shift = true;
|
||||
// TODO,这里有个bug,全部干员中的selected,和当前的,不一定是同一个页面
|
||||
// 不过目前没影响,反正滑动到最前面了,selected的一定是在最前面
|
||||
//ctrler.click(find_iter->rect);
|
||||
//Ctrler.click(find_iter->rect);
|
||||
//sleep(300);
|
||||
break;
|
||||
case infrast::WorkMode::Extreme: // TODO
|
||||
|
||||
@@ -50,14 +50,14 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
|
||||
++index;
|
||||
|
||||
ctrler.click(tab);
|
||||
Ctrler.click(tab);
|
||||
sleep(tab_task_ptr->rear_delay);
|
||||
|
||||
/* 识别当前制造/贸易站有没有添加干员按钮,没有就不换班 */
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
add_analyzer.set_image(image);
|
||||
if (!add_analyzer.analyze()) {
|
||||
log.info("no add button, just continue");
|
||||
Log.info("no add button, just continue");
|
||||
continue;
|
||||
}
|
||||
auto& rect = add_analyzer.get_result().rect;
|
||||
@@ -72,7 +72,7 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
|
||||
/* 识别当前正在造什么 */
|
||||
MatchImageAnalyzer product_analyzer(image);
|
||||
auto& all_products = resource.infrast().get_facility_info(m_facility).products;
|
||||
auto& all_products = Resrc.infrast().get_facility_info(m_facility).products;
|
||||
std::string cur_product = all_products.at(0);
|
||||
double max_score = 0;
|
||||
for (const std::string& product : all_products) {
|
||||
@@ -89,7 +89,7 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
}
|
||||
}
|
||||
set_product(cur_product);
|
||||
log.info("cur product", cur_product);
|
||||
Log.info("cur product", cur_product);
|
||||
|
||||
// 使用无人机
|
||||
if (cur_product == m_uses_of_drones) {
|
||||
@@ -107,7 +107,7 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
}
|
||||
|
||||
/* 进入干员选择页面 */
|
||||
ctrler.click(add_button);
|
||||
Ctrler.click(add_button);
|
||||
sleep(add_task_ptr->rear_delay);
|
||||
|
||||
constexpr int retry_times = 1;
|
||||
@@ -153,7 +153,7 @@ bool asst::InfrastProductionTask::opers_detect_with_swipe()
|
||||
return false;
|
||||
}
|
||||
size_t num = opers_detect();
|
||||
log.trace("opers_detect return", num);
|
||||
Log.trace("opers_detect return", num);
|
||||
|
||||
// 无论如何也不会没有干员的,除非前面的操作哪里出错了,没进到干员选择的页面。那也就没必要继续下去了
|
||||
if (num == 0) {
|
||||
@@ -179,7 +179,7 @@ bool asst::InfrastProductionTask::opers_detect_with_swipe()
|
||||
size_t asst::InfrastProductionTask::opers_detect()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
|
||||
InfrastOperImageAnalyzer oper_analyzer(image);
|
||||
oper_analyzer.set_facility(m_facility);
|
||||
@@ -207,7 +207,7 @@ size_t asst::InfrastProductionTask::opers_detect()
|
||||
// 有可能是同一个干员,比一下hash
|
||||
int dist = utils::hamming(cur_oper.face_hash, oper.face_hash);
|
||||
#ifdef LOG_TRACE
|
||||
log.trace("opers_detect hash dist |", dist);
|
||||
Log.trace("opers_detect hash dist |", dist);
|
||||
#endif
|
||||
return dist < m_face_hash_thres;
|
||||
});
|
||||
@@ -223,7 +223,7 @@ size_t asst::InfrastProductionTask::opers_detect()
|
||||
bool asst::InfrastProductionTask::optimal_calc()
|
||||
{
|
||||
LogTraceFunction;
|
||||
auto& facility_info = resource.infrast().get_facility_info(m_facility);
|
||||
auto& facility_info = Resrc.infrast().get_facility_info(m_facility);
|
||||
int cur_max_num_of_opers = facility_info.max_num_of_opers - m_cur_num_of_lokced_opers;
|
||||
|
||||
std::vector<infrast::SkillsComb> all_avaliable_combs;
|
||||
@@ -248,7 +248,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
for (const auto& skill : comb.skills) {
|
||||
skill_str += skill.id + " ";
|
||||
}
|
||||
log.trace(skill_str, comb.efficient.at(m_product));
|
||||
Log.trace(skill_str, comb.efficient.at(m_product));
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, int> skills_num;
|
||||
@@ -285,7 +285,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
log_str += "; ";
|
||||
}
|
||||
log_str += "]";
|
||||
log.trace("Single comb efficient", max_efficient, " , skills:", log_str);
|
||||
Log.trace("Single comb efficient", max_efficient, " , skills:", log_str);
|
||||
}
|
||||
|
||||
// 如果有被锁住的干员,说明当前基建没升满级,组合就不启用
|
||||
@@ -295,7 +295,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
}
|
||||
|
||||
// 遍历所有组合,找到效率最高的
|
||||
auto& all_group = resource.infrast().get_skills_group(m_facility);
|
||||
auto& all_group = Resrc.infrast().get_skills_group(m_facility);
|
||||
for (const infrast::SkillsGroup& group : all_group) {
|
||||
LogTraceScope(group.desc);
|
||||
auto cur_available_opers = all_avaliable_combs;
|
||||
@@ -374,7 +374,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
if (!opt.possible_hashs.empty()) {
|
||||
for (const auto& [key, hash] : opt.possible_hashs) {
|
||||
int dist = utils::hamming(find_iter->name_hash, hash);
|
||||
log.trace("optimal_calc | name hash dist", dist, hash, find_iter->name_hash);
|
||||
Log.trace("optimal_calc | name hash dist", dist, hash, find_iter->name_hash);
|
||||
if (dist < m_name_hash_thres) {
|
||||
hash_matched = true;
|
||||
break;
|
||||
@@ -419,7 +419,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
log_str += "; ";
|
||||
}
|
||||
log_str += "]";
|
||||
log.trace(group.desc, "efficient", cur_efficient, " , skills:", log_str);
|
||||
Log.trace(group.desc, "efficient", cur_efficient, " , skills:", log_str);
|
||||
}
|
||||
|
||||
if (cur_efficient > max_efficient) {
|
||||
@@ -434,7 +434,7 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
log_str += "; ";
|
||||
}
|
||||
log_str += "]";
|
||||
log.trace("optimal efficient", max_efficient, " , skills:", log_str);
|
||||
Log.trace("optimal efficient", max_efficient, " , skills:", log_str);
|
||||
}
|
||||
|
||||
m_optimal_combs = std::move(optimal_combs);
|
||||
@@ -450,7 +450,7 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
|
||||
InfrastOperImageAnalyzer oper_analyzer(image);
|
||||
oper_analyzer.set_facility(m_facility);
|
||||
@@ -493,7 +493,7 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
// 既要技能相同,也要hash相同,双重校验
|
||||
for (const auto& [_, hash] : opt_iter->possible_hashs) {
|
||||
int dist = utils::hamming(lhs.name_hash, hash);
|
||||
log.trace("opers_choose | name hash dist", dist);
|
||||
Log.trace("opers_choose | name hash dist", dist);
|
||||
if (dist < m_name_hash_thres) {
|
||||
return true;
|
||||
}
|
||||
@@ -508,7 +508,7 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
}
|
||||
// 这种情况可能是需要选择两个同样的技能,上一次循环选了一个,但是没有把滑出当前页面,本次又识别到了这个已选择的人
|
||||
if (find_iter->selected == true) {
|
||||
auto& facility_info = resource.infrast().get_facility_info(m_facility);
|
||||
auto& facility_info = Resrc.infrast().get_facility_info(m_facility);
|
||||
int cur_max_num_of_opers = facility_info.max_num_of_opers - m_cur_num_of_lokced_opers;
|
||||
if (cur_max_num_of_opers != 1) {
|
||||
cur_all_opers.erase(find_iter);
|
||||
@@ -517,14 +517,14 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
// 但是如果当前设施只有一个位置,即不存在“上次循环”的情况,说明是清除干员按钮没点到
|
||||
}
|
||||
else {
|
||||
ctrler.click(find_iter->rect);
|
||||
Ctrler.click(find_iter->rect);
|
||||
}
|
||||
{
|
||||
auto avlb_iter = std::find_if(
|
||||
m_all_available_opers.cbegin(), m_all_available_opers.cend(),
|
||||
[&](const infrast::Oper& lhs) -> bool {
|
||||
int dist = utils::hamming(lhs.face_hash, find_iter->face_hash);
|
||||
log.trace("opers_choose | face hash dist", dist);
|
||||
Log.trace("opers_choose | face hash dist", dist);
|
||||
if (dist < m_face_hash_thres) {
|
||||
return true;
|
||||
}
|
||||
@@ -535,7 +535,7 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
m_all_available_opers.erase(avlb_iter);
|
||||
}
|
||||
else {
|
||||
log.error("opers_choose | not found oper");
|
||||
Log.error("opers_choose | not found oper");
|
||||
}
|
||||
}
|
||||
cur_all_opers.erase(find_iter);
|
||||
@@ -593,7 +593,7 @@ bool asst::InfrastProductionTask::facility_list_detect()
|
||||
LogTraceFunction;
|
||||
m_facility_list_tabs.clear();
|
||||
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
MultiMatchImageAnalyzer mm_analyzer(image);
|
||||
|
||||
const auto task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
|
||||
@@ -48,7 +48,7 @@ bool asst::InfrastReceptionTask::close_end_prompt()
|
||||
{
|
||||
const auto end_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
task.get("EndOfClueExchange"));
|
||||
MatchImageAnalyzer analyzer(ctrler.get_image());
|
||||
MatchImageAnalyzer analyzer(Ctrler.get_image());
|
||||
analyzer.set_task_info(*end_task_ptr);
|
||||
if (!analyzer.analyze()) {
|
||||
return true;
|
||||
@@ -78,17 +78,17 @@ bool asst::InfrastReceptionTask::proc_clue()
|
||||
proc_vacancy();
|
||||
|
||||
// 开启线索交流,“解锁线索”
|
||||
cv::Mat image = ctrler.get_image();
|
||||
cv::Mat image = Ctrler.get_image();
|
||||
MatchImageAnalyzer unlock_analyzer(image);
|
||||
const auto unlock_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
task.get("UnlockClues"));
|
||||
unlock_analyzer.set_task_info(*unlock_task_ptr);
|
||||
if (unlock_analyzer.analyze()) {
|
||||
ctrler.click(unlock_analyzer.get_result().rect);
|
||||
Ctrler.click(unlock_analyzer.get_result().rect);
|
||||
sleep(unlock_task_ptr->rear_delay);
|
||||
click_bottomleft_tab();
|
||||
proc_vacancy();
|
||||
image = ctrler.get_image();
|
||||
image = Ctrler.get_image();
|
||||
}
|
||||
|
||||
// 所有的空位分析一次,看看还缺哪些线索
|
||||
@@ -98,7 +98,7 @@ bool asst::InfrastReceptionTask::proc_clue()
|
||||
}
|
||||
const auto& vacancy = vacancy_analyzer.get_vacancy();
|
||||
for (auto&& [id, _] : vacancy) {
|
||||
log.trace("InfrastReceptionTask | Vacancy", id);
|
||||
Log.trace("InfrastReceptionTask | Vacancy", id);
|
||||
}
|
||||
|
||||
std::string product;
|
||||
@@ -108,7 +108,7 @@ bool asst::InfrastReceptionTask::proc_clue()
|
||||
else {
|
||||
product = "General";
|
||||
}
|
||||
log.trace("InfrastReceptionTask | product", product);
|
||||
Log.trace("InfrastReceptionTask | product", product);
|
||||
set_product(product);
|
||||
|
||||
return true;
|
||||
@@ -122,7 +122,7 @@ bool asst::InfrastReceptionTask::proc_vacancy()
|
||||
"No1", "No2", "No3", "No4", "No5", "No6", "No7"
|
||||
};
|
||||
|
||||
cv::Mat image = ctrler.get_image();
|
||||
cv::Mat image = Ctrler.get_image();
|
||||
for (const std::string& clue : clue_suffix) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
@@ -135,18 +135,18 @@ bool asst::InfrastReceptionTask::proc_vacancy()
|
||||
}
|
||||
// 点开线索的空位
|
||||
Rect vacancy = vacancy_analyzer.get_vacancy().cbegin()->second;
|
||||
ctrler.click(vacancy);
|
||||
Ctrler.click(vacancy);
|
||||
int delay = task.get(clue_vacancy + clue)->rear_delay;
|
||||
sleep(delay);
|
||||
|
||||
// 识别右边列表中的线索,然后用最底下的那个(一般都是剩余时间最短的)
|
||||
swipe_to_the_bottom_of_clue_list_on_the_right();
|
||||
image = ctrler.get_image();
|
||||
image = Ctrler.get_image();
|
||||
InfrastClueImageAnalyzer clue_analyzer(image);
|
||||
if (!clue_analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
ctrler.click(clue_analyzer.get_result().back().first);
|
||||
Ctrler.click(clue_analyzer.get_result().back().first);
|
||||
sleep(delay);
|
||||
}
|
||||
return true;
|
||||
@@ -155,14 +155,14 @@ bool asst::InfrastReceptionTask::proc_vacancy()
|
||||
bool asst::InfrastReceptionTask::shift()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
MatchImageAnalyzer add_analyzer(image);
|
||||
|
||||
const auto raw_task_ptr = task.get("InfrastAddOperator" + m_facility + m_work_mode_name);
|
||||
switch (raw_task_ptr->algorithm) {
|
||||
case AlgorithmType::JustReturn:
|
||||
if (raw_task_ptr->action == ProcessTaskAction::ClickRect) {
|
||||
ctrler.click(raw_task_ptr->specific_rect);
|
||||
Ctrler.click(raw_task_ptr->specific_rect);
|
||||
}
|
||||
break;
|
||||
case AlgorithmType::MatchTemplate: {
|
||||
@@ -172,7 +172,7 @@ bool asst::InfrastReceptionTask::shift()
|
||||
if (!add_analyzer.analyze()) {
|
||||
return true;
|
||||
}
|
||||
ctrler.click(add_analyzer.get_result().rect);
|
||||
Ctrler.click(add_analyzer.get_result().rect);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@@ -214,7 +214,7 @@ bool asst::InfrastReceptionTask::swipe_to_the_bottom_of_clue_list_on_the_right()
|
||||
static int loop_times = task.get("InfrastClueOnTheRightSwipeBegin")->max_times;
|
||||
|
||||
for (int i = 0; i != loop_times; ++i) {
|
||||
ctrler.swipe(begin_rect, end_rect, duration, true, 0, false);
|
||||
Ctrler.swipe(begin_rect, end_rect, duration, true, 0, false);
|
||||
}
|
||||
sleep(extra_delay);
|
||||
return false;
|
||||
|
||||
@@ -26,6 +26,11 @@ namespace asst
|
||||
return _unique_instance;
|
||||
}
|
||||
|
||||
static void set_dirname(std::string dirname) noexcept
|
||||
{
|
||||
m_dirname = std::move(dirname);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void trace(Args&&... args)
|
||||
{
|
||||
@@ -45,8 +50,8 @@ namespace asst
|
||||
log(level, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
const std::string m_log_filename = asst::utils::get_cur_dir() + "asst.log";
|
||||
const std::string m_log_bak_filename = asst::utils::get_cur_dir() + "asst.bak.log";
|
||||
const std::string m_log_filename = m_dirname + "asst.log";
|
||||
const std::string m_log_bak_filename = m_dirname + "asst.bak.log";
|
||||
|
||||
private:
|
||||
Logger()
|
||||
@@ -76,8 +81,7 @@ namespace asst
|
||||
trace("MeoAssistance Process Start");
|
||||
trace("Version", asst::Version);
|
||||
trace("Build DataTime", __DATE__, __TIME__);
|
||||
trace("Working Path", utils::get_cur_dir());
|
||||
trace("Resource Path", utils::get_resource_dir());
|
||||
trace("Working Path", m_dirname);
|
||||
trace("-----------------------------");
|
||||
}
|
||||
|
||||
@@ -126,6 +130,7 @@ namespace asst
|
||||
}
|
||||
};
|
||||
|
||||
inline static std::string m_dirname;
|
||||
std::mutex m_trace_mutex;
|
||||
};
|
||||
|
||||
@@ -150,8 +155,8 @@ namespace asst
|
||||
std::chrono::time_point<std::chrono::system_clock> m_start_time;
|
||||
};
|
||||
|
||||
static auto& log = Logger::get_instance();
|
||||
|
||||
//static auto& log = Logger::get_instance();
|
||||
#define Log Logger::get_instance()
|
||||
#define LogTraceFunction LoggerAux _func_aux(__FUNCTION__)
|
||||
#define LogTraceScope LoggerAux _func_aux
|
||||
}
|
||||
|
||||
@@ -7,48 +7,19 @@
|
||||
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)
|
||||
m_templ_thres(templ_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);
|
||||
const cv::Mat& templ = Resrc.templ().get_templ(m_templ_name);
|
||||
if (templ.empty()) {
|
||||
log.error("templ is 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;
|
||||
match_templ(templ);
|
||||
}
|
||||
|
||||
bool asst::MatchImageAnalyzer::match_templ(const cv::Mat& templ)
|
||||
@@ -57,7 +28,7 @@ bool asst::MatchImageAnalyzer::match_templ(const cv::Mat& templ)
|
||||
|
||||
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,
|
||||
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;
|
||||
@@ -77,7 +48,7 @@ bool asst::MatchImageAnalyzer::match_templ(const cv::Mat& templ)
|
||||
|
||||
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());
|
||||
Log.trace("match_templ |", m_templ_name, "score:", max_val, "rect:", rect.to_string(), "roi:", m_roi.to_string());
|
||||
}
|
||||
|
||||
if (max_val >= m_templ_thres) {
|
||||
@@ -88,22 +59,3 @@ bool asst::MatchImageAnalyzer::match_templ(const cv::Mat& templ)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,19 +27,23 @@ namespace asst
|
||||
{
|
||||
m_templ_name = std::move(templ_name);
|
||||
}
|
||||
void set_threshold(double templ_thres, double hist_thres = 0.0) noexcept
|
||||
void set_threshold(double templ_thres) noexcept
|
||||
{
|
||||
m_templ_thres = templ_thres;
|
||||
m_hist_thres = hist_thres;
|
||||
}
|
||||
void set_task_info(MatchTaskInfo task_info) noexcept
|
||||
{
|
||||
m_use_cache = task_info.cache;
|
||||
m_mask_range = std::move(task_info.mask_range);
|
||||
m_templ_name = std::move(task_info.templ_name);
|
||||
m_templ_thres = task_info.templ_threshold;
|
||||
m_hist_thres = task_info.hist_threshold;
|
||||
set_roi(task_info.roi);
|
||||
|
||||
if (task_info.cache && !task_info.region_of_appeared.empty()) {
|
||||
m_roi = task_info.region_of_appeared;
|
||||
}
|
||||
else {
|
||||
set_roi(task_info.roi);
|
||||
correct_roi();
|
||||
}
|
||||
}
|
||||
|
||||
//const std::vector<MatchRect>& get_result() const noexcept {
|
||||
@@ -51,15 +55,11 @@ namespace asst
|
||||
}
|
||||
|
||||
protected:
|
||||
static cv::Mat to_hist(const cv::Mat& src);
|
||||
|
||||
virtual bool match_templ(const cv::Mat& templ);
|
||||
virtual bool comp_hist(const cv::Mat& hist, const cv::Rect roi);
|
||||
|
||||
std::string m_templ_name;
|
||||
MatchRect m_result;
|
||||
double m_templ_thres = 0.0;
|
||||
double m_hist_thres = 0.0;
|
||||
bool m_use_cache = false;
|
||||
std::pair<int, int> m_mask_range;
|
||||
};
|
||||
|
||||
@@ -13,12 +13,12 @@ asst::MultiMatchImageAnalyzer::MultiMatchImageAnalyzer(const cv::Mat& image, con
|
||||
|
||||
bool asst::MultiMatchImageAnalyzer::analyze()
|
||||
{
|
||||
log.trace("MultiMatchImageAnalyzer::analyze | ", m_templ_name);
|
||||
Log.trace("MultiMatchImageAnalyzer::analyze | ", m_templ_name);
|
||||
m_result.clear();
|
||||
|
||||
const cv::Mat& templ = resource.templ().get_templ(m_templ_name);
|
||||
const cv::Mat& templ = Resrc.templ().get_templ(m_templ_name);
|
||||
if (templ.empty()) {
|
||||
log.error("templ is empty!");
|
||||
Log.error("templ is empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@ void asst::MultiMatchImageAnalyzer::sort_result()
|
||||
{
|
||||
// 按位置排个序
|
||||
std::sort(m_result.begin(), m_result.end(),
|
||||
[](const MatchRect& lhs, const MatchRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
});
|
||||
[](const MatchRect& lhs, const MatchRect& rhs) -> bool {
|
||||
if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序
|
||||
return lhs.rect.x < rhs.rect.x;
|
||||
}
|
||||
else {
|
||||
return lhs.rect.y < rhs.rect.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat& templ)
|
||||
@@ -45,7 +45,7 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat& templ)
|
||||
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,
|
||||
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;
|
||||
@@ -92,7 +92,7 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat& templ)
|
||||
log_str += res.rect.to_string() + " : " + std::to_string(res.score) + "; ";
|
||||
}
|
||||
log_str += "]";
|
||||
log.trace("multi_match_templ | ", m_templ_name, log_str);
|
||||
Log.trace("multi_match_templ | ", m_templ_name, log_str, "roi:", m_roi.to_string());
|
||||
|
||||
if (!m_result.empty()) {
|
||||
return true;
|
||||
|
||||
@@ -48,12 +48,7 @@ bool asst::OcrImageAnalyzer::analyze()
|
||||
}
|
||||
return true;
|
||||
};
|
||||
m_ocr_result = resource.ocr().recognize(m_image, m_roi, all_pred);
|
||||
m_ocr_result = Resrc.ocr().recognize(m_image, m_roi, all_pred);
|
||||
//log.trace("ocr result", m_ocr_result);
|
||||
if (!m_ocr_result.empty()) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return !m_ocr_result.empty();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,15 @@ namespace asst
|
||||
m_required = std::move(task_info.text);
|
||||
m_full_match = task_info.need_full_match;
|
||||
m_replace = std::move(task_info.replace_map);
|
||||
|
||||
set_roi(task_info.roi);
|
||||
correct_roi();
|
||||
auto& cache_roi = task_info.region_of_appeared;
|
||||
if (task_info.cache && !cache_roi.empty()) {
|
||||
if (cache_roi.area() < m_roi.area()) {
|
||||
m_roi = cache_roi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_pred(const TextRectProc& pred)
|
||||
|
||||
@@ -70,8 +70,8 @@ std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat & image, cons
|
||||
result.emplace_back(std::move(tr));
|
||||
}
|
||||
}
|
||||
log.trace("OcrPack::recognize | raw : ", log_str_raw);
|
||||
log.trace("OcrPack::recognize | proc : ", log_str_proc);
|
||||
Log.trace("OcrPack::recognize | raw : ", log_str_raw);
|
||||
Log.trace("OcrPack::recognize | proc : ", log_str_proc);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -82,5 +82,6 @@ std::vector<asst::TextRect> asst::OcrPack::recognize(const cv::Mat & image, cons
|
||||
tr.rect.y += roi.y;
|
||||
return pred(tr);
|
||||
};
|
||||
Log.trace("OcrPack::recognize | roi : ", roi.to_string());
|
||||
return recognize(image(utils::make_rect<cv::Rect>(roi)), rect_cor);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ std::string asst::PenguinUploader::cvt_json(const std::string& rec_res)
|
||||
|
||||
// Doc: https://developer.penguin-stats.io/public-api/api-v2-instruction/report-api
|
||||
json::value body;
|
||||
auto& opt = resource.cfg().get_options();
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
body["server"] = opt.penguin_report_server;
|
||||
body["stageId"] = rec["stage"]["stageId"];
|
||||
// To fix: https://github.com/MistEO/MeoAssistance-Arknights/issues/40
|
||||
@@ -43,12 +43,12 @@ std::string asst::PenguinUploader::cvt_json(const std::string& rec_res)
|
||||
|
||||
bool asst::PenguinUploader::request_penguin(const std::string& body)
|
||||
{
|
||||
auto& opt = resource.cfg().get_options();
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
std::string body_escape = utils::string_replace_all(body, "\"", "\\\"");
|
||||
std::string cmd_line = utils::string_replace_all(opt.penguin_report_cmd_line, "[body]", body_escape);
|
||||
cmd_line = utils::string_replace_all(cmd_line, "[extra]", opt.penguin_report_extra_param);
|
||||
|
||||
log.trace("request_penguin |", cmd_line);
|
||||
Log.trace("request_penguin |", cmd_line);
|
||||
|
||||
SECURITY_ATTRIBUTES pipe_sec_attr = { 0 };
|
||||
pipe_sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
@@ -88,7 +88,7 @@ bool asst::PenguinUploader::request_penguin(const std::string& body)
|
||||
|
||||
DWORD exit_ret = -1;
|
||||
::GetExitCodeProcess(pi.hProcess, &exit_ret);
|
||||
log.trace("curl say:", pipe_str);
|
||||
Log.trace("curl say:", pipe_str);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ bool ProcessTask::_run()
|
||||
};
|
||||
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
|
||||
|
||||
auto& task_delay = resource.cfg().get_options().task_delay;
|
||||
auto& task_delay = Resrc.cfg().get_options().task_delay;
|
||||
while (!m_cur_tasks_name.empty()) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
@@ -46,7 +46,7 @@ bool ProcessTask::_run()
|
||||
task_info_ptr = front_task_ptr;
|
||||
}
|
||||
else {
|
||||
const auto& image = ctrler.get_image();
|
||||
const auto& image = Ctrler.get_image();
|
||||
ProcessTaskImageAnalyzer analyzer(image, m_cur_tasks_name);
|
||||
if (!analyzer.analyze()) {
|
||||
return false;
|
||||
@@ -93,7 +93,7 @@ bool ProcessTask::_run()
|
||||
//m_callback(AsstMsg::AppendProcessTask, next_json, m_callback_arg);
|
||||
//return true;
|
||||
|
||||
log.trace(next_json.to_string());
|
||||
Log.trace(next_json.to_string());
|
||||
set_tasks(task_info_ptr->exceeded_next);
|
||||
sleep(task_delay);
|
||||
continue;
|
||||
@@ -113,7 +113,7 @@ bool ProcessTask::_run()
|
||||
exec_click_task(rect);
|
||||
break;
|
||||
case ProcessTaskAction::ClickRand: {
|
||||
auto&& [width, height] = ctrler.get_scale_size();
|
||||
auto&& [width, height] = Ctrler.get_scale_size();
|
||||
const Rect full_rect(0, 0, width, height);
|
||||
exec_click_task(full_rect);
|
||||
} break;
|
||||
@@ -128,14 +128,14 @@ bool ProcessTask::_run()
|
||||
need_stop = true;
|
||||
break;
|
||||
case ProcessTaskAction::StageDrops: {
|
||||
cv::Mat image = ctrler.get_image(true);
|
||||
std::string res = resource.penguin().recognize(image);
|
||||
cv::Mat image = Ctrler.get_image(true);
|
||||
std::string res = Resrc.penguin().recognize(image);
|
||||
m_callback(AsstMsg::StageDrops, json::parse(res).value(), m_callback_arg);
|
||||
|
||||
auto& opt = resource.cfg().get_options();
|
||||
auto& opt = Resrc.cfg().get_options();
|
||||
if (opt.print_window) {
|
||||
static const std::string dirname = utils::get_cur_dir() + "screenshot\\";
|
||||
save_image(image, dirname);
|
||||
//static const std::string dirname = utils::get_cur_dir() + "screenshot\\";
|
||||
//save_image(image, dirname);
|
||||
}
|
||||
if (opt.penguin_report) {
|
||||
PenguinUploader::upload(res);
|
||||
@@ -170,7 +170,7 @@ bool ProcessTask::_run()
|
||||
next_json["task_chain"] = m_task_chain;
|
||||
next_json["retry_times"] = m_retry_times;
|
||||
next_json["tasks"] = json::array(task_info_ptr->next);
|
||||
log.trace(next_json.to_string());
|
||||
Log.trace(next_json.to_string());
|
||||
|
||||
set_tasks(task_info_ptr->next);
|
||||
sleep(task_delay);
|
||||
@@ -181,12 +181,12 @@ bool ProcessTask::_run()
|
||||
|
||||
void ProcessTask::exec_click_task(const Rect& matched_rect)
|
||||
{
|
||||
ctrler.click(matched_rect);
|
||||
Ctrler.click(matched_rect);
|
||||
}
|
||||
|
||||
void asst::ProcessTask::exec_swipe_task(ProcessTaskAction action)
|
||||
{
|
||||
const auto&& [width, height] = ctrler.get_scale_size();
|
||||
const auto&& [width, height] = Ctrler.get_scale_size();
|
||||
|
||||
const static Rect right_rect(width * 0.8,
|
||||
height * 0.4,
|
||||
@@ -200,10 +200,10 @@ void asst::ProcessTask::exec_swipe_task(ProcessTaskAction action)
|
||||
|
||||
switch (action) {
|
||||
case asst::ProcessTaskAction::SwipeToTheLeft:
|
||||
ctrler.swipe(left_rect, right_rect);
|
||||
Ctrler.swipe(left_rect, right_rect);
|
||||
break;
|
||||
case asst::ProcessTaskAction::SwipeToTheRight:
|
||||
ctrler.swipe(right_rect, left_rect);
|
||||
Ctrler.swipe(right_rect, left_rect);
|
||||
break;
|
||||
default: // 走不到这里,TODO 报个错
|
||||
break;
|
||||
|
||||
@@ -22,11 +22,11 @@ bool asst::ProcessTaskImageAnalyzer::match_analyze(std::shared_ptr<TaskInfo> tas
|
||||
}
|
||||
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;
|
||||
task_ptr->region_of_appeared = m_result_rect;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -56,7 +56,7 @@ bool asst::ProcessTaskImageAnalyzer::ocr_analyze(std::shared_ptr<TaskInfo> task_
|
||||
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());
|
||||
Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found in cache", tr.to_string());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -64,43 +64,21 @@ bool asst::ProcessTaskImageAnalyzer::ocr_analyze(std::shared_ptr<TaskInfo> task_
|
||||
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);
|
||||
m_ocr_analyzer->set_task_info(*ocr_task_ptr);
|
||||
|
||||
// 识别区域文字,并加入缓存
|
||||
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();
|
||||
bool ret = m_ocr_analyzer->analyze();
|
||||
|
||||
const auto& ocr_result = m_ocr_analyzer->get_result();
|
||||
const auto& ocr_result = m_ocr_analyzer->get_result();
|
||||
if (ret) {
|
||||
auto& res = ocr_result.front();
|
||||
m_result = ocr_task_ptr;
|
||||
m_result_rect = res.rect;
|
||||
ocr_task_ptr->region_of_appeared
|
||||
= res.rect.center_zoom(2.0, m_image.cols, m_image.rows); // OCR库不扩大一点容易识别不到
|
||||
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;
|
||||
}
|
||||
Log.trace("ProcessTaskImageAnalyzer::ocr_analyze | found", res.to_string());
|
||||
}
|
||||
|
||||
// 都没有的话,再完整的识别整个ROI
|
||||
return analyze_roi(ocr_task_ptr->roi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void asst::ProcessTaskImageAnalyzer::reset() noexcept
|
||||
@@ -143,4 +121,4 @@ void asst::ProcessTaskImageAnalyzer::set_image(const cv::Mat & image)
|
||||
{
|
||||
AbstractImageAnalyzer::set_image(image);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ bool asst::RecruitImageAnalyzer::tags_analyze()
|
||||
const auto tags_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
|
||||
task.get("RecruitTags"));
|
||||
tags_analyzer.set_roi(tags_task_ptr->roi);
|
||||
auto& all_tags_set = resource.recruit().get_all_tags();
|
||||
auto& all_tags_set = Resrc.recruit().get_all_tags();
|
||||
std::vector<std::string> all_tags_vec;
|
||||
all_tags_vec.assign(all_tags_set.begin(), all_tags_set.end());
|
||||
tags_analyzer.set_required(std::move(all_tags_vec));
|
||||
@@ -38,7 +38,7 @@ bool asst::RecruitImageAnalyzer::tags_analyze()
|
||||
if (tags_analyzer.analyze()) {
|
||||
m_tags_result = tags_analyzer.get_result();
|
||||
return true;
|
||||
//if (m_tags_result.size() == resource.recruit().CorrectNumberOfTags) {
|
||||
//if (m_tags_result.size() == Resrc.recruit().CorrectNumberOfTags) {
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ bool RecruitTask::_run()
|
||||
m_has_special_tag = false;
|
||||
m_has_refresh = false;
|
||||
|
||||
const cv::Mat& image = ctrler.get_image();
|
||||
const cv::Mat& image = Ctrler.get_image();
|
||||
if (image.empty()) {
|
||||
m_callback(AsstMsg::ImageIsEmpty, task_start_json, m_callback_arg);
|
||||
return false;
|
||||
@@ -37,7 +37,7 @@ bool RecruitTask::_run()
|
||||
|
||||
if (m_set_time) {
|
||||
for (const auto& rect : analyzer.get_set_time_rect()) {
|
||||
ctrler.click(rect, false);
|
||||
Ctrler.click(rect, false);
|
||||
}
|
||||
}
|
||||
const std::vector<TextRect>& all_tags = analyzer.get_tags_result();
|
||||
@@ -96,7 +96,7 @@ bool RecruitTask::_run()
|
||||
RecruitCombs oper_combs;
|
||||
oper_combs.tags = comb;
|
||||
|
||||
for (const RecruitOperInfo& cur_oper : resource.recruit().get_all_opers()) {
|
||||
for (const RecruitOperInfo& cur_oper : Resrc.recruit().get_all_opers()) {
|
||||
int matched_count = 0;
|
||||
for (const std::string& tag : comb) {
|
||||
if (cur_oper.tags.find(tag) != cur_oper.tags.cend()) {
|
||||
@@ -201,12 +201,12 @@ bool RecruitTask::_run()
|
||||
|
||||
if (!result_vec.empty()) {
|
||||
/* 点击最优解的tags */
|
||||
if (std::find(m_required_level.cbegin(), m_required_level.cend(), m_maybe_level) != m_required_level.cend()) {
|
||||
if (std::find(m_select_level.cbegin(), m_select_level.cend(), m_maybe_level) != m_select_level.cend()) {
|
||||
const std::vector<std::string>& final_tags_name = result_vec.at(0).tags;
|
||||
|
||||
for (const TextRect& text_area : all_tags) {
|
||||
if (std::find(final_tags_name.cbegin(), final_tags_name.cend(), text_area.text) != final_tags_name.cend()) {
|
||||
ctrler.click(text_area.rect, true);
|
||||
Ctrler.click(text_area.rect, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,8 +219,8 @@ bool RecruitTask::_run()
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecruitTask::set_param(std::vector<int> required_level, bool set_time) noexcept
|
||||
void RecruitTask::set_param(std::vector<int> select_level, bool set_time) noexcept
|
||||
{
|
||||
m_required_level = std::move(required_level);
|
||||
m_select_level = std::move(select_level);
|
||||
m_set_time = set_time;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace asst
|
||||
using AbstractTask::AbstractTask;
|
||||
virtual ~RecruitTask() = default;
|
||||
|
||||
void set_param(std::vector<int> required_level, bool set_time = true) noexcept;
|
||||
void set_param(std::vector<int> select_level, bool set_time = true) noexcept;
|
||||
|
||||
bool get_has_special_tag() const noexcept
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace asst
|
||||
virtual bool _run() override;
|
||||
|
||||
/* 外部设置参数 */
|
||||
std::vector<int> m_required_level;
|
||||
std::vector<int> m_select_level;
|
||||
bool m_set_time = false;
|
||||
|
||||
/* 内部处理用参数*/
|
||||
|
||||
@@ -112,5 +112,6 @@ namespace asst
|
||||
PenguinPack m_penguin_pack_unique_ins;
|
||||
};
|
||||
|
||||
static auto& resource = Resource::get_instance();
|
||||
//static auto& resource = Resource::get_instance();
|
||||
#define Resrc Resource::get_instance()
|
||||
}
|
||||
|
||||
@@ -32,11 +32,7 @@ std::shared_ptr<asst::TaskInfo> asst::TaskData::get(std::string name)
|
||||
void asst::TaskData::clear_cache() noexcept
|
||||
{
|
||||
for (auto&& [name, ptr] : m_all_tasks_info) {
|
||||
switch (ptr->algorithm) {
|
||||
case AlgorithmType::OcrDetect:
|
||||
std::dynamic_pointer_cast<OcrTaskInfo>(ptr)->region_of_appeared.clear();
|
||||
break;
|
||||
}
|
||||
ptr->region_of_appeared = Rect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +70,8 @@ bool asst::TaskData::parse(const json::value& json)
|
||||
|
||||
match_task_info_ptr->templ_threshold = task_json.get(
|
||||
"templThreshold", TemplThresholdDefault);
|
||||
match_task_info_ptr->hist_threshold = task_json.get(
|
||||
"histThreshold", HistThresholdDefault);
|
||||
match_task_info_ptr->cache = task_json.get("cache", true);
|
||||
match_task_info_ptr->special_threshold = task_json.get(
|
||||
"specialThreshold", 0);
|
||||
if (task_json.exist("maskRange")) {
|
||||
match_task_info_ptr->mask_range = std::make_pair(
|
||||
task_json.at("maskRange")[0].as_integer(),
|
||||
@@ -96,10 +91,10 @@ bool asst::TaskData::parse(const json::value& json)
|
||||
ocr_task_info_ptr->replace_map.emplace(rep.as_array()[0].as_string(), rep.as_array()[1].as_string());
|
||||
}
|
||||
}
|
||||
ocr_task_info_ptr->cache = task_json.get("cache", true);
|
||||
task_info_ptr = ocr_task_info_ptr;
|
||||
} break;
|
||||
}
|
||||
task_info_ptr->cache = task_json.get("cache", true);
|
||||
task_info_ptr->algorithm = algorithm;
|
||||
task_info_ptr->name = name;
|
||||
std::string action = task_json.get("action", std::string());
|
||||
|
||||
@@ -45,29 +45,7 @@ const cv::Mat& asst::TemplResource::get_templ(const std::string& key) const noex
|
||||
}
|
||||
}
|
||||
|
||||
const std::pair<cv::Mat, cv::Rect>& asst::TemplResource::get_hist(const std::string& key) const noexcept
|
||||
{
|
||||
if (auto iter = m_hists.find(key);
|
||||
iter != m_hists.cend()) {
|
||||
return iter->second;
|
||||
}
|
||||
else {
|
||||
static const std::pair<cv::Mat, cv::Rect> empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
void asst::TemplResource::emplace_templ(std::string key, cv::Mat templ)
|
||||
{
|
||||
m_templs.emplace(std::move(key), std::move(templ));
|
||||
}
|
||||
|
||||
void asst::TemplResource::emplace_hist(std::string key, cv::Mat hist, cv::Rect roi)
|
||||
{
|
||||
m_hists.emplace(std::move(key), std::make_pair(std::move(hist), std::move(roi)));
|
||||
}
|
||||
|
||||
void asst::TemplResource::clear_hists() noexcept
|
||||
{
|
||||
m_hists.clear();
|
||||
}
|
||||
|
||||
@@ -20,15 +20,11 @@ namespace asst
|
||||
|
||||
bool exist_templ(const std::string& key) const noexcept;
|
||||
const cv::Mat& get_templ(const std::string& key) const noexcept;
|
||||
const std::pair<cv::Mat, cv::Rect>& get_hist(const std::string& key) const noexcept;
|
||||
|
||||
void emplace_templ(std::string key, cv::Mat templ);
|
||||
void emplace_hist(std::string key, cv::Mat hist, cv::Rect roi);
|
||||
void clear_hists() noexcept;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> m_templs_filename;
|
||||
std::unordered_map<std::string, cv::Mat> m_templs;
|
||||
std::unordered_map<std::string, std::pair<cv::Mat, cv::Rect>> m_hists;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
namespace asst
|
||||
{
|
||||
constexpr static const char* Version = "v2.2.2";
|
||||
constexpr static const char* Version = "v2.3.0";
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ namespace MeoAsstGui
|
||||
|
||||
private delegate void ProcCallbckMsg(AsstMsg msg, JObject detail);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern IntPtr AsstCreate();
|
||||
[DllImport("MeoAssistance.dll")] private static extern IntPtr AsstCreate(string dirname);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern IntPtr AsstCreateEx(CallbackDelegate callback, IntPtr custom_arg);
|
||||
[DllImport("MeoAssistance.dll")] private static extern IntPtr AsstCreateEx(string dirname, CallbackDelegate callback, IntPtr custom_arg);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern void AsstDestory(IntPtr ptr);
|
||||
[DllImport("MeoAssistance.dll")] private static extern void AsstDestroy(IntPtr ptr);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstCatchDefault(IntPtr ptr);
|
||||
|
||||
@@ -36,9 +36,9 @@ namespace MeoAsstGui
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstAppendInfrast(IntPtr ptr, int work_mode, string[] order, int order_len, string uses_of_drones, double dorm_threshold);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstAppendRecruit(IntPtr ptr, int max_times, int[] required_level, int required_len, int[] confirm_level, int confirm_len, bool need_refresh);
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstAppendRecruit(IntPtr ptr, int max_times, int[] select_level, int required_len, int[] confirm_level, int confirm_len, bool need_refresh);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstStartRecruitCalc(IntPtr ptr, int[] required_level, int required_len, bool set_time);
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstStartRecruitCalc(IntPtr ptr, int[] select_level, int required_len, bool set_time);
|
||||
|
||||
[DllImport("MeoAssistance.dll")] private static extern bool AsstStart(IntPtr ptr);
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace MeoAsstGui
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_ptr = AsstCreateEx(_callback, IntPtr.Zero);
|
||||
_ptr = AsstCreateEx(System.IO.Directory.GetCurrentDirectory(), _callback, IntPtr.Zero);
|
||||
if (_ptr == IntPtr.Zero)
|
||||
{
|
||||
_windowManager.ShowMessageBox("程序初始化错误!请检查是否是因为使用了中文路径", "错误");
|
||||
@@ -331,9 +331,9 @@ namespace MeoAsstGui
|
||||
return AsstAppendMall(_ptr, with_shopping);
|
||||
}
|
||||
|
||||
public bool AsstAppendRecruit(int max_times, int[] required_level, int required_len, int[] confirm_level, int confirm_len, bool need_refresh)
|
||||
public bool AsstAppendRecruit(int max_times, int[] select_level, int required_len, int[] confirm_level, int confirm_len, bool need_refresh)
|
||||
{
|
||||
return AsstAppendRecruit(_ptr, max_times, required_level, required_len, confirm_level, confirm_len, need_refresh);
|
||||
return AsstAppendRecruit(_ptr, max_times, select_level, required_len, confirm_level, confirm_len, need_refresh);
|
||||
}
|
||||
|
||||
public bool AsstAppendInfrast(int work_mode, string[] order, int order_len, string uses_of_drones, double dorm_threshold)
|
||||
@@ -346,9 +346,9 @@ namespace MeoAsstGui
|
||||
return AsstStart(_ptr);
|
||||
}
|
||||
|
||||
public bool AsstStartRecruitCalc(int[] required_level, int required_len, bool set_time)
|
||||
public bool AsstStartRecruitCalc(int[] select_level, int required_len, bool set_time)
|
||||
{
|
||||
return AsstStartRecruitCalc(_ptr, required_level, required_len, set_time);
|
||||
return AsstStartRecruitCalc(_ptr, select_level, required_len, set_time);
|
||||
}
|
||||
|
||||
public bool AsstStop()
|
||||
|
||||
@@ -348,7 +348,7 @@ namespace MeoAsstGui
|
||||
public bool ResourceOTA()
|
||||
{
|
||||
const string req_base_url = "https://api.github.com/repos/MistEO/MeoAssistance-Arknights/commits?path=";
|
||||
const string down_base_url = "https://cdn.jsdelivr.net/gh/MistEO/MeoAssistance-Arknights@master/";
|
||||
const string down_base_url = "https://cdn.jsdelivr.net/gh/MistEO/MeoAssistance-Arknights@";
|
||||
var update_dict = new Dictionary<string, string>()
|
||||
{
|
||||
{ "3rdparty/resource/penguin-stats-recognize/json/stages.json" , "resource/penguin-stats-recognize/json/stages.json"},
|
||||
@@ -382,7 +382,8 @@ namespace MeoAsstGui
|
||||
}
|
||||
|
||||
string tempname = filename + ".tmp";
|
||||
if (!DownloadFile(down_base_url + url, tempname))
|
||||
string download_url = down_base_url + cloud_sha + "/" + url;
|
||||
if (!DownloadFile(download_url, tempname))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
233
src/Python/interface.py
Normal file
233
src/Python/interface.py
Normal file
@@ -0,0 +1,233 @@
|
||||
import ctypes
|
||||
import os
|
||||
import json
|
||||
import pathlib
|
||||
from message import Message
|
||||
|
||||
|
||||
class Asst:
|
||||
CallBackType = ctypes.CFUNCTYPE(
|
||||
None, ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p)
|
||||
"""
|
||||
回调函数,使用实例可参照my_callback
|
||||
|
||||
:params:
|
||||
``param1 message``: 消息类型
|
||||
``param2 details``: gbk json string
|
||||
``param3 arg``: 自定义参数
|
||||
"""
|
||||
|
||||
def __init__(self, dirname: str, callback: CallBackType, arg=None):
|
||||
"""
|
||||
:params:
|
||||
``dirname``: DLL及资源所在文件夹路径
|
||||
``callback``: 回调函数
|
||||
``arg``: 自定义参数
|
||||
"""
|
||||
self.__dllpath = pathlib.Path(dirname) / 'MeoAssistance.dll'
|
||||
self.__dll = ctypes.WinDLL(str(self.__dllpath))
|
||||
|
||||
self.__dll.AsstCreateEx.restype = ctypes.c_void_p
|
||||
self.__dll.AsstCreateEx.argtypes = (ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p,)
|
||||
self.__ptr = self.__dll.AsstCreateEx(dirname.encode('utf-8'), callback, arg)
|
||||
|
||||
def __del__(self):
|
||||
self.__dll.AsstDestroy.argtypes = (ctypes.c_void_p,)
|
||||
self.__dll.AsstDestroy(self.__ptr)
|
||||
|
||||
def catch_default(self) -> bool:
|
||||
"""
|
||||
连接配置文件中的默认选项(模拟器or安卓手机)
|
||||
|
||||
:return: 是否连接成功
|
||||
"""
|
||||
self.__dll.AsstCatchDefault.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstCatchDefault(self.__ptr)
|
||||
|
||||
def catch_emulator(self) -> bool:
|
||||
"""
|
||||
连接模拟器
|
||||
|
||||
:return: 是否连接成功
|
||||
"""
|
||||
self.__dll.AsstCatchEmulator.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstCatchEmulator(self.__ptr)
|
||||
|
||||
def catch_custom(self, address: str) -> bool:
|
||||
"""
|
||||
连接自定义设备
|
||||
|
||||
:return: 是否连接成功
|
||||
"""
|
||||
self.__dll.AsstCatchCustom.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_char_p,)
|
||||
return self.__dll.AsstCatchCustom(self.__ptr, address.encode('utf-8'))
|
||||
|
||||
def append_fight(self, max_medicine: int, max_stone: int, max_times: int) -> bool:
|
||||
"""
|
||||
添加刷理智任务
|
||||
|
||||
:params:
|
||||
``max_medicine``: 最多吃多少理智药
|
||||
``max_stone``: 最多吃多少源石
|
||||
``max_times``: 最多刷多少
|
||||
"""
|
||||
self.__dll.AsstAppendFight.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int,)
|
||||
return self.__dll.AsstAppendFight(self.__ptr, max_medicine, max_stone, max_times)
|
||||
|
||||
def append_award(self) -> bool:
|
||||
"""
|
||||
添加领取每日奖励任务
|
||||
"""
|
||||
self.__dll.AsstAppendAward.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstAppendAward(self.__ptr)
|
||||
|
||||
def append_visit(self) -> bool:
|
||||
"""
|
||||
添加访问好友任务
|
||||
"""
|
||||
self.__dll.AsstAppendVisit.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstAppendVisit(self.__ptr)
|
||||
|
||||
def append_mall(self, with_shopping: bool) -> bool:
|
||||
"""
|
||||
添加信用商店任务
|
||||
|
||||
:params:
|
||||
``with_shopping``: 是否信用商店购物
|
||||
"""
|
||||
self.__dll.AsstAppendMall.argtypes = (ctypes.c_void_p, ctypes.c_bool)
|
||||
return self.__dll.AsstAppendMall(self.__ptr, with_shopping)
|
||||
|
||||
def append_infrast(self, work_mode: int, order_list: list, uses_of_drones: str, dorm_threshold: float) -> bool:
|
||||
"""
|
||||
添加基建任务
|
||||
|
||||
:params:
|
||||
``work_mode``: 工作模式,当前仅支持传 1
|
||||
``order_list``: 换班顺序,str list,例如 [ "Mfg", "Trade", "Control", "Power", "Reception", "Office", "Dorm"]
|
||||
``uses_of_drones``: 无人机用途,支持以下之一:"_NotUse"、"Money"、"SyntheticJade"、"CombatRecord"、"PureGold"、"OriginStone"、"Chip"
|
||||
``dorm_threshold``: 宿舍心情阈值,取值 [0, 1.0]
|
||||
"""
|
||||
order_byte_list = []
|
||||
|
||||
for item in order_list:
|
||||
order_byte_list.append(item.encode('utf-8'))
|
||||
|
||||
order_len = len(order_byte_list)
|
||||
order_arr = (ctypes.c_char_p * order_len)()
|
||||
order_arr[:] = order_byte_list
|
||||
|
||||
self.__dll.AsstAppendInfrast.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.POINTER(ctypes.c_char_p), ctypes.c_int,
|
||||
ctypes.c_char_p, ctypes.c_double,)
|
||||
return self.__dll.AsstAppendInfrast(self.__ptr, work_mode,
|
||||
order_arr, order_len,
|
||||
uses_of_drones.encode('utf-8'), dorm_threshold)
|
||||
|
||||
def append_recruit(self, max_times: int, select_level: list, confirm_level: list, need_refresh: bool) -> bool:
|
||||
"""
|
||||
添加自动公招任务
|
||||
|
||||
:params:
|
||||
``max_times``: 自动公招次数
|
||||
``select_level``: 要点击的Tags等级(例如3级Tags不选也可以直接确认),int list
|
||||
``confirm_level``: 要确认开始招募的Tags等级,int list
|
||||
``need_refresh``: 是否刷新3级Tags
|
||||
"""
|
||||
select_len = len(select_level)
|
||||
select_arr = (ctypes.c_int * select_len)()
|
||||
select_arr[:] = select_level
|
||||
|
||||
confirm_len = len(confirm_level)
|
||||
confirm_arr = (ctypes.c_int * confirm_len)()
|
||||
confirm_arr[:] = confirm_level
|
||||
|
||||
self.__dll.AsstAppendRecruit.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.POINTER(ctypes.c_int), ctypes.c_int,
|
||||
ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_bool,)
|
||||
return self.__dll.AsstAppendRecruit(self.__ptr, max_times,
|
||||
select_arr, select_len,
|
||||
confirm_arr, confirm_len, need_refresh)
|
||||
|
||||
def start(self) -> bool:
|
||||
"""
|
||||
开始任务
|
||||
"""
|
||||
self.__dll.AsstStart.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstStart(self.__ptr)
|
||||
|
||||
def start_recurit_calc(self, select_level: list, set_time: bool) -> bool:
|
||||
"""
|
||||
进行公招计算
|
||||
|
||||
:params:
|
||||
``select_level``: 要点击的Tags等级,int list
|
||||
``set_time``: 是否要点击9小时
|
||||
"""
|
||||
select_len = len(select_level)
|
||||
select_arr = (ctypes.c_int * select_len)()
|
||||
select_arr[:] = select_level
|
||||
|
||||
self.__dll.AsstStartRecruitCalc.argtypes = (
|
||||
ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_bool,)
|
||||
return self.__dll.AsstStartRecruitCalc(self.__ptr, select_arr, select_len, set_time)
|
||||
|
||||
def stop(self) -> bool:
|
||||
"""
|
||||
停止并清空所有任务
|
||||
"""
|
||||
self.__dll.AsstStop.argtypes = (ctypes.c_void_p,)
|
||||
return self.__dll.AsstStop(self.__ptr)
|
||||
|
||||
def set_penguin_id(self, id: str) -> bool:
|
||||
"""
|
||||
设置企鹅物流ID
|
||||
|
||||
:params:
|
||||
``id``: 企鹅物流ID,仅数字部分
|
||||
"""
|
||||
self.__dll.AsstSetPenguinId.argtypes = (
|
||||
ctypes.c_void_p, ctypes.c_char_p)
|
||||
return self.__dll.AsstSetPenguinId(self.__ptr, id.encode('utf-8'))
|
||||
|
||||
def get_version(self) -> str:
|
||||
"""
|
||||
获取DLL版本号
|
||||
|
||||
:return: 版本号
|
||||
"""
|
||||
self.__dll.AsstGetVersion.restype = ctypes.c_char_p
|
||||
return self.__dll.AsstGetVersion().decode('utf-8')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@Asst.CallBackType
|
||||
def my_callback(msg, details, arg):
|
||||
d = json.loads(details.decode('gbk'))
|
||||
print(Message(msg), d, arg)
|
||||
|
||||
dirname: str = (pathlib.Path.cwd().parent.parent / 'x64' / 'Release').__str__()
|
||||
asst = Asst(dirname=dirname, callback=my_callback)
|
||||
|
||||
print('version', asst.get_version())
|
||||
|
||||
if asst.catch_default():
|
||||
print('连接成功')
|
||||
else:
|
||||
print('连接失败')
|
||||
os.system.exit()
|
||||
|
||||
# asst.append_fight(0, 0, 1)
|
||||
asst.append_infrast(1, [ "Mfg", "Trade", "Control", "Power", "Reception", "Office", "Dorm"], "Money", 0.3)
|
||||
# asst.append_award()
|
||||
asst.start()
|
||||
|
||||
# asst.start_recurit_clac([4, 5, 6], True)
|
||||
|
||||
while True:
|
||||
pass
|
||||
255
src/Python/message.py
Normal file
255
src/Python/message.py
Normal file
@@ -0,0 +1,255 @@
|
||||
from enum import Enum, unique, auto
|
||||
|
||||
|
||||
|
||||
@unique
|
||||
class Message(Enum):
|
||||
"""
|
||||
回调消息类型
|
||||
|
||||
注释部分仅展示常用消息的回调JSON格式,完全的回调JSON请参考C++侧实现代码
|
||||
"""
|
||||
|
||||
PtrIsNull = auto()
|
||||
"""
|
||||
指针为空
|
||||
"""
|
||||
|
||||
ImageIsEmpty = auto()
|
||||
"""
|
||||
图像为空
|
||||
"""
|
||||
|
||||
WindowMinimized = auto()
|
||||
"""
|
||||
[已弃用] 窗口被最小化了
|
||||
"""
|
||||
|
||||
InitFaild = auto()
|
||||
"""
|
||||
初始化失败
|
||||
"""
|
||||
|
||||
TaskError = auto()
|
||||
"""
|
||||
任务错误(任务一直出错,retry次数达到上限)
|
||||
"""
|
||||
|
||||
OcrResultError = auto()
|
||||
"""
|
||||
Ocr识别结果错误。公招如果识别的Tags数量不足5个,会报这个错
|
||||
"""
|
||||
|
||||
TaskStart = 1000
|
||||
"""
|
||||
单个原子任务开始
|
||||
"""
|
||||
|
||||
TaskMatched = auto()
|
||||
"""
|
||||
任务匹配成功
|
||||
"""
|
||||
|
||||
ReachedLimit = auto()
|
||||
"""
|
||||
单个原子任务达到次数上限
|
||||
"""
|
||||
|
||||
ReadyToSleep = auto()
|
||||
"""
|
||||
准备开始睡眠
|
||||
"""
|
||||
|
||||
EndOfSleep = auto()
|
||||
"""
|
||||
睡眠结束
|
||||
"""
|
||||
|
||||
AppendProcessTask = auto()
|
||||
"""
|
||||
[已弃用] 新增流程任务,Assistance内部消息,外部不需要处理
|
||||
"""
|
||||
|
||||
AppendTask = auto()
|
||||
"""
|
||||
[已弃用] 新增任务,Assistance内部消息,外部不需要处理
|
||||
"""
|
||||
|
||||
TaskCompleted = auto()
|
||||
"""
|
||||
单个原子任务完成
|
||||
|
||||
:Json格式:
|
||||
{ "name": string, "type": int, "exec_time": int, "max_times": int, "task_type" : string, "algorithm" : int}
|
||||
|
||||
:字段解释:
|
||||
``name`` 任务名
|
||||
:常见值:
|
||||
``StartButton2`` 开始行动(橙色按钮)
|
||||
``MedicineConfirm`` 使用理智药
|
||||
``StoneConfirm`` 使用源石
|
||||
``RecruitRefresh`` 公招刷新标签
|
||||
|
||||
``type`` 操作类型
|
||||
|
||||
``exec_times`` 已执行次数
|
||||
|
||||
``max_times`` 最大执行次数
|
||||
|
||||
``task_type`` 任务类型
|
||||
|
||||
``algorithm`` 算法类型
|
||||
"""
|
||||
|
||||
PrintWindow = auto()
|
||||
"""
|
||||
截图消息
|
||||
"""
|
||||
|
||||
ProcessTaskStopAction = auto()
|
||||
"""
|
||||
流程任务执行到了Stop的动作
|
||||
"""
|
||||
|
||||
TaskChainCompleted = auto()
|
||||
"""
|
||||
任务链完成
|
||||
|
||||
:Json格式:
|
||||
{ "task_chain": string }
|
||||
|
||||
:字段解释:
|
||||
``task_chain`` 任务链名称
|
||||
"""
|
||||
|
||||
ProcessTaskNotMatched = auto()
|
||||
"""
|
||||
流程任务识别错误
|
||||
"""
|
||||
|
||||
AllTasksCompleted = auto()
|
||||
"""
|
||||
所有任务完成
|
||||
|
||||
:Json格式:
|
||||
null
|
||||
"""
|
||||
|
||||
TaskChainStart = auto()
|
||||
"""
|
||||
开始任务链
|
||||
|
||||
:Json格式:
|
||||
{ "task_chain": string }
|
||||
:字段解释:
|
||||
``task_chain`` 任务链名称
|
||||
:常见值:
|
||||
"Fight" 刷理智
|
||||
"Award" 领取每日奖励
|
||||
"Visit" 访问好友
|
||||
"Mall" 信用商店
|
||||
"Infrast" 基建
|
||||
"Recruit" 自动公招
|
||||
"RecruitCalc" 公招计算
|
||||
"""
|
||||
|
||||
TextDetected = 2000
|
||||
"""
|
||||
识别到文字
|
||||
"""
|
||||
|
||||
ImageFindResult = auto()
|
||||
"""
|
||||
查找图像的结果
|
||||
"""
|
||||
|
||||
ImageMatched = auto()
|
||||
"""
|
||||
图像匹配成功
|
||||
"""
|
||||
|
||||
StageDrops = auto()
|
||||
"""
|
||||
关卡掉落信息
|
||||
|
||||
:Json格式:
|
||||
{"exceptions":[],"resultLabel":true,"drops":[{"dropType":"NORMAL_DROP","itemId":"2002","quantity":1,"itemName":"初级作战记录"},{"dropType":"NORMAL_DROP","itemId":"2003","quantity":1,"itemName":"中级作战记录"},{"dropType":"NORMAL_DROP","itemId":"2004","quantity":3,"itemName":"高级作战记录"}],"dropTypes":[{"dropTypes":"LMB"},{"dropTypes":"NORMAL_DROP"}],"stage":{"stageCode":"LS-5","stageId":"wk_kc_5"},"stars":3,"fingerprint":"598b253d3b24247b756f39202052375138233b75653c2a575a111f59462a2d413c092e50421a1731ff0c07b07809070e131715bfad4a44300a1c0e0a5d0b620c","md5":"43084d95fcf1c0a0cce3fdeab8c41334","cost":33.7536,"statistics":[{"itemId":"2004","itemName":"高级作战记录","count":15},{"itemId":"2002","itemName":"初级作战记录","count":5},{"itemId":"2003","itemName":"中级作战记录","count":5}]}
|
||||
|
||||
:字段解释:
|
||||
``drops`` 当次掉落
|
||||
``statistics`` 掉落统计
|
||||
"""
|
||||
|
||||
RecruitTagsDetected = 3000
|
||||
"""
|
||||
公招识别到了Tags
|
||||
|
||||
:Json格式:
|
||||
{"tags":["近卫干员","狙击干员","医疗干员","新手","输出"]}
|
||||
"""
|
||||
|
||||
RecruitSpecialTag = auto()
|
||||
"""
|
||||
公招识别到了特殊的Tag
|
||||
|
||||
:Json格式:
|
||||
{ "tag": string}
|
||||
|
||||
字段解释
|
||||
``tag`` 特殊Tag
|
||||
:常见值:
|
||||
"高级资深干员"
|
||||
"支援机械"
|
||||
"""
|
||||
|
||||
RecruitResult = auto()
|
||||
"""
|
||||
公开招募结果
|
||||
|
||||
:Json格式:
|
||||
{"result":[{"tags":["近卫干员","群攻"],"tag_level":3,"opers":[{"name":"幽灵鲨","level":5},{"name":"布洛卡","level":5},{"name":"艾丝黛尔","level":4},{"name":"泡普卡","level":3}]},{"tags":["群攻"],"tag_level":3,"opers":[{"name":"陨星","level":5},{"name":"送葬人","level":5},{"name":"幽灵鲨","level":5},{"name":"布洛卡","level":5},{"name":"远山","level":4},{"name":"格雷伊","level":4},{"name":"白雪","level":4},{"name":"艾丝黛尔","level":4},{"name":"泡普卡","level":3},{"name":"炎熔","level":3},{"name":"空爆","level":3}]},{"tags":["费用回复"],"tag_level":3,"opers":[{"name":"德克萨斯","level":5},{"name":"凛冬","level":5},{"name":"苇草","level":5},{"name":"清道夫","level":4},{"name":"红豆","level":4},{"name":"桃金娘","level":4},{"name":"翎羽","level":3},{"name":"香草","level":3},{"name":"芬","level":3}]},{"tags":["近卫干员"],"tag_level":3,"opers":[{"name":"诗怀雅","level":5},{"name":"星极","level":5},{"name":"因陀罗","level":5},{"name":"幽灵鲨","level":5},{"name":"布洛卡","level":5},{"name":"猎蜂","level":4},{"name":"杜宾","level":4},{"name":"艾丝黛尔","level":4},{"name":"慕斯","level":4},{"name":"霜叶","level":4},{"name":"缠丸","level":4},{"name":"泡普卡","level":3},{"name":"玫兰莎","level":3},{"name":"月见夜","level":3},{"name":"Castle-3","level":1}]},{"tags":["术师干员"],"tag_level":3,"opers":[{"name":"夜魔","level":5},{"name":"远山","level":4},{"name":"格雷伊","level":4},{"name":"夜烟","level":4},{"name":"史都华德","level":3},{"name":"炎熔","level":3},{"name":"12F","level":2},{"name":"杜林","level":2}]},{"tags":["术师干员","群攻"],"tag_level":3,"opers":[{"name":"远山","level":4},{"name":"格雷伊","level":4},{"name":"炎熔","level":3}]},{"tags":["新手"],"tag_level":2,"opers":[{"name":"黑角","level":2},{"name":"巡林者","level":2},{"name":"12F","level":2},{"name":"杜林","level":2},{"name":"夜刀","level":2}]},{"tags":["新手","术师干员"],"tag_level":2,"opers":[{"name":"12F","level":2},{"name":"杜林","level":2}]}],"maybe_level":3}
|
||||
|
||||
:字段解释:
|
||||
``result`` 识别结果
|
||||
``maybe_level`` 可能出的等级
|
||||
"""
|
||||
|
||||
RecruitSelected = auto()
|
||||
"""
|
||||
选择了Tags
|
||||
|
||||
:Json格式:
|
||||
{"tags":["术师干员","减速"]}
|
||||
"""
|
||||
|
||||
InfrastSkillsDetected = 4000
|
||||
"""
|
||||
识别到了基建技能(当前页面)
|
||||
"""
|
||||
|
||||
InfrastSkillsResult = auto()
|
||||
"""
|
||||
识别到的所有可用技能
|
||||
"""
|
||||
|
||||
InfrastComb = auto()
|
||||
"""
|
||||
当前房间的最优干员组合
|
||||
"""
|
||||
|
||||
EnterFacility = auto()
|
||||
"""
|
||||
进入某个房间
|
||||
|
||||
:Json格式:
|
||||
{ "facility": string, "index": int }
|
||||
:字段解释:
|
||||
``facility`` 房间名
|
||||
``index`` 第几个该类房间
|
||||
"""
|
||||
|
||||
#
|
||||
FacilityInfo = auto()
|
||||
"""
|
||||
当前设施信息
|
||||
"""
|
||||
@@ -1,14 +1,27 @@
|
||||
#include "AsstCaller.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
const char* get_cur_dir()
|
||||
{
|
||||
char exepath_buff[_MAX_PATH] = { 0 };
|
||||
::GetModuleFileNameA(NULL, exepath_buff, _MAX_PATH);
|
||||
std::string exepath(exepath_buff);
|
||||
std::string cur_dir = exepath.substr(0, exepath.find_last_of('\\') + 1);
|
||||
return cur_dir.c_str();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
void* ptr = AsstCreate();
|
||||
void* ptr = AsstCreate(get_cur_dir());
|
||||
auto ret = AsstCatchEmulator(ptr);
|
||||
if (!ret) {
|
||||
getchar();
|
||||
if (ptr) {
|
||||
AsstDestory(ptr);
|
||||
AsstDestroy(ptr);
|
||||
ptr = nullptr;
|
||||
}
|
||||
return -1;
|
||||
@@ -39,7 +52,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
AsstDestory(ptr);
|
||||
AsstDestroy(ptr);
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user