mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-16 01:40:46 +08:00
临时保存,尝试解决工作线程死锁问题
This commit is contained in:
@@ -32,7 +32,11 @@ namespace asst {
|
||||
|
||||
std::optional<std::string> catch_emulator(const std::string& emulator_name = std::string());
|
||||
|
||||
void start(const std::string& task);
|
||||
// 开始刷理智
|
||||
void start_sanity();
|
||||
// 开始访问基建
|
||||
void start_visit();
|
||||
// 开始公开招募操作
|
||||
void start_open_recruit(const std::vector<int>& required_level, bool set_time = true);
|
||||
|
||||
void stop(bool block = true);
|
||||
@@ -42,16 +46,8 @@ namespace asst {
|
||||
|
||||
bool print_window(const std::string& filename, bool block = true);
|
||||
|
||||
// for debug
|
||||
// 计算公开招募,需要当前处在选择公招Tag的页面
|
||||
// 参数:
|
||||
// required_level:需要的等级,最优组合的最低等级,在required_level中,才会进行点击
|
||||
// set_time:是否自动设置时间(9小时)
|
||||
// 返回值:
|
||||
// std::vector< std::pair < Tags名vector,这个Tags组合可能出的干员组合 > >
|
||||
std::optional<std::vector<std::pair<std::vector<std::string>, OperCombs>>>
|
||||
open_recruit(const std::vector<int>& required_level, bool set_time = true);
|
||||
|
||||
// 开始匹配任务,调试用
|
||||
void start_match_task(const std::string& task);
|
||||
private:
|
||||
static void working_proc(Assistance* pThis);
|
||||
static void task_callback(TaskMsg msg, const json::value& detail, void* custom_arg);
|
||||
|
||||
@@ -16,7 +16,7 @@ MEOAPI_PORT void AsstStart(asst::Assistance* p_asst, const char* task);
|
||||
MEOAPI_PORT void AsstStop(asst::Assistance* p_asst);
|
||||
MEOAPI_PORT bool AsstSetParam(asst::Assistance* p_asst, const char* type, const char* param, const char* value);
|
||||
MEOAPI_PORT bool AsstGetParam(asst::Assistance* p_asst, const char* type, const char* param, char * buffer, int buffer_size);
|
||||
MEOAPI_PORT bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bool set_time, char * result_buffer, int bufsize, int& maybe_level);
|
||||
MEOAPI_PORT bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bool set_time);
|
||||
|
||||
MEOAPI_PORT bool CheckVersionUpdate(char* tag_buffer, int tag_bufsize, char* html_url_buffer, int html_bufsize, char* body_buffer, int body_bufsize);
|
||||
|
||||
|
||||
@@ -19,6 +19,12 @@ namespace json
|
||||
{
|
||||
class value;
|
||||
}
|
||||
namespace std
|
||||
{
|
||||
template <class _Mutex>
|
||||
class unique_lock;
|
||||
class mutex;
|
||||
}
|
||||
|
||||
namespace asst {
|
||||
|
||||
@@ -43,6 +49,7 @@ namespace asst {
|
||||
TaskMatched,
|
||||
ReachedLimit,
|
||||
ReadyToSleep,
|
||||
EndOfSleep,
|
||||
AppendMatchTask,
|
||||
TaskCompleted,
|
||||
MissionStop,
|
||||
@@ -63,6 +70,7 @@ namespace asst {
|
||||
{TaskMsg::TaskMatched, "TaskMatched"},
|
||||
{TaskMsg::ReachedLimit, "ReachedLimit"},
|
||||
{TaskMsg::ReadyToSleep, "ReadyToSleep"},
|
||||
{TaskMsg::EndOfSleep, "EndOfSleep"},
|
||||
{TaskMsg::AppendMatchTask, "AppendMatchTask"},
|
||||
{TaskMsg::TaskCompleted, "TaskCompleted"},
|
||||
{TaskMsg::MissionStop, "MissionStop"},
|
||||
@@ -99,6 +107,7 @@ namespace asst {
|
||||
virtual bool run() = 0;
|
||||
|
||||
virtual void set_exit_flag(bool* exit_flag);
|
||||
virtual void set_lock(std::unique_lock<std::mutex>* lock_ptr) { m_lock_ptr = lock_ptr; }
|
||||
virtual int get_task_type() { return m_task_type; }
|
||||
virtual void set_retry_times(int times) { m_retry_times = times; }
|
||||
virtual int get_retry_times() { return m_retry_times; }
|
||||
@@ -115,6 +124,7 @@ namespace asst {
|
||||
TaskCallback m_callback;
|
||||
void* m_callback_arg = NULL;
|
||||
bool* m_exit_flag = NULL;
|
||||
std::unique_lock<std::mutex>* m_lock_ptr;
|
||||
int m_task_type = TaskType::TaskTypeInvalid;
|
||||
int m_retry_times = INT_MAX;
|
||||
};
|
||||
|
||||
@@ -95,7 +95,17 @@ std::optional<std::string> Assistance::catch_emulator(const std::string& emulato
|
||||
}
|
||||
}
|
||||
|
||||
void Assistance::start(const std::string& task)
|
||||
void asst::Assistance::start_sanity()
|
||||
{
|
||||
start_match_task("SanityBegin");
|
||||
}
|
||||
|
||||
void asst::Assistance::start_visit()
|
||||
{
|
||||
start_match_task("VisitBegin");
|
||||
}
|
||||
|
||||
void Assistance::start_match_task(const std::string& task)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
DebugTrace("Start |", task);
|
||||
@@ -218,175 +228,6 @@ bool asst::Assistance::find_text_and_click(const std::string& text, bool block)
|
||||
return m_control_ptr->click(result.value());
|
||||
}
|
||||
|
||||
std::optional<std::vector<std::pair<std::vector<std::string>, OperCombs>>>
|
||||
asst::Assistance::open_recruit(const std::vector<int>& required_level, bool set_time)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
const cv::Mat& image = get_format_image();
|
||||
set_control_scale(image.cols, image.rows);
|
||||
lock.unlock(); // 后面的计算耗时太长,先解锁
|
||||
|
||||
if (set_time) {
|
||||
start("RecruitTime");
|
||||
}
|
||||
|
||||
std::vector<TextArea> ider_result = m_identify_ptr->ocr_detect(image);
|
||||
std::vector<TextArea> filt_result;
|
||||
std::string ider_str;
|
||||
for (TextArea& res : ider_result) {
|
||||
// 替换一些常见的文字识别错误
|
||||
// TODO: 这块时间复杂度有点高,待优化
|
||||
for (const auto& [src, cor] : m_configer.m_ocr_replace) {
|
||||
res.text = StringReplaceAll(res.text, src, cor);
|
||||
}
|
||||
ider_str += res.text + " ,";
|
||||
for (const std::string& t : m_recruit_configer.m_all_tags) {
|
||||
if (res.text == t) {
|
||||
filt_result.emplace_back(std::move(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ider_str.back() == ',') {
|
||||
ider_str.pop_back();
|
||||
}
|
||||
DebugTrace("All ocr text: ", Utf8ToGbk(ider_str));
|
||||
|
||||
if (filt_result.size() != 5) {
|
||||
DebugTraceError("Error, Tags recognition error!!!");
|
||||
stop(true);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<std::string> tags;
|
||||
for (const TextArea& t_a : filt_result) {
|
||||
tags.emplace_back(t_a.text);
|
||||
}
|
||||
DebugTraceInfo("All Tags", VectorToString(tags, true));
|
||||
|
||||
// Tags全组合
|
||||
std::vector<std::vector<std::string>> all_combs;
|
||||
int len = tags.size();
|
||||
int count = std::pow(2, len);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::vector<std::string> temp;
|
||||
for (int j = 0, mask = 1; j < len; ++j) {
|
||||
if ((i & mask) != 0) { // What the fuck???
|
||||
temp.emplace_back(tags.at(j));
|
||||
}
|
||||
mask = mask * 2;
|
||||
}
|
||||
// 游戏里最多选择3个tag
|
||||
if (!temp.empty() && temp.size() <= 3) {
|
||||
all_combs.emplace_back(std::move(temp));
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::vector<std::string>, OperCombs> result_map;
|
||||
for (const std::vector<std::string>& comb : all_combs) {
|
||||
for (const OperInfo& cur_oper : m_recruit_configer.m_all_opers) {
|
||||
int matched_count = 0;
|
||||
// 组合中每一个tag,是否在干员tags中
|
||||
for (const std::string& tag : comb) {
|
||||
if (cur_oper.tags.find(tag) != cur_oper.tags.cend()) {
|
||||
++matched_count;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matched_count == comb.size()) {
|
||||
static const std::string SeniorOper = GbkToUtf8("高级资深干员");
|
||||
// 高资tag和六星强绑定,如果没有高资tag,即使其他tag匹配上了也不可能出六星
|
||||
if (cur_oper.level == 6
|
||||
&& std::find(comb.cbegin(), comb.cend(), SeniorOper) == comb.cend()) {
|
||||
continue;
|
||||
}
|
||||
OperCombs& oper_combs = result_map[comb];
|
||||
oper_combs.opers.emplace_back(cur_oper);
|
||||
|
||||
static const std::string SupportMachine = GbkToUtf8("支援机械");
|
||||
if (cur_oper.level == 1
|
||||
&& std::find(comb.cbegin(), comb.cend(), SupportMachine) != comb.cend()) {
|
||||
DebugTraceInfo("Has Level 1");
|
||||
}
|
||||
// 一星小车不计入最低等级
|
||||
if (cur_oper.level != 1 && (
|
||||
oper_combs.min_level == 0 || oper_combs.min_level > cur_oper.level)) {
|
||||
oper_combs.min_level = cur_oper.level;
|
||||
}
|
||||
|
||||
if (oper_combs.max_level == 0 || oper_combs.max_level < cur_oper.level) {
|
||||
oper_combs.max_level = cur_oper.level;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// map没法按值排序,转个vector再排
|
||||
std::vector<std::pair<std::vector<std::string>, OperCombs>> result_vector;
|
||||
for (auto&& pair : result_map) {
|
||||
result_vector.emplace_back(std::move(pair));
|
||||
}
|
||||
std::sort(result_vector.begin(), result_vector.end(), [](const auto& lhs, const auto& rhs)
|
||||
->bool {
|
||||
// 1、最小等级小的,排最后
|
||||
// 2、最小等级相同,最大等级小的,排后面
|
||||
// 3、1 2都相同,标签多的,排后面
|
||||
if (lhs.second.min_level != rhs.second.min_level) {
|
||||
return lhs.second.min_level > rhs.second.min_level;
|
||||
}
|
||||
else if (lhs.second.max_level != rhs.second.max_level) {
|
||||
return lhs.second.max_level > rhs.second.max_level;
|
||||
}
|
||||
else {
|
||||
return lhs.first.size() < rhs.first.size();
|
||||
}
|
||||
});
|
||||
|
||||
for (const auto& [combs, oper_combs] : result_vector) {
|
||||
std::string tag_str;
|
||||
for (const std::string& tag : combs) {
|
||||
tag_str += tag + " ,";
|
||||
}
|
||||
if (tag_str.back() == ',') {
|
||||
tag_str.pop_back();
|
||||
}
|
||||
|
||||
std::string opers_str;
|
||||
for (const OperInfo& oper : oper_combs.opers) {
|
||||
opers_str += std::to_string(oper.level) + "-" + oper.name + " ,";
|
||||
}
|
||||
if (opers_str.back() == ',') {
|
||||
opers_str.pop_back();
|
||||
}
|
||||
DebugTraceInfo("Tags:", VectorToString(combs, true), "May be recruited: ", Utf8ToGbk(opers_str));
|
||||
}
|
||||
|
||||
stop(true);
|
||||
if (!required_level.empty() && !result_vector.empty()) {
|
||||
if (std::find(required_level.cbegin(), required_level.cend(), result_vector[0].second.min_level)
|
||||
== required_level.cend()) {
|
||||
return result_vector;
|
||||
}
|
||||
const std::vector<std::string>& final_tags = result_vector[0].first;
|
||||
std::vector<TextArea> final_text_areas;
|
||||
|
||||
lock.lock();
|
||||
for (const TextArea& text_area : filt_result) {
|
||||
if (std::find(final_tags.cbegin(), final_tags.cend(), text_area.text) != final_tags.cend()) {
|
||||
final_text_areas.emplace_back(text_area);
|
||||
m_control_ptr->click(text_area.rect);
|
||||
Sleep(300);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
}
|
||||
return result_vector;
|
||||
}
|
||||
|
||||
void Assistance::working_proc(Assistance* pThis)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
@@ -400,6 +241,7 @@ void Assistance::working_proc(Assistance* pThis)
|
||||
std::shared_ptr<AbstractTask> task_ptr = pThis->m_tasks_queue.front();
|
||||
task_ptr->set_ptr(pThis->m_window_ptr, pThis->m_view_ptr, pThis->m_control_ptr, pThis->m_identify_ptr);
|
||||
task_ptr->set_exit_flag(&pThis->m_thread_idle);
|
||||
task_ptr->set_lock(&lock);
|
||||
bool ret = task_ptr->run();
|
||||
if (ret) {
|
||||
retry_times = 0;
|
||||
@@ -443,21 +285,9 @@ void Assistance::task_callback(TaskMsg msg, const json::value& detail, void* cus
|
||||
Assistance* p_this = (Assistance*)custom_arg;
|
||||
switch (msg)
|
||||
{
|
||||
case TaskMsg::PtrIsNull:
|
||||
break;
|
||||
case TaskMsg::ImageIsEmpty:
|
||||
break;
|
||||
case TaskMsg::WindowMinimized:
|
||||
break;
|
||||
case TaskMsg::TaskMatched:
|
||||
break;
|
||||
case TaskMsg::ReachedLimit:
|
||||
break;
|
||||
case TaskMsg::ReadyToSleep:
|
||||
break;
|
||||
case TaskMsg::TaskCompleted:
|
||||
break;
|
||||
case TaskMsg::MissionStop:
|
||||
case TaskMsg::EndOfSleep:
|
||||
break;
|
||||
case TaskMsg::AppendMatchTask:
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ void AsstStart(asst::Assistance* p_asst, const char* task)
|
||||
if (p_asst == NULL) {
|
||||
}
|
||||
|
||||
p_asst->start(task);
|
||||
p_asst->start_match_task(task);
|
||||
}
|
||||
|
||||
void AsstStop(asst::Assistance* p_asst)
|
||||
@@ -74,7 +74,7 @@ bool AsstGetParam(asst::Assistance* p_asst, const char* type, const char* param,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bool set_time, char* result_buffer, int bufsize, int& maybe_level)
|
||||
bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bool set_time)
|
||||
{
|
||||
if (p_asst == NULL) {
|
||||
return false;
|
||||
@@ -82,30 +82,8 @@ bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bo
|
||||
int len = sizeof required_level / sizeof(int);
|
||||
std::vector<int> level_vector;
|
||||
level_vector.assign(required_level, required_level + len);
|
||||
auto&& ret = p_asst->open_recruit(level_vector, set_time);
|
||||
if (ret) {
|
||||
// <std::vector<std::pair<std::vector<std::string>, OperCombs>>>
|
||||
std::string result_str;
|
||||
maybe_level = 0;
|
||||
for (auto&& [tags, oper_combs] : ret.value())
|
||||
{
|
||||
result_str += std::to_string(oper_combs.min_level) + "ÐÇTags: "
|
||||
+ asst::VectorToString(tags, true) + "\n\t";
|
||||
for (auto&& oper : oper_combs.opers)
|
||||
{
|
||||
result_str += std::to_string(oper.level) + " - " + asst::Utf8ToGbk(oper.name) + " ";
|
||||
}
|
||||
result_str += "\n\n";
|
||||
if (maybe_level == 0) {
|
||||
maybe_level = oper_combs.min_level;
|
||||
}
|
||||
}
|
||||
strcpy_s(result_buffer, bufsize, result_str.c_str());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
p_asst->start_open_recruit(level_vector, set_time);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
|
||||
using namespace asst;
|
||||
|
||||
@@ -87,12 +88,15 @@ void AbstractTask::sleep(unsigned millisecond)
|
||||
callback_json["time"] = millisecond;
|
||||
m_callback(TaskMsg::ReadyToSleep, callback_json, m_callback_arg);
|
||||
|
||||
m_lock_ptr->unlock();
|
||||
while ((m_exit_flag == NULL || *m_exit_flag == false)
|
||||
&& duration < millisecond) {
|
||||
duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now() - start).count();
|
||||
std::this_thread::yield();
|
||||
}
|
||||
m_lock_ptr->lock();
|
||||
m_callback(TaskMsg::EndOfSleep, callback_json, m_callback_arg);
|
||||
}
|
||||
|
||||
MatchTask::MatchTask(TaskCallback callback, void* callback_arg,
|
||||
@@ -240,7 +244,12 @@ OcrAbstractTask::OcrAbstractTask(TaskCallback callback, void* callback_arg)
|
||||
std::vector<TextArea> OcrAbstractTask::ocr_detect()
|
||||
{
|
||||
const cv::Mat& image = get_format_image();
|
||||
return m_identify_ptr->ocr_detect(image);
|
||||
|
||||
m_lock_ptr->unlock();
|
||||
auto&& dst = m_identify_ptr->ocr_detect(image);
|
||||
m_lock_ptr->lock();
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
OpenRecruitTask::OpenRecruitTask(TaskCallback callback, void* callback_arg,
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace MeoAsstGui
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
|
||||
[DllImport("MeoAssistance.dll")] static private extern IntPtr CreateAsst();
|
||||
[DllImport("MeoAssistance.dll")] static private extern void DestoryAsst(IntPtr ptr);
|
||||
[DllImport("MeoAssistance.dll")] static private extern IntPtr AsstCreate();
|
||||
[DllImport("MeoAssistance.dll")] static private extern void AsstDestory(IntPtr ptr);
|
||||
[DllImport("MeoAssistance.dll")] static private extern bool AsstCatchEmulator(IntPtr ptr);
|
||||
[DllImport("MeoAssistance.dll")] static private extern void AsstStart(IntPtr ptr, string task);
|
||||
[DllImport("MeoAssistance.dll")] static private extern void AsstStop(IntPtr ptr);
|
||||
@@ -46,12 +46,12 @@ namespace MeoAsstGui
|
||||
}
|
||||
~MainWindow()
|
||||
{
|
||||
DestoryAsst(p_asst);
|
||||
AsstDestory(p_asst);
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
p_asst = CreateAsst();
|
||||
p_asst = AsstCreate();
|
||||
update_times.Tick += new EventHandler(updateExecTimes);
|
||||
update_times.Interval = TimeSpan.FromSeconds(1);
|
||||
|
||||
|
||||
@@ -55,6 +55,9 @@
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>MeoAsstGui.App</StartupObject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
|
||||
@@ -53,3 +53,4 @@ using System.Windows;
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: NeutralResourcesLanguage("zh")]
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace MeoAsstGui
|
||||
public partial class RecruitWindow : Window
|
||||
{
|
||||
[DllImport("MeoAssistance.dll")] static private extern bool AsstCatchEmulator(IntPtr ptr);
|
||||
[DllImport("MeoAssistance.dll")] static private extern bool AsstRunOpenRecruit(IntPtr ptr, int[] required_level, bool set_time, [In, Out] StringBuilder result, int buffer_size, ref int maybe_level);
|
||||
[DllImport("MeoAssistance.dll")] static private extern bool AsstRunOpenRecruit(IntPtr ptr, int[] required_level, bool set_time);
|
||||
|
||||
private IntPtr p_asst;
|
||||
public RecruitWindow(IntPtr ptr)
|
||||
|
||||
Reference in New Issue
Block a user