mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
新增回调消息的处理线程和队列;完成主界面的回调处理
This commit is contained in:
@@ -42,7 +42,8 @@ namespace asst {
|
||||
std::optional<std::string> get_param(const std::string& type, const std::string& param);
|
||||
|
||||
private:
|
||||
static void working_proc(Assistance* pThis);
|
||||
static void working_proc(Assistance* p_this);
|
||||
static void msg_proc(Assistance* p_this);
|
||||
static void task_callback(TaskMsg msg, const json::value& detail, void* custom_arg);
|
||||
|
||||
void append_match_task(const std::vector<std::string>& tasks);
|
||||
@@ -55,15 +56,22 @@ namespace asst {
|
||||
std::shared_ptr<Identify> m_identify_ptr = nullptr;
|
||||
bool m_inited = false;
|
||||
|
||||
bool m_thread_exit = false;
|
||||
std::queue<std::shared_ptr<AbstractTask>> m_tasks_queue;
|
||||
TaskCallback m_callback = nullptr;
|
||||
void* m_callback_arg = nullptr;
|
||||
|
||||
bool m_thread_idle = true;
|
||||
std::thread m_working_thread;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condvar;
|
||||
bool m_thread_exit = false;
|
||||
bool m_thread_idle = true;
|
||||
std::queue<std::shared_ptr<AbstractTask>> m_tasks_queue;
|
||||
|
||||
TaskCallback m_callback = nullptr;
|
||||
void* m_callback_arg = nullptr;
|
||||
std::thread m_msg_thread;
|
||||
std::queue<std::pair<TaskMsg, json::value>> m_msg_queue;
|
||||
std::mutex m_msg_mutex;
|
||||
std::condition_variable m_msg_condvar;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -110,4 +110,5 @@ namespace asst {
|
||||
#define DebugTrace Logger::get_instance().log_trace
|
||||
#define DebugTraceInfo Logger::get_instance().log_info
|
||||
#define DebugTraceError Logger::get_instance().log_error
|
||||
#define DebugTraceFunction LoggerAux _func_aux(__FUNCTION__)
|
||||
#define DebugTraceFunction LoggerAux _func_aux(__FUNCTION__)
|
||||
#define DebugTraceScope LoggerAux _func_aux
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "AsstDef.h"
|
||||
#include "AsstAux.h"
|
||||
|
||||
#include <json.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
class Mat;
|
||||
@@ -39,6 +41,7 @@ namespace asst {
|
||||
ImageIsEmpty,
|
||||
WindowMinimized,
|
||||
/* Info Msg */
|
||||
TaskStart,
|
||||
ImageMatched,
|
||||
TaskMatched,
|
||||
ReachedLimit,
|
||||
@@ -47,7 +50,7 @@ namespace asst {
|
||||
AppendMatchTask,
|
||||
TaskCompleted,
|
||||
PrintWindow,
|
||||
MissionStop,
|
||||
TaskStop,
|
||||
/* Open Recruit Msg */
|
||||
TextDetected,
|
||||
RecruitTagsDetected,
|
||||
@@ -62,6 +65,7 @@ namespace asst {
|
||||
{TaskMsg::PtrIsNull, "PtrIsNull"},
|
||||
{TaskMsg::ImageIsEmpty, "ImageIsEmpty"},
|
||||
{TaskMsg::WindowMinimized, "WindowMinimized"},
|
||||
{TaskMsg::TaskStart, "TaskStart"},
|
||||
{TaskMsg::ImageMatched, "ImageMatched"},
|
||||
{TaskMsg::TaskMatched, "TaskMatched"},
|
||||
{TaskMsg::ReachedLimit, "ReachedLimit"},
|
||||
@@ -70,7 +74,7 @@ namespace asst {
|
||||
{TaskMsg::AppendMatchTask, "AppendMatchTask"},
|
||||
{TaskMsg::TaskCompleted, "TaskCompleted"},
|
||||
{TaskMsg::PrintWindow, "PrintWindow"},
|
||||
{TaskMsg::MissionStop, "MissionStop"},
|
||||
{TaskMsg::TaskStop, "TaskStop"},
|
||||
{TaskMsg::TextDetected, "TextDetected"},
|
||||
{TaskMsg::RecruitTagsDetected, "RecruitTagsDetected"},
|
||||
{TaskMsg::OcrResultError, "OcrResultError"},
|
||||
|
||||
@@ -35,6 +35,7 @@ Assistance::Assistance(TaskCallback callback, void* callback_arg)
|
||||
m_identify_ptr->ocr_init_models(GetResourceDir() + "OcrLiteNcnn\\models\\");
|
||||
|
||||
m_working_thread = std::thread(working_proc, this);
|
||||
m_msg_thread = std::thread(msg_proc, this);
|
||||
}
|
||||
|
||||
Assistance::~Assistance()
|
||||
@@ -48,10 +49,14 @@ Assistance::~Assistance()
|
||||
m_thread_exit = true;
|
||||
m_thread_idle = true;
|
||||
m_condvar.notify_all();
|
||||
m_msg_condvar.notify_all();
|
||||
|
||||
if (m_working_thread.joinable()) {
|
||||
m_working_thread.join();
|
||||
}
|
||||
if (m_msg_thread.joinable()) {
|
||||
m_msg_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> Assistance::catch_emulator(const std::string& emulator_name)
|
||||
@@ -184,23 +189,24 @@ std::optional<std::string> Assistance::get_param(const std::string& type, const
|
||||
return Configer::get_instance().get_param(type, param);
|
||||
}
|
||||
|
||||
void Assistance::working_proc(Assistance* pThis)
|
||||
void Assistance::working_proc(Assistance* p_this)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
|
||||
int retry_times = 0;
|
||||
while (!pThis->m_thread_exit) {
|
||||
std::unique_lock<std::mutex> lock(pThis->m_mutex);
|
||||
if (!pThis->m_thread_idle && !pThis->m_tasks_queue.empty()) {
|
||||
while (!p_this->m_thread_exit) {
|
||||
DebugTraceScope("Assistance::working_proc Loop");
|
||||
std::unique_lock<std::mutex> lock(p_this->m_mutex);
|
||||
if (!p_this->m_thread_idle && !p_this->m_tasks_queue.empty()) {
|
||||
|
||||
auto start_time = std::chrono::system_clock::now();
|
||||
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);
|
||||
std::shared_ptr<AbstractTask> task_ptr = p_this->m_tasks_queue.front();
|
||||
task_ptr->set_ptr(p_this->m_window_ptr, p_this->m_view_ptr, p_this->m_control_ptr, p_this->m_identify_ptr);
|
||||
task_ptr->set_exit_flag(&p_this->m_thread_idle);
|
||||
bool ret = task_ptr->run();
|
||||
if (ret) {
|
||||
retry_times = 0;
|
||||
pThis->m_tasks_queue.pop();
|
||||
p_this->m_tasks_queue.pop();
|
||||
}
|
||||
else // 失败了不pop,一直跑。 Todo: 设一个上限
|
||||
{
|
||||
@@ -210,8 +216,8 @@ void Assistance::working_proc(Assistance* pThis)
|
||||
// 如果下个任务是识别,就按识别的延时来;如果下个任务是点击,就按点击的延时来;……
|
||||
// 如果都符合,就取个最大值
|
||||
int delay = 0;
|
||||
if (!pThis->m_tasks_queue.empty()) {
|
||||
int next_type = pThis->m_tasks_queue.front()->get_task_type();
|
||||
if (!p_this->m_tasks_queue.empty()) {
|
||||
int next_type = p_this->m_tasks_queue.front()->get_task_type();
|
||||
std::vector<int> candidate_delay = { 0 };
|
||||
if (next_type & TaskType::TaskTypeClick) {
|
||||
candidate_delay.emplace_back(Configer::get_instance().m_options.task_control_delay);
|
||||
@@ -221,21 +227,45 @@ void Assistance::working_proc(Assistance* pThis)
|
||||
}
|
||||
delay = *std::max_element(candidate_delay.cbegin(), candidate_delay.cend());
|
||||
}
|
||||
pThis->m_condvar.wait_until(lock,
|
||||
p_this->m_condvar.wait_until(lock,
|
||||
start_time + std::chrono::milliseconds(delay),
|
||||
[&]() -> bool { return pThis->m_thread_idle; });
|
||||
[&]() -> bool { return p_this->m_thread_idle; });
|
||||
}
|
||||
else {
|
||||
pThis->m_thread_idle = true;
|
||||
pThis->m_condvar.wait(lock);
|
||||
p_this->m_thread_idle = true;
|
||||
p_this->m_condvar.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Assistance::msg_proc(Assistance* p_this)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
|
||||
while (!p_this->m_thread_exit) {
|
||||
DebugTraceScope("Assistance::msg_proc Loop");
|
||||
std::unique_lock<std::mutex> lock(p_this->m_msg_mutex);
|
||||
if (!p_this->m_msg_queue.empty()) {
|
||||
// 结构化绑定只能是引用,后续的pop会使引用失效,所以需要重新构造一份,这里采用了move的方式
|
||||
auto && [temp_msg, temp_detail] = p_this->m_msg_queue.front();
|
||||
TaskMsg msg = std::move(temp_msg);
|
||||
json::value detail = std::move(temp_detail);
|
||||
p_this->m_msg_queue.pop();
|
||||
lock.unlock();
|
||||
|
||||
if (p_this->m_callback) {
|
||||
p_this->m_callback(msg, detail, p_this->m_callback_arg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
p_this->m_msg_condvar.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Assistance::task_callback(TaskMsg msg, const json::value& detail, void* custom_arg)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
DebugTrace(msg, detail.to_string());
|
||||
DebugTrace("Assistance::task_callback |", msg, detail.to_string());
|
||||
|
||||
Assistance* p_this = (Assistance*)custom_arg;
|
||||
json::value more_detail = detail;
|
||||
@@ -259,7 +289,9 @@ void Assistance::task_callback(TaskMsg msg, const json::value& detail, void* cus
|
||||
}
|
||||
|
||||
if (p_this->m_callback) {
|
||||
p_this->m_callback(msg, more_detail, p_this->m_callback_arg);
|
||||
std::unique_lock<std::mutex> lock(p_this->m_msg_mutex);
|
||||
p_this->m_msg_queue.emplace(msg, std::move(more_detail));
|
||||
p_this->m_msg_condvar.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,8 @@ bool MatchTask::run()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_callback(TaskMsg::TaskStart, json::value(), m_callback_arg);
|
||||
|
||||
Rect rect;
|
||||
auto&& ret = match_image(&rect);
|
||||
if (!ret) {
|
||||
@@ -179,7 +181,7 @@ bool MatchTask::run()
|
||||
case MatchTaskType::DoNothing:
|
||||
break;
|
||||
case MatchTaskType::Stop:
|
||||
m_callback(TaskMsg::MissionStop, json::value(), m_callback_arg);
|
||||
m_callback(TaskMsg::TaskStop, json::value(), m_callback_arg);
|
||||
need_stop = true;
|
||||
break;
|
||||
case MatchTaskType::PrintWindow:
|
||||
@@ -206,12 +208,12 @@ bool MatchTask::run()
|
||||
return true;
|
||||
}
|
||||
|
||||
// 后置固定延时
|
||||
sleep(task.rear_delay);
|
||||
|
||||
callback_json["exec_times"] = task.exec_times;
|
||||
m_callback(TaskMsg::TaskCompleted, callback_json, m_callback_arg);
|
||||
|
||||
// 后置固定延时
|
||||
sleep(task.rear_delay);
|
||||
|
||||
json::value next_json = callback_json;
|
||||
next_json["tasks"] = json::array(task.next);
|
||||
m_callback(TaskMsg::AppendMatchTask, next_json, m_callback_arg);
|
||||
@@ -314,6 +316,8 @@ bool OpenRecruitTask::run()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_callback(TaskMsg::TaskStart, json::value(), m_callback_arg);
|
||||
|
||||
/* Find all text */
|
||||
std::vector<TextArea> all_text_area = ocr_detect();
|
||||
|
||||
@@ -515,6 +519,8 @@ bool ClickTask::run()
|
||||
m_callback(TaskMsg::PtrIsNull, json::value(), m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
m_callback(TaskMsg::TaskStart, json::value(), m_callback_arg);
|
||||
|
||||
m_control_ptr->click(m_rect);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
xmlns:local="clr-namespace:MeoAsstGui"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Blue.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Indigo.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -14,6 +14,9 @@ using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Threading;
|
||||
using System.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace MeoAsstGui
|
||||
{
|
||||
@@ -35,20 +38,81 @@ namespace MeoAsstGui
|
||||
IntPtr p_asst, string type, string param,
|
||||
[In, Out] StringBuilder lp_string, int buffer_size);
|
||||
|
||||
|
||||
private delegate void CallbackDelegate(int msg, IntPtr json_buffer, IntPtr custom_arg);
|
||||
private delegate void ProcCallbckMsg(TaskMsg msg, JObject detail);
|
||||
|
||||
private static CallbackDelegate callback;
|
||||
|
||||
private IntPtr p_asst;
|
||||
private UpdateDialog updateDialog;
|
||||
private RecruitWindow recuitWindow;
|
||||
private DispatcherTimer update_times = new DispatcherTimer();
|
||||
|
||||
public enum TaskMsg
|
||||
{
|
||||
/* Error Msg */
|
||||
PtrIsNull,
|
||||
ImageIsEmpty,
|
||||
WindowMinimized,
|
||||
/* Info Msg */
|
||||
TaskStart,
|
||||
ImageMatched,
|
||||
TaskMatched,
|
||||
ReachedLimit,
|
||||
ReadyToSleep,
|
||||
EndOfSleep,
|
||||
AppendMatchTask,
|
||||
TaskCompleted,
|
||||
PrintWindow,
|
||||
TaskStop,
|
||||
/* Open Recruit Msg */
|
||||
TextDetected,
|
||||
RecruitTagsDetected,
|
||||
OcrResultError,
|
||||
RecruitSpecialTag,
|
||||
RecruitResult,
|
||||
AppendTask
|
||||
};
|
||||
|
||||
private void CallbackFunction(int msg, IntPtr json_buffer, IntPtr custom_arg)
|
||||
{
|
||||
string json_str = Marshal.PtrToStringAnsi(json_buffer);
|
||||
Console.WriteLine(json_str);
|
||||
//Console.WriteLine(json_str);
|
||||
JObject json = (JObject)JsonConvert.DeserializeObject(json_str);
|
||||
ProcCallbckMsg dlg = new ProcCallbckMsg(updateGui);
|
||||
this.Dispatcher.Invoke(dlg, msg, json);
|
||||
}
|
||||
private void updateGui(TaskMsg msg, JObject detail)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case TaskMsg.TaskCompleted:
|
||||
string task_name = detail["name"].ToString();
|
||||
if (task_name == "StartButton2")
|
||||
{
|
||||
exec_times.Content = "已开始行动 " + (int)detail["exec_times"] + " 次";
|
||||
}
|
||||
else if (task_name == "StoneConfirm")
|
||||
{
|
||||
stone_times.Content = "已碎石 " + (int)detail["exec_times"] + " 个";
|
||||
}
|
||||
break;
|
||||
case TaskMsg.TaskStart:
|
||||
label_status.Content = "正在运行中……";
|
||||
break;
|
||||
case TaskMsg.TaskStop:
|
||||
label_status.Content = "已刷完,自动停止";
|
||||
if (checkBox_shutdown.IsChecked == true)
|
||||
{
|
||||
System.Diagnostics.Process.Start("shutdown.exe", "-s -t 60");
|
||||
|
||||
MessageBoxResult result = MessageBox.Show("已刷完,即将关机,是否取消?", "提示", MessageBoxButton.OK);
|
||||
if (result == MessageBoxResult.OK)
|
||||
{
|
||||
System.Diagnostics.Process.Start("shutdown.exe", "-a");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
public MainWindow()
|
||||
{
|
||||
@@ -63,8 +127,8 @@ namespace MeoAsstGui
|
||||
{
|
||||
callback = CallbackFunction;
|
||||
p_asst = AsstCreateEx(callback, IntPtr.Zero);
|
||||
update_times.Tick += new EventHandler(updateExecTimes);
|
||||
update_times.Interval = TimeSpan.FromSeconds(1);
|
||||
//update_times.Tick += new EventHandler(updateExecTimes);
|
||||
//update_times.Interval = TimeSpan.FromSeconds(1);
|
||||
|
||||
// for debug
|
||||
//updateDialog = new UpdateDialog();
|
||||
@@ -76,14 +140,12 @@ namespace MeoAsstGui
|
||||
bool catched = AsstCatchEmulator(p_asst);
|
||||
catch_status.Content = "捕获模拟器窗口:" + catched;
|
||||
AsstStart(p_asst, "SanityBegin");
|
||||
update_times.Start();
|
||||
}
|
||||
|
||||
private void button_Click_stop(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AsstStop(p_asst);
|
||||
catch_status.Content = "";
|
||||
update_times.Stop();
|
||||
exec_times.Content = "";
|
||||
stone_times.Content = "";
|
||||
label_status.Content = "";
|
||||
@@ -132,43 +194,6 @@ namespace MeoAsstGui
|
||||
AsstStart(p_asst, "VisitBegin");
|
||||
}
|
||||
|
||||
private void updateExecTimes(object sender, EventArgs e)
|
||||
{
|
||||
StringBuilder buff_start = new StringBuilder(16);
|
||||
AsstGetParam(p_asst, "task.execTimes", "StartButton2", buff_start, 16);
|
||||
exec_times.Content = "已开始行动 " + buff_start + " 次";
|
||||
|
||||
if (checkBox_useStone.IsChecked == true)
|
||||
{
|
||||
StringBuilder buff_stone = new StringBuilder(16);
|
||||
AsstGetParam(p_asst, "task.execTimes", "StoneConfirm", buff_stone, 16);
|
||||
stone_times.Content = "已碎石 " + buff_stone + " 个";
|
||||
}
|
||||
|
||||
|
||||
StringBuilder buff_running = new StringBuilder(4);
|
||||
AsstGetParam(p_asst, "status", "running", buff_running, 4);
|
||||
if (int.Parse(buff_running.ToString()) == 0)
|
||||
{
|
||||
update_times.Stop();
|
||||
label_status.Content = "已刷完,自动停止";
|
||||
if (checkBox_shutdown.IsChecked == true)
|
||||
{
|
||||
System.Diagnostics.Process.Start("shutdown.exe", "-s -t 60");
|
||||
|
||||
MessageBoxResult result = MessageBox.Show("已刷完,即将关机,是否取消?", "提示", MessageBoxButton.OK);
|
||||
if (result == MessageBoxResult.OK)
|
||||
{
|
||||
System.Diagnostics.Process.Start("shutdown.exe", "-a");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
label_status.Content = "正在运行中……";
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBox_maxTimes_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (checkBox_maxTimes.IsChecked == true)
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
<StartupObject>MeoAsstGui.App</StartupObject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
@@ -124,6 +127,7 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
||||
6
MeoAsstGui/packages.config
Normal file
6
MeoAsstGui/packages.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MaterialDesignColors" version="2.0.1" targetFramework="net472" />
|
||||
<package id="MaterialDesignThemes" version="4.1.0" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user