临时保存,尝试解决工作线程死锁问题

This commit is contained in:
MistEO
2021-08-02 23:22:06 +08:00
parent ef29380dde
commit 9d43909fba
10 changed files with 54 additions and 227 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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