mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
Merge branch 'dev'
This commit is contained in:
@@ -89,11 +89,11 @@ A game assistance for Arknights
|
||||
|
||||
#### MuMu模拟器
|
||||
|
||||
支持
|
||||
完美支持
|
||||
|
||||
#### 雷电模拟器
|
||||
|
||||
勉强支持,偶尔能用偶尔用不了,莫名其妙的,有空再修,暂时不建议用_(:з」∠)_
|
||||
支持
|
||||
|
||||
#### 逍遥模拟器
|
||||
|
||||
|
||||
@@ -72,14 +72,14 @@
|
||||
"screencap": "[Adb] -s 127.0.0.1:7555 exec-out screencap -p"
|
||||
}
|
||||
},
|
||||
"LDPlayer": {
|
||||
"LDPlayerLocal": {
|
||||
"handle": {
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
"window": ""
|
||||
},
|
||||
"adb": {
|
||||
"path": "[EmulatorPath]adb.exe",
|
||||
"connect": "[Adb] connect 127.0.0.1:5555",
|
||||
"connect": "[Adb] devices",
|
||||
"click": "[Adb] -s emulator-5554 shell input tap [x] [y]",
|
||||
"swipe": "[Adb] -s emulator-5554 shell input swipe [x1] [y1] [x2] [y2] [duration]",
|
||||
"display": "[Adb] -s emulator-5554 shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
@@ -87,19 +87,19 @@
|
||||
"screencap": "[Adb] -s emulator-5554 shell screencap -p"
|
||||
}
|
||||
},
|
||||
"LDPlayer64": {
|
||||
"LDPlayerRemote": {
|
||||
"handle": {
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器(64)"
|
||||
"window": ""
|
||||
},
|
||||
"adb": {
|
||||
"path": "[EmulatorPath]adb.exe",
|
||||
"connect": "[Adb] connect 127.0.0.1:5555",
|
||||
"click": "[Adb] -s emulator-5554 shell input tap [x] [y]",
|
||||
"swipe": "[Adb] -s emulator-5554 shell input swipe [x1] [y1] [x2] [y2] [duration]",
|
||||
"display": "[Adb] -s emulator-5554 shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"click": "[Adb] -s 127.0.0.1:5555 shell input tap [x] [y]",
|
||||
"swipe": "[Adb] -s 127.0.0.1:5555 shell input swipe [x1] [y1] [x2] [y2] [duration]",
|
||||
"display": "[Adb] -s 127.0.0.1:5555 shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"displayRegex": "cur=%dx%d",
|
||||
"screencap": "[Adb] -s emulator-5554 shell screencap -p"
|
||||
"screencap": "[Adb] -s 127.0.0.1:5555 shell screencap -p"
|
||||
}
|
||||
},
|
||||
"Nox": {
|
||||
@@ -117,6 +117,21 @@
|
||||
"screencap": "[Adb] -s 127.0.0.1:62001 exec-out screencap -p"
|
||||
}
|
||||
},
|
||||
"NoxPort2": {
|
||||
"handle": {
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
},
|
||||
"adb": {
|
||||
"path": "[EmulatorPath]nox_adb.exe",
|
||||
"connect": "[Adb] connect 127.0.0.1:59865",
|
||||
"click": "[Adb] -s 127.0.0.1:59865 shell input tap [x] [y]",
|
||||
"swipe": "[Adb] -s 127.0.0.1:59865 shell input swipe [x1] [y1] [x2] [y2] [duration]",
|
||||
"display": "[Adb] -s 127.0.0.1:59865 shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"displayRegex": "cur=%dx%d",
|
||||
"screencap": "[Adb] -s 127.0.0.1:59865 exec-out screencap -p"
|
||||
}
|
||||
},
|
||||
"XYAZ": {
|
||||
"handle": {
|
||||
"class": "Qt5QWindowIcon",
|
||||
@@ -158,11 +173,11 @@
|
||||
"Doc": "USB连接暂时不兼容多设备的情况",
|
||||
"path": "[ExecDir]platform-tools\\adb.exe",
|
||||
"connect": "[Adb] devices",
|
||||
"click": "[Adb] shell input tap [x] [y]",
|
||||
"swipe": "[Adb] shell input swipe [x1] [y1] [x2] [y2] [duration]",
|
||||
"display": "[Adb] shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"click": "[Adb] -d shell input tap [x] [y]",
|
||||
"swipe": "[Adb] -d shell input swipe [x1] [y1] [x2] [y2] [duration]",
|
||||
"display": "[Adb] -d shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"displayRegex": "cur=%dx%d",
|
||||
"screencap": "[Adb] exec-out screencap -p"
|
||||
"screencap": "[Adb] -d exec-out screencap -p"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1250,18 +1250,19 @@
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastOperSelected": {
|
||||
"template": "OperSelected.png",
|
||||
"template": "empty.png",
|
||||
"cache": false,
|
||||
"templThreshold": 0.35,
|
||||
"templThreshold": 8000,
|
||||
"templThreshold_Doc": "这个任务中作为符合range的像素点数量阈值",
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
95,
|
||||
105
|
||||
],
|
||||
"rectMove": [
|
||||
0,
|
||||
-252,
|
||||
-230,
|
||||
74,
|
||||
320
|
||||
283
|
||||
]
|
||||
},
|
||||
"InfrastOperOnShift": {
|
||||
@@ -1278,63 +1279,84 @@
|
||||
"InfrastClueVacancyNo1": {
|
||||
"template": "ClueVacancyNo1.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
0,
|
||||
100,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastClueVacancyNo2": {
|
||||
"template": "ClueVacancyNo2.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
200,
|
||||
200,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastClueVacancyNo3": {
|
||||
"template": "ClueVacancyNo3.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
400,
|
||||
100,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastClueVacancyNo4": {
|
||||
"template": "ClueVacancyNo4.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
650,
|
||||
150,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastClueVacancyNo5": {
|
||||
"template": "ClueVacancyNo5.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
300,
|
||||
420,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastClueVacancyNo6": {
|
||||
"template": "ClueVacancyNo6.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
500,
|
||||
350,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
"InfrastClueVacancyNo7": {
|
||||
"template": "ClueVacancyNo7.png",
|
||||
"cache": false,
|
||||
"maskRange": [
|
||||
180,
|
||||
255
|
||||
"templThreshold": 0.75,
|
||||
"roi": [
|
||||
50,
|
||||
350,
|
||||
500,
|
||||
250
|
||||
],
|
||||
"rearDelay": 1000
|
||||
},
|
||||
@@ -1344,6 +1366,12 @@
|
||||
"maskRange": [
|
||||
1,
|
||||
255
|
||||
],
|
||||
"roi": [
|
||||
800,
|
||||
0,
|
||||
480,
|
||||
720
|
||||
]
|
||||
},
|
||||
"InfrastClueOnTheRightSwipeBegin": {
|
||||
@@ -1355,8 +1383,8 @@
|
||||
300,
|
||||
100
|
||||
],
|
||||
"preDelay": 1000,
|
||||
"rearDelay": 1000,
|
||||
"preDelay": 500,
|
||||
"rearDelay": 500,
|
||||
"maxTimes": 1,
|
||||
"Doc": "这里的preDelay作为滑动duration使用,rearDelay作为滑动额外延时使用,maxTimes作为重复次数使用"
|
||||
},
|
||||
@@ -1423,6 +1451,6 @@
|
||||
"template": "UnlockClues.png",
|
||||
"action": "clickSelf",
|
||||
"cache": false,
|
||||
"rearDelay": 3000
|
||||
"rearDelay": 5000
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ namespace asst {
|
||||
OpersDetected = 4000, // 识别到了干员s
|
||||
OpersIdtfResult, // 干员识别结果(总的)
|
||||
InfrastComb, // 当前房间的最优干员组合
|
||||
EnterStation, // 进入某个房间
|
||||
EnterFacility, // 进入某个房间
|
||||
StationInfo, // 当前房间信息
|
||||
ReadyToShift, // 准备换班
|
||||
ShiftCompleted, // 换班完成(单个房间)
|
||||
@@ -80,7 +80,7 @@ namespace asst {
|
||||
{AsstMsg::OpersDetected, "OpersDetected"},
|
||||
{AsstMsg::OpersIdtfResult, "OpersIdtfResult"},
|
||||
{AsstMsg::InfrastComb, "InfrastComb"},
|
||||
{AsstMsg::EnterStation, "EnterStation"},
|
||||
{AsstMsg::EnterFacility, "EnterFacility"},
|
||||
{AsstMsg::StationInfo, "StationInfo"},
|
||||
{AsstMsg::ReadyToShift, "ReadyToShift"},
|
||||
{AsstMsg::ShiftCompleted, "ShiftCompleted"},
|
||||
|
||||
@@ -121,7 +121,7 @@ void asst::Controller::pipe_working_proc()
|
||||
|
||||
bool Controller::try_capture(const EmulatorInfo& info, bool without_handle)
|
||||
{
|
||||
LogTraceFunction;
|
||||
LogTraceScope("try_capture | " + info.name);
|
||||
|
||||
const HandleInfo& handle_info = info.handle;
|
||||
std::string adb_dir;
|
||||
@@ -554,9 +554,15 @@ int asst::Controller::swipe_without_scale(const Rect& r1, const Rect& r2, int du
|
||||
|
||||
cv::Mat asst::Controller::get_image(bool raw)
|
||||
{
|
||||
static bool has_successful = false;
|
||||
if (!screencap()) {
|
||||
return cv::Mat();
|
||||
// 如果之前成功截图过,这次没成功可能是一次意外,重试一次
|
||||
// 点名批评雷电模拟器!
|
||||
if (!(has_successful && screencap())) {
|
||||
return cv::Mat();
|
||||
}
|
||||
}
|
||||
has_successful = true;
|
||||
//std::shared_lock<std::shared_mutex> image_lock(m_image_mutex);
|
||||
if (raw) {
|
||||
return m_cache_image;
|
||||
|
||||
@@ -5,18 +5,29 @@
|
||||
#include "InfrastFacilityImageAnalyzer.h"
|
||||
#include "Controller.h"
|
||||
#include "Resource.h"
|
||||
#include "Logger.hpp"
|
||||
#include "AsstMsg.h"
|
||||
|
||||
bool asst::InfrastAbstractTask::enter_facility(const std::string& facility, int index)
|
||||
{
|
||||
LogTraceFunction;
|
||||
json::value enter_json = json::object{
|
||||
{ "facility", facility },
|
||||
{ "index", index}
|
||||
};
|
||||
m_callback(AsstMsg::EnterFacility, enter_json, m_callback_arg);
|
||||
|
||||
const auto& image = ctrler.get_image();
|
||||
|
||||
InfrastFacilityImageAnalyzer analyzer(image);
|
||||
analyzer.set_to_be_analyzed({ facility });
|
||||
if (!analyzer.analyze()) {
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -30,6 +41,8 @@ bool asst::InfrastAbstractTask::enter_facility(const std::string& facility, int
|
||||
|
||||
bool asst::InfrastAbstractTask::enter_oper_list_page()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
auto image = ctrler.get_image();
|
||||
|
||||
// 识别右边的“进驻”按钮
|
||||
@@ -40,25 +53,30 @@ bool asst::InfrastAbstractTask::enter_oper_list_page()
|
||||
|
||||
// 如果没找到,说明“进驻信息”这个按钮没有被点开,那就点开它
|
||||
if (!enter_analyzer.analyze()) {
|
||||
log.trace("ready to analyze the stationed info button");
|
||||
OcrImageAnalyzer station_analyzer(image);
|
||||
|
||||
const auto stationedinfo_task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
|
||||
resource.task().task_ptr("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);
|
||||
sleep(stationedinfo_task_ptr->rear_delay);
|
||||
// 点开了按钮之后,再识别一次右边的
|
||||
image = ctrler.get_image();
|
||||
enter_analyzer.set_image(image);
|
||||
if (!enter_analyzer.analyze()) {
|
||||
log.error("no enterlist button");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.error("no stationed info button");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
log.trace("ready to click the enterlist button");
|
||||
ctrler.click(enter_analyzer.get_result().front().rect);
|
||||
sleep(enter_task_ptr->rear_delay);
|
||||
|
||||
@@ -67,6 +85,7 @@ bool asst::InfrastAbstractTask::enter_oper_list_page()
|
||||
|
||||
void asst::InfrastAbstractTask::async_swipe_of_operlist(bool reverse)
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect begin_rect = resource.task().task_ptr("InfrastOperListSwipeBegin")->specific_rect;
|
||||
static Rect end_rect = resource.task().task_ptr("InfrastOperListSwipeEnd")->specific_rect;
|
||||
static int duration = resource.task().task_ptr("InfrastOperListSwipeBegin")->pre_delay;
|
||||
@@ -81,6 +100,7 @@ void asst::InfrastAbstractTask::async_swipe_of_operlist(bool reverse)
|
||||
|
||||
void asst::InfrastAbstractTask::await_swipe()
|
||||
{
|
||||
LogTraceFunction;
|
||||
static int extra_delay = resource.task().task_ptr("InfrastOperListSwipeBegin")->rear_delay;
|
||||
|
||||
ctrler.wait(m_last_swipe_id);
|
||||
@@ -89,6 +109,7 @@ void asst::InfrastAbstractTask::await_swipe()
|
||||
|
||||
bool asst::InfrastAbstractTask::click_bottomleft_tab()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto task_ptr = resource.task().task_ptr("InfrastBottomLeftTab");
|
||||
ctrler.click(task_ptr->specific_rect);
|
||||
sleep(task_ptr->rear_delay);
|
||||
@@ -97,6 +118,7 @@ bool asst::InfrastAbstractTask::click_bottomleft_tab()
|
||||
|
||||
bool asst::InfrastAbstractTask::click_clear_button()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto task_ptr = resource.task().task_ptr("InfrastClearButton");
|
||||
ctrler.click(task_ptr->specific_rect);
|
||||
sleep(task_ptr->rear_delay);
|
||||
@@ -105,6 +127,7 @@ bool asst::InfrastAbstractTask::click_clear_button()
|
||||
|
||||
bool asst::InfrastAbstractTask::click_confirm_button()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
|
||||
resource.task().task_ptr("InfrastConfirmButton"));
|
||||
ctrler.click(task_ptr->specific_rect);
|
||||
@@ -114,6 +137,9 @@ bool asst::InfrastAbstractTask::click_confirm_button()
|
||||
OcrImageAnalyzer analyzer;
|
||||
analyzer.set_task_info(*task_ptr);
|
||||
for (int i = 0; i != m_retry_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto& image = ctrler.get_image();
|
||||
analyzer.set_image(image);
|
||||
if (!analyzer.analyze()) {
|
||||
@@ -133,6 +159,7 @@ void asst::InfrastAbstractTask::sync_swipe_of_operlist(bool reverse)
|
||||
|
||||
void asst::InfrastAbstractTask::swipe_to_the_left_of_operlist()
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect begin_rect = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->specific_rect;
|
||||
static Rect end_rect = resource.task().task_ptr("InfrastOperListSwipeToTheLeftEnd")->specific_rect;
|
||||
static int duration = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->pre_delay;
|
||||
@@ -140,6 +167,9 @@ void asst::InfrastAbstractTask::swipe_to_the_left_of_operlist()
|
||||
static int loop_times = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->max_times;
|
||||
|
||||
for (int i = 0; i != loop_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return;
|
||||
}
|
||||
ctrler.swipe(end_rect, begin_rect, duration, true, 0, false);
|
||||
}
|
||||
sleep(extra_delay);
|
||||
@@ -147,6 +177,7 @@ void asst::InfrastAbstractTask::swipe_to_the_left_of_operlist()
|
||||
|
||||
void asst::InfrastAbstractTask::swipe_to_the_left_of_main_ui()
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect begin_rect = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->specific_rect;
|
||||
static Rect end_rect = resource.task().task_ptr("InfrastOperListSwipeToTheLeftEnd")->specific_rect;
|
||||
static int duration = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->pre_delay;
|
||||
@@ -157,6 +188,7 @@ void asst::InfrastAbstractTask::swipe_to_the_left_of_main_ui()
|
||||
|
||||
void asst::InfrastAbstractTask::swipe_to_the_right_of_main_ui()
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect begin_rect = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->specific_rect;
|
||||
static Rect end_rect = resource.task().task_ptr("InfrastOperListSwipeToTheLeftEnd")->specific_rect;
|
||||
static int duration = resource.task().task_ptr("InfrastOperListSwipeToTheLeftBegin")->pre_delay;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
bool asst::InfrastClueVacancyImageAnalyzer::analyze()
|
||||
{
|
||||
@@ -14,9 +15,11 @@ bool asst::InfrastClueVacancyImageAnalyzer::analyze()
|
||||
resource.task().task_ptr(clue_vacancy + suffix));
|
||||
analyzer.set_task_info(*task_ptr);
|
||||
if (!analyzer.analyze()) {
|
||||
log.trace("no", clue_vacancy, suffix);
|
||||
continue;
|
||||
}
|
||||
Rect rect = analyzer.get_result().rect;
|
||||
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);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "InfrastMoodImageAnalyzer.h"
|
||||
#include "Resource.h"
|
||||
#include "Controller.h"
|
||||
#include "Logger.hpp"
|
||||
|
||||
const std::string asst::InfrastDormTask::FacilityName = "Dorm";
|
||||
|
||||
@@ -17,6 +18,9 @@ bool asst::InfrastDormTask::run()
|
||||
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
|
||||
|
||||
for (; m_cur_dorm_index < m_max_num_of_dorm; ++m_cur_dorm_index) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
enter_facility(FacilityName, m_cur_dorm_index);
|
||||
if (!enter_oper_list_page()) {
|
||||
return false;
|
||||
@@ -26,9 +30,13 @@ bool asst::InfrastDormTask::run()
|
||||
|
||||
int quantity_selected = 0;
|
||||
while (quantity_selected < MaxNumOfOpers) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto& image = ctrler.get_image();
|
||||
InfrastMoodImageAnalyzer mood_analyzer(image);
|
||||
if (!mood_analyzer.analyze()) {
|
||||
log.error("mood analyze faild!");
|
||||
return false;
|
||||
}
|
||||
mood_analyzer.sort_result();
|
||||
@@ -36,7 +44,11 @@ bool asst::InfrastDormTask::run()
|
||||
|
||||
int quantity_resting = 0;
|
||||
for (const auto& mood_info : mood_result) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
if (quantity_selected >= MaxNumOfOpers) {
|
||||
log.trace("quantity_selected:", quantity_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
switch (mood_info.smiley.type)
|
||||
@@ -44,6 +56,7 @@ bool asst::InfrastDormTask::run()
|
||||
case InfrastSmileyType::Rest:
|
||||
// 如果当前页面休息完成的人数超过5个,说明已经已经把所有心情不满的滑过一遍、没有更多的了,直接退出即可
|
||||
if (++quantity_resting > MaxNumOfOpers) {
|
||||
log.trace("quantity_resting:", quantity_resting, ", confirm");
|
||||
click_confirm_button();
|
||||
return true;
|
||||
}
|
||||
@@ -57,6 +70,7 @@ bool asst::InfrastDormTask::run()
|
||||
{
|
||||
ctrler.click(mood_info.rect);
|
||||
if (++quantity_selected >= MaxNumOfOpers) {
|
||||
log.trace("quantity_selected:", quantity_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -66,6 +80,7 @@ bool asst::InfrastDormTask::run()
|
||||
}
|
||||
}
|
||||
if (quantity_selected >= MaxNumOfOpers) {
|
||||
log.trace("quantity_selected:", quantity_selected, ", just break");
|
||||
break;
|
||||
}
|
||||
sync_swipe_of_operlist();
|
||||
@@ -78,6 +93,8 @@ bool asst::InfrastDormTask::run()
|
||||
|
||||
bool asst::InfrastDormTask::click_confirm_button()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
const auto task_ptr = std::dynamic_pointer_cast<OcrTaskInfo>(
|
||||
resource.task().task_ptr("InfrastConfirmButton"));
|
||||
ctrler.click(task_ptr->specific_rect);
|
||||
@@ -98,6 +115,9 @@ bool asst::InfrastDormTask::click_confirm_button()
|
||||
OcrImageAnalyzer analyzer;
|
||||
analyzer.set_task_info(*task_ptr);
|
||||
for (int i = 0; i != m_retry_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto& image = ctrler.get_image();
|
||||
analyzer.set_image(image);
|
||||
if (!analyzer.analyze()) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Resource.h"
|
||||
#include "MultiMatchImageAnalyzer.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
bool asst::InfrastFacilityImageAnalyzer::analyze()
|
||||
{
|
||||
@@ -32,13 +33,13 @@ bool asst::InfrastFacilityImageAnalyzer::analyze()
|
||||
|
||||
int cor_suffix_index = -1;
|
||||
|
||||
for (const auto& [key, task_name] : facility_task_name) {
|
||||
if (!m_to_be_analyzed.empty()) { // 若为空,则分析所有设施
|
||||
if (std::find(m_to_be_analyzed.cbegin(), m_to_be_analyzed.cend(), key)
|
||||
== m_to_be_analyzed.cend()) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
std::string task_name = find_iter->second;
|
||||
std::vector<MatchRect> cur_facility_result;
|
||||
// 已知基建缩放状态的时候,只识别这个缩放状态下的就行了
|
||||
// 否则识别所有状态,直到找出正确的当前缩放状态
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace asst {
|
||||
|
||||
virtual bool analyze() override;
|
||||
|
||||
// 若为空,则分析所有设施
|
||||
void set_to_be_analyzed(std::vector<std::string> facilities) noexcept {
|
||||
m_to_be_analyzed = std::move(facilities);
|
||||
}
|
||||
@@ -53,7 +52,7 @@ namespace asst {
|
||||
|
||||
// key:设施名,value:所有这种设施的当前Rect(例如所有制造站的位置)
|
||||
std::unordered_map<std::string, std::vector<MatchRect>> m_result;
|
||||
// 需要识别的设施名,若为空,则分析所有设施
|
||||
// 需要识别的设施名
|
||||
std::vector<std::string> m_to_be_analyzed;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,10 +17,7 @@ bool asst::InfrastInfoTask::run()
|
||||
const auto& image = ctrler.get_image();
|
||||
|
||||
InfrastFacilityImageAnalyzer analyzer(image);
|
||||
std::vector<std::string> all_facilities;
|
||||
for (auto&& [key, _value] : resource.infrast().get_facility_info()) {
|
||||
all_facilities.emplace_back(key);
|
||||
}
|
||||
analyzer.set_to_be_analyzed({ "Mfg", "Trade", "Power" });
|
||||
if (!analyzer.analyze()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,15 +4,24 @@
|
||||
#include "InfrastSmileyImageAnalyzer.h"
|
||||
#include "MatchImageAnalyzer.h"
|
||||
#include "AsstUtils.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
bool asst::InfrastMoodImageAnalyzer::analyze()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
mood_detect();
|
||||
mood_analyze();
|
||||
hash_calc();
|
||||
selected_analyze();
|
||||
working_analyze();
|
||||
|
||||
for (auto&& info : m_result) {
|
||||
log.trace(info.hash, info.rect.to_string(),
|
||||
"smiley:", (int)info.smiley.type, "mood:", info.percentage,
|
||||
"selected:", info.selected, "working:", info.working);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -186,20 +195,32 @@ bool asst::InfrastMoodImageAnalyzer::selected_analyze()
|
||||
resource.task().task_ptr("InfrastOperSelected"));
|
||||
Rect rect_move = selected_task_ptr->rect_move;
|
||||
|
||||
MatchImageAnalyzer selected_analyzer(m_image);
|
||||
selected_analyzer.set_task_info(*selected_task_ptr);
|
||||
|
||||
for (auto&& info : m_result) {
|
||||
Rect selected_rect = rect_move;
|
||||
cv::Rect selected_rect = utils::make_rect<cv::Rect>(rect_move);
|
||||
selected_rect.x += info.smiley.rect.x;
|
||||
selected_rect.y += info.smiley.rect.y;
|
||||
selected_analyzer.set_roi(selected_rect);
|
||||
if (selected_analyzer.analyze()) {
|
||||
info.selected = true;
|
||||
#ifdef LOG_TRACE
|
||||
cv::putText(m_image_draw, "SELECTED", cv::Point(selected_rect.x, selected_rect.y + 50), 1, 1, cv::Scalar(0, 0, 255), 2);
|
||||
#endif
|
||||
|
||||
cv::Mat roi = m_image(selected_rect);
|
||||
cv::Mat hsv, bin;
|
||||
cv::cvtColor(roi, hsv, cv::COLOR_BGR2HSV);
|
||||
std::vector<cv::Mat> channels;
|
||||
cv::split(hsv, channels);
|
||||
int mask_lowb = selected_task_ptr->mask_range.first;
|
||||
int mask_uppb = selected_task_ptr->mask_range.second;
|
||||
|
||||
int count = 0;
|
||||
auto& h_channel = channels.at(0);
|
||||
for (int i = 0; i != h_channel.rows; ++i) {
|
||||
for (int j = 0; j != h_channel.cols; ++j) {
|
||||
cv::uint8_t value = h_channel.at<cv::uint8_t>(i, j);
|
||||
if (mask_lowb < value
|
||||
&& value < mask_uppb) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.trace("selected_analyze |", count);
|
||||
info.selected = count >= selected_task_ptr->templ_threshold;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ bool asst::InfrastOfficeTask::run()
|
||||
|
||||
constexpr int retry_times = 1;
|
||||
for (int i = 0; i <= retry_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
swipe_to_the_left_of_operlist();
|
||||
opers_detect_with_swipe();
|
||||
swipe_to_the_left_of_operlist();
|
||||
|
||||
@@ -17,6 +17,9 @@ bool asst::InfrastPowerTask::run()
|
||||
set_product("Drone");
|
||||
|
||||
for (int i = 0; i != MaxNumOfFacility; ++i) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
swipe_to_the_left_of_main_ui();
|
||||
enter_facility(FacilityName, i);
|
||||
|
||||
|
||||
@@ -35,8 +35,11 @@
|
||||
|
||||
bool asst::InfrastProductionTask::shift_facility_list()
|
||||
{
|
||||
LogTraceFunction;
|
||||
facility_list_detect();
|
||||
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto tab_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
resource.task().task_ptr("InfrastFacilityListTab" + m_facility));
|
||||
MatchImageAnalyzer add_analyzer;
|
||||
@@ -45,6 +48,9 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
add_analyzer.set_task_info(*add_task_ptr);
|
||||
|
||||
for (const Rect& tab : m_facility_list_tabs) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
ctrler.click(tab);
|
||||
sleep(tab_task_ptr->rear_delay);
|
||||
|
||||
@@ -52,6 +58,7 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
const auto& image = ctrler.get_image();
|
||||
add_analyzer.set_image(image);
|
||||
if (!add_analyzer.analyze()) {
|
||||
log.info("no add button, just continue");
|
||||
continue;
|
||||
}
|
||||
Rect add_button = add_analyzer.get_result().rect;
|
||||
@@ -71,12 +78,16 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
}
|
||||
}
|
||||
set_product(cur_product);
|
||||
log.info("cur product", cur_product);
|
||||
/* 进入干员选择页面 */
|
||||
ctrler.click(add_button);
|
||||
sleep(add_task_ptr->rear_delay);
|
||||
|
||||
constexpr int retry_times = 1;
|
||||
for (int i = 0; i <= retry_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
click_clear_button();
|
||||
swipe_to_the_left_of_operlist();
|
||||
|
||||
@@ -102,11 +113,16 @@ bool asst::InfrastProductionTask::shift_facility_list()
|
||||
|
||||
bool asst::InfrastProductionTask::opers_detect_with_swipe()
|
||||
{
|
||||
LogTraceFunction;
|
||||
m_all_available_opers.clear();
|
||||
|
||||
int first_number = 0;
|
||||
while (true) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
size_t num = opers_detect();
|
||||
log.trace("opers_detect return", num);
|
||||
|
||||
// 这里本来是判断不相等就可以退出循环。
|
||||
// 但是有时候滑动会把一个干员挡住一半,一个页面完整的干员真的只有10个,所以加个2的差值
|
||||
@@ -126,6 +142,7 @@ bool asst::InfrastProductionTask::opers_detect_with_swipe()
|
||||
|
||||
size_t asst::InfrastProductionTask::opers_detect()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto& image = ctrler.get_image();
|
||||
|
||||
InfrastSkillsImageAnalyzer skills_analyzer(image);
|
||||
@@ -176,6 +193,7 @@ size_t asst::InfrastProductionTask::opers_detect()
|
||||
|
||||
bool asst::InfrastProductionTask::optimal_calc()
|
||||
{
|
||||
LogTraceFunction;
|
||||
auto& facility_info = resource.infrast().get_facility_info(m_facility);
|
||||
int max_num_of_opers = facility_info.max_num_of_opers;
|
||||
|
||||
@@ -322,8 +340,12 @@ bool asst::InfrastProductionTask::optimal_calc()
|
||||
|
||||
bool asst::InfrastProductionTask::opers_choose()
|
||||
{
|
||||
LogTraceFunction;
|
||||
bool has_error = false;
|
||||
while (true) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
const auto& image = ctrler.get_image();
|
||||
|
||||
InfrastSkillsImageAnalyzer skills_analyzer(image);
|
||||
@@ -389,6 +411,7 @@ bool asst::InfrastProductionTask::opers_choose()
|
||||
|
||||
bool asst::InfrastProductionTask::facility_list_detect()
|
||||
{
|
||||
LogTraceFunction;
|
||||
m_facility_list_tabs.clear();
|
||||
|
||||
const auto& image = ctrler.get_image();
|
||||
|
||||
@@ -38,8 +38,12 @@ bool asst::InfrastReceptionTask::run()
|
||||
|
||||
bool asst::InfrastReceptionTask::harvest_clue()
|
||||
{
|
||||
LogTraceFunction;
|
||||
std::vector<std::string> tasks_vec = { "InfrastClueNew" };
|
||||
while (!tasks_vec.empty()) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
ProcessTaskImageAnalyzer analyzer(ctrler.get_image(), tasks_vec);
|
||||
if (!analyzer.analyze()) {
|
||||
break;
|
||||
@@ -71,37 +75,15 @@ bool asst::InfrastReceptionTask::harvest_clue()
|
||||
|
||||
bool asst::InfrastReceptionTask::proc_clue()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const static std::string clue_vacancy = "InfrastClueVacancy";
|
||||
const static std::vector<std::string> clue_suffix = {
|
||||
"No1", "No2", "No3", "No4", "No5", "No6", "No7" };
|
||||
|
||||
cv::Mat image;
|
||||
for (const std::string& clue : clue_suffix) {
|
||||
// 先识别线索的空位
|
||||
image = ctrler.get_image();
|
||||
InfrastClueVacancyImageAnalyzer vacancy_analyzer(image);
|
||||
vacancy_analyzer.set_to_be_analyzed({ clue });
|
||||
if (!vacancy_analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
// 点开线索的空位
|
||||
Rect vacancy = vacancy_analyzer.get_vacancy().cbegin()->second;
|
||||
ctrler.click(vacancy);
|
||||
int delay = resource.task().task_ptr(clue_vacancy + clue)->rear_delay;
|
||||
sleep(delay);
|
||||
proc_vacancy();
|
||||
|
||||
// 识别右边列表中的线索,然后用最底下的那个(一般都是剩余时间最短的)
|
||||
swipe_to_the_bottom_of_clue_list_on_the_right();
|
||||
image = ctrler.get_image();
|
||||
InfrastClueImageAnalyzer clue_analyzer(image);
|
||||
if (!clue_analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
ctrler.click(clue_analyzer.get_result().back().first);
|
||||
sleep(delay);
|
||||
}
|
||||
// 开启线索交流,“解锁线索”
|
||||
image = ctrler.get_image();
|
||||
cv::Mat image = ctrler.get_image();
|
||||
MatchImageAnalyzer unlock_analyzer(image);
|
||||
const auto unlock_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
resource.task().task_ptr("UnlockClues"));
|
||||
@@ -110,6 +92,7 @@ bool asst::InfrastReceptionTask::proc_clue()
|
||||
ctrler.click(unlock_analyzer.get_result().rect);
|
||||
sleep(unlock_task_ptr->rear_delay);
|
||||
click_bottomleft_tab();
|
||||
proc_vacancy();
|
||||
image = ctrler.get_image();
|
||||
}
|
||||
|
||||
@@ -136,8 +119,46 @@ bool asst::InfrastReceptionTask::proc_clue()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::InfrastReceptionTask::proc_vacancy()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const static std::string clue_vacancy = "InfrastClueVacancy";
|
||||
const static std::vector<std::string> clue_suffix = {
|
||||
"No1", "No2", "No3", "No4", "No5", "No6", "No7" };
|
||||
|
||||
for (const std::string& clue : clue_suffix) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
// 先识别线索的空位
|
||||
cv::Mat image = ctrler.get_image();
|
||||
InfrastClueVacancyImageAnalyzer vacancy_analyzer(image);
|
||||
vacancy_analyzer.set_to_be_analyzed({ clue });
|
||||
if (!vacancy_analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
// 点开线索的空位
|
||||
Rect vacancy = vacancy_analyzer.get_vacancy().cbegin()->second;
|
||||
ctrler.click(vacancy);
|
||||
int delay = resource.task().task_ptr(clue_vacancy + clue)->rear_delay;
|
||||
sleep(delay);
|
||||
|
||||
// 识别右边列表中的线索,然后用最底下的那个(一般都是剩余时间最短的)
|
||||
swipe_to_the_bottom_of_clue_list_on_the_right();
|
||||
image = ctrler.get_image();
|
||||
InfrastClueImageAnalyzer clue_analyzer(image);
|
||||
if (!clue_analyzer.analyze()) {
|
||||
continue;
|
||||
}
|
||||
ctrler.click(clue_analyzer.get_result().back().first);
|
||||
sleep(delay);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::InfrastReceptionTask::shift()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto& image = ctrler.get_image();
|
||||
MatchImageAnalyzer add_analyzer(image);
|
||||
|
||||
@@ -153,6 +174,9 @@ bool asst::InfrastReceptionTask::shift()
|
||||
|
||||
constexpr int retry_times = 1;
|
||||
for (int i = 0; i <= retry_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
swipe_to_the_left_of_operlist();
|
||||
click_clear_button();
|
||||
|
||||
@@ -173,6 +197,7 @@ bool asst::InfrastReceptionTask::shift()
|
||||
|
||||
bool asst::InfrastReceptionTask::swipe_to_the_bottom_of_clue_list_on_the_right()
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect begin_rect = resource.task().task_ptr("InfrastClueOnTheRightSwipeBegin")->specific_rect;
|
||||
static Rect end_rect = resource.task().task_ptr("InfrastClueOnTheRightSwipeEnd")->specific_rect;
|
||||
static int duration = resource.task().task_ptr("InfrastClueOnTheRightSwipeBegin")->pre_delay;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace asst {
|
||||
private:
|
||||
bool harvest_clue();
|
||||
bool proc_clue();
|
||||
bool proc_vacancy();
|
||||
bool shift();
|
||||
bool swipe_to_the_bottom_of_clue_list_on_the_right();
|
||||
};
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
bool asst::InfrastSkillsImageAnalyzer::analyze()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
m_skills_detected.clear();
|
||||
m_skills_splited.clear();
|
||||
m_result.clear();
|
||||
@@ -18,11 +20,20 @@ bool asst::InfrastSkillsImageAnalyzer::analyze()
|
||||
|
||||
skill_analyze();
|
||||
|
||||
for (auto&& info : m_result) {
|
||||
std::string skill_str;
|
||||
for (auto&& skill : info.skills_comb.skills) {
|
||||
skill_str += skill.names.front() + " ";
|
||||
}
|
||||
log.trace(info.hash, info.rect.to_string(), skill_str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void asst::InfrastSkillsImageAnalyzer::sort_result()
|
||||
{
|
||||
LogTraceFunction;
|
||||
// 按位置排个序
|
||||
std::sort(m_result.begin(), m_result.end(),
|
||||
[](const auto& lhs, const auto& rhs) -> bool {
|
||||
@@ -38,6 +49,7 @@ void asst::InfrastSkillsImageAnalyzer::sort_result()
|
||||
|
||||
bool asst::InfrastSkillsImageAnalyzer::skills_detect()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto upper_task_ptr = resource.task().task_ptr("InfrastSkillsUpper");
|
||||
const auto lower_task_ptr = resource.task().task_ptr("InfrastSkillsLower");
|
||||
const auto hash_task_ptr = resource.task().task_ptr("InfrastSkillsHash");
|
||||
@@ -98,6 +110,7 @@ bool asst::InfrastSkillsImageAnalyzer::skills_detect()
|
||||
|
||||
bool asst::InfrastSkillsImageAnalyzer::skills_split()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
resource.task().task_ptr("InfrastSkills"));
|
||||
const auto thres = task_ptr->hist_threshold;
|
||||
@@ -144,6 +157,7 @@ bool asst::InfrastSkillsImageAnalyzer::skills_split()
|
||||
|
||||
bool asst::InfrastSkillsImageAnalyzer::skill_analyze()
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
resource.task().task_ptr("InfrastSkills"));
|
||||
|
||||
@@ -151,11 +165,6 @@ bool asst::InfrastSkillsImageAnalyzer::skill_analyze()
|
||||
skill_analyzer.set_mask_range(task_ptr->mask_range);
|
||||
skill_analyzer.set_threshold(task_ptr->templ_threshold);
|
||||
|
||||
const auto selected_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
resource.task().task_ptr("InfrastOperSelected"));
|
||||
MatchImageAnalyzer selected_analyzer(m_image);
|
||||
selected_analyzer.set_task_info(*selected_task_ptr);
|
||||
|
||||
for (const auto& [hash, skills_rect_vec] : m_skills_splited) {
|
||||
std::unordered_set<InfrastSkill> skills_set; // 单个干员的全部技能
|
||||
std::string log_str = "[ ";
|
||||
@@ -233,16 +242,7 @@ bool asst::InfrastSkillsImageAnalyzer::skill_analyze()
|
||||
// 识别该干员是否被选中。数据结构设计的不太合理,先这么凑合用了
|
||||
int smiley_x = skills_rect_vec.front().x - task_ptr->rect_move.x;
|
||||
int smiley_y = skills_rect_vec.front().y - task_ptr->rect_move.y;
|
||||
Rect selected_rect = selected_task_ptr->rect_move;
|
||||
selected_rect.x += smiley_x;
|
||||
selected_rect.y += smiley_y;
|
||||
selected_analyzer.set_roi(selected_rect);
|
||||
if (selected_analyzer.analyze()) {
|
||||
info.selected = true;
|
||||
}
|
||||
else {
|
||||
info.selected = false;
|
||||
}
|
||||
info.selected = selected_analyze(smiley_x, smiley_y);
|
||||
|
||||
m_result.emplace_back(std::move(info));
|
||||
}
|
||||
@@ -250,4 +250,40 @@ bool asst::InfrastSkillsImageAnalyzer::skill_analyze()
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool asst::InfrastSkillsImageAnalyzer::selected_analyze(int smiley_x, int smiley_y)
|
||||
{
|
||||
LogTraceFunction;
|
||||
const auto selected_task_ptr = std::dynamic_pointer_cast<MatchTaskInfo>(
|
||||
resource.task().task_ptr("InfrastOperSelected"));
|
||||
cv::Rect selected_rect = utils::make_rect<cv::Rect>(selected_task_ptr->rect_move);
|
||||
selected_rect.x += smiley_x;
|
||||
selected_rect.y += smiley_y;
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
cv::Mat draw = m_image_draw.clone();
|
||||
cv::rectangle(draw, selected_rect, cv::Scalar(0, 0, 255), 2);
|
||||
#endif // LOG_TRACE
|
||||
cv::Mat roi = m_image(selected_rect);
|
||||
cv::Mat hsv, bin;
|
||||
cv::cvtColor(roi, hsv, cv::COLOR_BGR2HSV);
|
||||
std::vector<cv::Mat> channels;
|
||||
cv::split(hsv, channels);
|
||||
int mask_lowb = selected_task_ptr->mask_range.first;
|
||||
int mask_uppb = selected_task_ptr->mask_range.second;
|
||||
|
||||
int count = 0;
|
||||
auto& h_channel = channels.at(0);
|
||||
for (int i = 0; i != h_channel.rows; ++i) {
|
||||
for (int j = 0; j != h_channel.cols; ++j) {
|
||||
cv::uint8_t value = h_channel.at<cv::uint8_t>(i, j);
|
||||
if (mask_lowb < value
|
||||
&& value < mask_uppb) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.trace("selected_analyze |", count);
|
||||
return count >= selected_task_ptr->templ_threshold;
|
||||
}
|
||||
@@ -37,6 +37,7 @@ namespace asst {
|
||||
bool skills_detect(); // 检测出所有技能区域
|
||||
bool skills_split(); // 拆分成一个一个的区域
|
||||
bool skill_analyze(); // 识别每个技能区域是啥
|
||||
bool selected_analyze(int smiley_x, int smiley_y); // 识别干员是否被选中
|
||||
|
||||
std::string m_facility;
|
||||
// skills_detect()的结果,key是hash,value是单个干员的全部技能区域
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace asst {
|
||||
constexpr static const char* Version = "v1.3-alpha.6";
|
||||
constexpr static const char* Version = "v1.3-alpha.7";
|
||||
}
|
||||
2
tools/build_release.bat
Normal file
2
tools/build_release.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
MSBuild.exe ..\MeoAssistance.sln /p:Configuration=Release /p:Platform=x64 /t:Rebuild
|
||||
sh zip_release.sh
|
||||
6
tools/zip_release.sh
Normal file
6
tools/zip_release.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
TargetDir="../x64/Release"
|
||||
LatestTag=$(git describe --tags $(git rev-list --tags --max-count=1))
|
||||
Package="../x64/MeoAssistance_"$LatestTag".zip"
|
||||
|
||||
cp ./*.url $TargetDir
|
||||
7z.exe a $Package $TargetDir/resource $TargetDir/*.dll $TargetDir/MeoAsstGui.exe $TargetDir/*.url
|
||||
2
tools/使用说明.url
Normal file
2
tools/使用说明.url
Normal file
@@ -0,0 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/MistEO/MeoAssistance-Arknights/blob/master/README.md
|
||||
2
tools/问题反馈.url
Normal file
2
tools/问题反馈.url
Normal file
@@ -0,0 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/MistEO/MeoAssistance-Arknights/issues
|
||||
Reference in New Issue
Block a user