Merge branch 'temp' into dev

This commit is contained in:
MistEO
2022-01-08 16:29:07 +08:00
36 changed files with 916 additions and 861 deletions

View File

@@ -190,6 +190,7 @@ A Game Assistant for Arknights
- [C 接口](https://github.com/MistEO/MeoAssistantArknights/blob/dev/include/AsstCaller.h)
- [Python 接口](https://github.com/MistEO/MeoAssistantArknights/wiki/Python-%E6%8E%A5%E5%8F%A3)
- [Golang 接口](https://github.com/MistEO/MeoAssistantArknights/wiki/Golang-%E6%8E%A5%E5%8F%A3)
- [回调消息协议](docs/回调消息协议.md)
## 广告

View File

@@ -55,7 +55,13 @@ sudo ldconfig
1. 直接拷贝上面编译的第三方库到 `3rdparty/lib` 或者 手动修改 `CMakeLists.txt` 指定第三方库路径
2. `3rdparty/include/opencv` 中的头文件是 `4.5.3` 版本的,若是使用其他版本,请注意头文件冲突问题(直接将你的 `opencv` 头文件覆盖过去就好)
3. 安装 `adb`, 并修改 `resource/config.json``Custom`.`adb`.`path` 的值为 `"adb"`
4. 复制资源文件到 `libMeoAssitant.so` 同一目录下,具体可参考 [这个脚本](../tools/update_resource.sh)
4. 复制资源文件到 `libMeoAssitant.so` 同一目录下
```sh
cd tools
sh ./update_resource.sh <YourBuildDir>
```
5. 通过 [Python 接口](../src/Python/interface.py) 或 [C 接口](../include/AsstCaller.h) 进行调用,需要自行编写少量的代码
6. `cmake` 可通过添加 `-DBUILD_TEST=ON` 选项来编译一个测试小 demo

326
docs/回调消息协议.md Normal file
View File

@@ -0,0 +1,326 @@
# 回调消息协议
## 回调函数原型
```c++
typedef void(ASST_CALL* AsstCallback)(int msg, const char* details, void* custom_arg);
```
## 参数总览
- `int msg`
消息类型
```c++
enum class AsstMsg
{
/* Global Info */
InternalError = 0, // 内部错误
InitFailed, // 初始化失败
ConnectionError, // 连接相关错误
AllTasksCompleted, // 全部任务完成
/* TaskChain Info */
TaskChainError = 10000, // 任务链执行/识别错误
TaskChainStart, // 任务链开始
TaskChainCompleted, // 任务链完成
TaskChainExtraInfo, // 任务链额外信息
/* SubTask Info */
SubTaskError = 20000, // 原子任务执行/识别错误
SubTaskStart, // 原子任务开始
SubTaskCompleted, // 原子任务完成
SubTaskExtraInfo // 原子任务额外信息
};
```
- `const char* details`
消息详情json 字符串,详见 [字段解释](#字段解释)
- `void* custom_arg`
调用方自定义参数,会原样传出 `AsstCreateEx` 接口中的 `custom_arg` 参数C 系语言可利用该参数传出 `this` 指针
## 字段解释
### InternalError
Todo
### InitFailed
```jsonc
{
"what": string, // 错误类型
"details": object, // 错误详情
}
```
### ConnectionError
Todo
### TaskChain 相关、AllTasksCompleted
```jsonc
{
"task_chain": string, // 当前的任务链
"pre_taskchain": string, // 上一个任务链
"next_taskchain": string, // 下一个任务链
"details": object, // 详情
}
```
### TaskChainExtraInfo
Todo
### SubTask 相关
```jsonc
{
"taskchain": string, // 当前任务链
"class": string, // 子任务类型
"details": object, // 详情
}
```
### SubTaskExtraInfo
```jsonc
{
"taskchain": string, // 当前任务链
"class": string, // 子任务类型
"what": string, // 信息类型
"details": object, // 信息详情
}
```
### 任务链 `taskchain` 字段
- `StartUp`
开始唤醒
- `Fight`
刷理智
- `Mall`
信用点及购物
- `Recruit`
自动公招
- `RecruitCalc`
公招识别
- `Infrast`
基建换班
- `Debug`
调试
### 子任务类型 `class` 字段
- `ProcessTask`
```jsonc
// 对应的 details 字段举例
{
"task": "StartButton2", // 任务名
"action": 512,
"exec_times": 1, // 已执行次数
"max_times": 999, // 最大执行次数
"algorithm": 0
}
```
- Todo 其他
#### 常见 `task` 字段
- `StartButton2`
开始战斗
- `MedicineConfirm`
使用理智药
- `StoneConfirm`
碎石
- `RecruitRefreshConfirm`
公招刷新标签
- `RecruitConfirm`
公招确认招募
### 额外信息 `what` 字段
- `StageDrops`
关卡材料掉落信息
```jsonc
// 对应的 details 字段举例
{
"exceptions": [],
"resultLabel": true,
"drops": [ // 本次识别到的掉落材料
{
"dropType": "NORMAL_DROP",
"itemId": "3301",
"quantity": 2,
"itemName": "技巧概要·卷1"
},
{
"dropType": "NORMAL_DROP",
"itemId": "3302",
"quantity": 1,
"itemName": "技巧概要·卷2"
},
{
"dropType": "NORMAL_DROP",
"itemId": "3303",
"quantity": 2,
"itemName": "技巧概要·卷3"
}
],
"dropTypes": [
{
"dropTypes": "LMB"
},
{
"dropTypes": "NORMAL_DROP"
}
],
"stage": { // 关卡信息
"stageCode": "CA-5",
"stageId": "wk_fly_5"
},
"stars": 3, // 行动结束星级
"fingerprint": "e464bafaa3f92877bbc4fb20209e4169ae49d587499c8d2e72026b96356c591f6a17477a5b345518a00b23be78252e0825070585d33f2109390807672c252a0b",
"md5": "b40ea51ec7802afa2e86951bffbbc21f",
"cost": 6.0624,
"statistics": [ // 本次执行期间总的材料掉落
{
"itemId": "3301",
"itemName": "技巧概要·卷1",
"count": 4
},
{
"itemId": "3302",
"itemName": "技巧概要·卷2",
"count": 3
},
{
"itemId": "3303",
"itemName": "技巧概要·卷3",
"count": 4
}
]
}
```
- `RecruitTagsDetected`
公招识别到了 Tags
```jsonc
// 对应的 details 字段举例
{
"tags": [
"费用回复",
"防护",
"先锋干员",
"辅助干员",
"近战位"
]
}
```
- `RecruitSpecialTag`
公招识别到了特殊 Tag
```jsonc
// 对应的 details 字段举例
{
"tag": "高级资深干员"
}
```
- `RecruitResult`
公招识别结果
```jsonc
// 对应的 details 字段举例
{
"level": 4, // 总的星级
"result": [
{
"tags": [
"削弱"
],
"level": 4, // 这组 tags 的星级
"opers": [
{
"name": "初雪",
"level": 5 // 干员星级
},
{
"name": "陨星",
"level": 5
},
{
"name": "槐琥",
"level": 5
},
{
"name": "夜烟",
"level": 4
},
{
"name": "流星",
"level": 4
}
]
},
{
"tags": [
"减速",
"术师干员"
],
"level": 4,
"opers": [
{
"name": "夜魔",
"level": 5
},
{
"name": "格雷伊",
"level": 4
}
]
},
{
"tags": [
"削弱",
"术师干员"
],
"level": 4,
"opers": [
{
"name": "夜烟",
"level": 4
}
]
}
]
}
```
- `RecruitTagsSelected`
公招选择了 Tags
```jsonc
// 对应的 details 字段举例
{
"tags": [
"减速",
"术师干员"
]
}
```
- `EnterFacility`
基建进入了设施
```jsonc
// 对应的 details 字段举例
{
"facility": "Mfg", // 设施名
"index": 0 // 设施序号
}
```

View File

@@ -13,17 +13,20 @@
using namespace asst;
AbstractTask::AbstractTask(AsstCallback callback, void* callback_arg)
AbstractTask::AbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain)
: m_callback(callback),
m_callback_arg(callback_arg)
m_callback_arg(callback_arg),
m_task_chain(std::move(task_chain))
{
;
}
bool asst::AbstractTask::run()
{
m_callback(AsstMsg::SubTaskStart, basic_info(), m_callback_arg);
for (m_cur_retry = 0; m_cur_retry < m_retry_times; ++m_cur_retry) {
if (_run()) {
m_callback(AsstMsg::SubTaskCompleted, basic_info(), m_callback_arg);
return true;
}
if (need_exit()) {
@@ -33,12 +36,37 @@ bool asst::AbstractTask::run()
sleep(delay);
if (!on_run_fails()) {
m_callback(AsstMsg::SubTaskError, basic_info(), m_callback_arg);
return false;
}
}
m_callback(AsstMsg::SubTaskError, basic_info(), m_callback_arg);
return false;
}
AbstractTask& asst::AbstractTask::set_exit_flag(bool* exit_flag) noexcept
{
m_exit_flag = exit_flag;
return *this;
}
AbstractTask& asst::AbstractTask::set_retry_times(int times) noexcept
{
m_retry_times = times;
return *this;
}
json::value asst::AbstractTask::basic_info() const
{
return json::object{
{ "taskchain", m_task_chain },
{ "class", typeid(*this).name() },
{ "details", json::object() }
//{ "CurRetryTimes", m_cur_retry },
//{ "MaxRetryTimes", m_retry_times }
};
}
bool AbstractTask::sleep(unsigned millisecond)
{
if (need_exit()) {
@@ -50,9 +78,7 @@ bool AbstractTask::sleep(unsigned millisecond)
auto start = std::chrono::steady_clock::now();
long long duration = 0;
json::value callback_json;
callback_json["time"] = millisecond;
m_callback(AsstMsg::ReadyToSleep, callback_json, m_callback_arg);
Log.trace("ready to sleep", millisecond);
while (!need_exit() && duration < millisecond) {
duration = std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -60,7 +86,7 @@ bool AbstractTask::sleep(unsigned millisecond)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::yield();
}
m_callback(AsstMsg::EndOfSleep, callback_json, m_callback_arg);
Log.trace("end of sleep", millisecond);
return !need_exit();
}
@@ -73,12 +99,6 @@ bool AbstractTask::save_image(const cv::Mat image, const std::string& dir)
bool ret = cv::imwrite(filename, image);
json::value callback_json;
callback_json["filename"] = filename;
callback_json["ret"] = ret;
callback_json["offset"] = 0;
m_callback(AsstMsg::PrintWindow, callback_json, m_callback_arg);
return true;
}

View File

@@ -8,28 +8,32 @@ namespace cv
{
class Mat;
}
namespace json
{
class value;
}
namespace asst
{
class AbstractTask
{
public:
AbstractTask(AsstCallback callback, void* callback_arg);
AbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain);
virtual ~AbstractTask() noexcept = default;
AbstractTask(const AbstractTask&) = default;
AbstractTask(AbstractTask&&) noexcept = default;
virtual bool run();
void set_exit_flag(bool* exit_flag) noexcept { m_exit_flag = exit_flag; }
void set_retry_times(int times) noexcept { m_retry_times = times; }
void set_task_chain(std::string name) noexcept { m_task_chain = std::move(name); }
AbstractTask& set_exit_flag(bool* exit_flag) noexcept;
AbstractTask& set_retry_times(int times) noexcept;
const std::string& get_task_chain() const noexcept { return m_task_chain; }
constexpr static int RetryTimesDefault = 20;
protected:
virtual bool _run() = 0;
virtual bool on_run_fails() { return true; }
virtual json::value basic_info() const;
bool sleep(unsigned millisecond);
bool save_image(const cv::Mat image, const std::string& dir);
@@ -40,7 +44,7 @@ namespace asst
AsstCallback m_callback;
void* m_callback_arg = nullptr;
bool* m_exit_flag = nullptr;
std::string m_task_chain;
const std::string m_task_chain;
int m_cur_retry = 0;
int m_retry_times = RetryTimesDefault;
};

View File

@@ -37,7 +37,7 @@ Assistant::Assistant(std::string dirname, AsstCallback callback, void* callback_
LogTraceFunction;
bool resource_ret = Resrc.load(m_dirname + "Resource/");
bool resource_ret = Resrc.load(m_dirname + "resource/");
if (!resource_ret) {
const std::string& error = Resrc.get_last_error();
Log.error("resource broken:", error);
@@ -45,9 +45,11 @@ Assistant::Assistant(std::string dirname, AsstCallback callback, void* callback_
throw error;
}
json::value callback_json;
callback_json["type"] = "resource broken";
callback_json["what"] = error;
m_callback(AsstMsg::InitFaild, callback_json, m_callback_arg);
callback_json["what"] = "resource broken";
callback_json["details"] = json::object{
{ "error", error }
};
m_callback(AsstMsg::InitFailed, callback_json, m_callback_arg);
throw error;
}
@@ -162,11 +164,10 @@ bool asst::Assistant::append_start_up(bool only_append)
std::unique_lock<std::mutex> lock(m_mutex);
auto task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this);
task_ptr->set_task_chain("StartUp");
task_ptr->set_tasks({ "StartUp" });
task_ptr->set_times_limit("ReturnToTerminal", 0);
task_ptr->set_times_limit("Terminal", 0);
auto task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this, "StartUp");
task_ptr->set_tasks({ "StartUp" })
.set_times_limit("ReturnToTerminal", 0)
.set_times_limit("Terminal", 0);
m_tasks_queue.emplace(task_ptr);
@@ -187,32 +188,29 @@ bool asst::Assistant::append_fight(const std::string& stage, int mecidine, int s
constexpr const char* TaskChain = "Fight";
// 进入选关界面(主界面的“终端”点进去)
auto terminal_task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this);
terminal_task_ptr->set_task_chain(TaskChain);
terminal_task_ptr->set_tasks({ "StageBegin" });
terminal_task_ptr->set_times_limit("LastBattle", 0);
terminal_task_ptr->set_times_limit("StartButton1", 0);
terminal_task_ptr->set_times_limit("StartButton2", 0);
terminal_task_ptr->set_times_limit("MedicineConfirm", 0);
terminal_task_ptr->set_times_limit("StoneConfirm", 0);
auto terminal_task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this, TaskChain);
terminal_task_ptr->set_tasks({ "StageBegin" })
.set_times_limit("LastBattle", 0)
.set_times_limit("StartButton1", 0)
.set_times_limit("StartButton2", 0)
.set_times_limit("MedicineConfirm", 0)
.set_times_limit("StoneConfirm", 0);
// 进入对应的关卡
auto stage_task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this);
stage_task_ptr->set_task_chain(TaskChain);
stage_task_ptr->set_tasks({ stage });
stage_task_ptr->set_times_limit("StartButton1", 0);
stage_task_ptr->set_times_limit("StartButton2", 0);
stage_task_ptr->set_times_limit("MedicineConfirm", 0);
stage_task_ptr->set_times_limit("StoneConfirm", 0);
auto stage_task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this, TaskChain);
stage_task_ptr->set_tasks({ stage })
.set_times_limit("StartButton1", 0)
.set_times_limit("StartButton2", 0)
.set_times_limit("MedicineConfirm", 0)
.set_times_limit("StoneConfirm", 0);
// 开始战斗任务
auto fight_task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this);
fight_task_ptr->set_task_chain(TaskChain);
fight_task_ptr->set_tasks({ "FightBegin" });
fight_task_ptr->set_times_limit("MedicineConfirm", mecidine);
fight_task_ptr->set_times_limit("StoneConfirm", stone);
fight_task_ptr->set_times_limit("StartButton1", times);
fight_task_ptr->set_times_limit("StartButton2", times);
auto fight_task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this, TaskChain);
fight_task_ptr->set_tasks({ "FightBegin" })
.set_times_limit("MedicineConfirm", mecidine)
.set_times_limit("StoneConfirm", stone)
.set_times_limit("StartButton1", times)
.set_times_limit("StartButton2", times);
std::unique_lock<std::mutex> lock(m_mutex);
@@ -260,13 +258,12 @@ bool asst::Assistant::append_mall(bool with_shopping, bool only_append)
std::unique_lock<std::mutex> lock(m_mutex);
const std::string task_chain = "Mall";
const std::string TaskChain = "Mall";
append_process_task("MallBegin", task_chain);
append_process_task("MallBegin", TaskChain);
if (with_shopping) {
auto shopping_task_ptr = std::make_shared<CreditShoppingTask>(task_callback, (void*)this);
shopping_task_ptr->set_task_chain(task_chain);
auto shopping_task_ptr = std::make_shared<CreditShoppingTask>(task_callback, (void*)this, TaskChain);
m_tasks_queue.emplace(shopping_task_ptr);
}
@@ -290,10 +287,9 @@ bool Assistant::append_process_task(const std::string& task_name, std::string ta
task_chain = task_name;
}
auto task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this);
task_ptr->set_task_chain(task_chain);
task_ptr->set_tasks({ task_name });
task_ptr->set_retry_times(retry_times);
auto task_ptr = std::make_shared<ProcessTask>(task_callback, (void*)this, task_chain);
task_ptr->set_tasks({ task_name })
.set_retry_times(retry_times);
m_tasks_queue.emplace(task_ptr);
@@ -314,14 +310,13 @@ bool asst::Assistant::append_recruit(unsigned max_times, const std::vector<int>&
append_process_task("RecruitBegin", TaskChain);
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_use_expedited(use_expedited);
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);
auto recruit_task_ptr = std::make_shared<AutoRecruitTask>(task_callback, (void*)this, TaskChain);
recruit_task_ptr->set_max_times(max_times)
.set_need_refresh(need_refresh)
.set_use_expedited(use_expedited)
.set_select_level(select_level)
.set_confirm_level(confirm_level)
.set_retry_times(AutoRecruitTaskRetryTimesDefault);
m_tasks_queue.emplace(recruit_task_ptr);
@@ -340,11 +335,10 @@ bool Assistant::append_debug()
{
constexpr static const char* DebugTaskChain = "Debug";
auto shift_task_ptr = std::make_shared<InfrastControlTask>(task_callback, (void*)this);
auto shift_task_ptr = std::make_shared<InfrastControlTask>(task_callback, (void*)this, DebugTaskChain);
shift_task_ptr->set_work_mode(infrast::WorkMode::Aggressive);
shift_task_ptr->set_facility("Control");
shift_task_ptr->set_product("MoodAddition");
shift_task_ptr->set_task_chain(DebugTaskChain);
m_tasks_queue.emplace(shift_task_ptr);
}
@@ -361,10 +355,9 @@ bool Assistant::start_recruit_calc(const std::vector<int>& select_level, bool se
std::unique_lock<std::mutex> lock(m_mutex);
auto task_ptr = std::make_shared<RecruitTask>(task_callback, (void*)this);
task_ptr->set_param(select_level, set_time);
auto task_ptr = std::make_shared<RecruitTask>(task_callback, (void*)this, "RecruitCalc");
task_ptr->set_retry_times(OpenRecruitTaskRetryTimesDefault);
task_ptr->set_task_chain("RecruitCalc");
task_ptr->set_param(select_level, set_time);
m_tasks_queue.emplace(task_ptr);
return start(false);
@@ -390,45 +383,37 @@ bool asst::Assistant::append_infrast(infrast::WorkMode work_mode, const std::vec
append_infrast_begin();
auto info_task_ptr = std::make_shared<InfrastInfoTask>(task_callback, (void*)this);
info_task_ptr->set_work_mode(work_mode);
info_task_ptr->set_task_chain(InfrastTaskCahin);
info_task_ptr->set_mood_threshold(dorm_threshold);
auto info_task_ptr = std::make_shared<InfrastInfoTask>(task_callback, (void*)this, InfrastTaskCahin);
info_task_ptr->set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
m_tasks_queue.emplace(info_task_ptr);
// 因为后期要考虑多任务间的联动等所以这些任务的声明暂时不放到for循环中
auto mfg_task_ptr = std::make_shared<InfrastMfgTask>(task_callback, (void*)this);
mfg_task_ptr->set_work_mode(work_mode);
mfg_task_ptr->set_task_chain(InfrastTaskCahin);
mfg_task_ptr->set_mood_threshold(dorm_threshold);
mfg_task_ptr->set_uses_of_drone(uses_of_drones);
auto trade_task_ptr = std::make_shared<InfrastTradeTask>(task_callback, (void*)this);
trade_task_ptr->set_work_mode(work_mode);
trade_task_ptr->set_task_chain(InfrastTaskCahin);
trade_task_ptr->set_mood_threshold(dorm_threshold);
trade_task_ptr->set_uses_of_drone(uses_of_drones);
auto power_task_ptr = std::make_shared<InfrastPowerTask>(task_callback, (void*)this);
power_task_ptr->set_work_mode(work_mode);
power_task_ptr->set_task_chain(InfrastTaskCahin);
power_task_ptr->set_mood_threshold(dorm_threshold);
auto office_task_ptr = std::make_shared<InfrastOfficeTask>(task_callback, (void*)this);
office_task_ptr->set_work_mode(work_mode);
office_task_ptr->set_task_chain(InfrastTaskCahin);
office_task_ptr->set_mood_threshold(dorm_threshold);
auto recpt_task_ptr = std::make_shared<InfrastReceptionTask>(task_callback, (void*)this);
recpt_task_ptr->set_work_mode(work_mode);
recpt_task_ptr->set_task_chain(InfrastTaskCahin);
recpt_task_ptr->set_mood_threshold(dorm_threshold);
auto control_task_ptr = std::make_shared<InfrastControlTask>(task_callback, (void*)this);
control_task_ptr->set_work_mode(work_mode);
control_task_ptr->set_task_chain(InfrastTaskCahin);
control_task_ptr->set_mood_threshold(dorm_threshold);
auto mfg_task_ptr = std::make_shared<InfrastMfgTask>(task_callback, (void*)this, InfrastTaskCahin);
mfg_task_ptr->set_uses_of_drone(uses_of_drones)
.set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
auto trade_task_ptr = std::make_shared<InfrastTradeTask>(task_callback, (void*)this, InfrastTaskCahin);
trade_task_ptr->set_uses_of_drone(uses_of_drones)
.set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
auto power_task_ptr = std::make_shared<InfrastPowerTask>(task_callback, (void*)this, InfrastTaskCahin);
power_task_ptr->set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
auto office_task_ptr = std::make_shared<InfrastOfficeTask>(task_callback, (void*)this, InfrastTaskCahin);
office_task_ptr->set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
auto recpt_task_ptr = std::make_shared<InfrastReceptionTask>(task_callback, (void*)this, InfrastTaskCahin);
recpt_task_ptr->set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
auto control_task_ptr = std::make_shared<InfrastControlTask>(task_callback, (void*)this, InfrastTaskCahin);
control_task_ptr->set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
auto dorm_task_ptr = std::make_shared<InfrastDormTask>(task_callback, (void*)this);
dorm_task_ptr->set_work_mode(work_mode);
dorm_task_ptr->set_task_chain(InfrastTaskCahin);
dorm_task_ptr->set_mood_threshold(dorm_threshold);
auto dorm_task_ptr = std::make_shared<InfrastDormTask>(task_callback, (void*)this, InfrastTaskCahin);
dorm_task_ptr->set_work_mode(work_mode)
.set_mood_threshold(dorm_threshold);
for (const auto& facility : order) {
if (facility == "Dorm") {
@@ -529,12 +514,13 @@ void Assistant::working_proc()
auto task_ptr = m_tasks_queue.front();
std::string cur_taskchain = task_ptr->get_task_chain();
json::value task_json = json::object{
{"task_chain", cur_taskchain},
json::value callback_json = json::object{
{"taskchain", cur_taskchain},
{"pre_taskchain", pre_taskchain}
};
if (cur_taskchain != pre_taskchain) {
task_callback(AsstMsg::TaskChainStart, task_json, this);
task_callback(AsstMsg::TaskChainStart, callback_json, this);
pre_taskchain = cur_taskchain;
}
@@ -542,17 +528,23 @@ void Assistant::working_proc()
bool ret = task_ptr->run();
m_tasks_queue.pop();
if (!ret) {
task_callback(AsstMsg::TaskError, task_json, this);
if (!m_tasks_queue.empty()) {
callback_json["next_taskchain"] = m_tasks_queue.front()->get_task_chain();
}
else if (m_tasks_queue.empty() || cur_taskchain != m_tasks_queue.front()->get_task_chain()) {
task_callback(AsstMsg::TaskChainCompleted, task_json, this);
}
if (m_tasks_queue.empty()) {
task_callback(AsstMsg::AllTasksCompleted, task_json, this);
else {
callback_json["next_taskchain"] = std::string();
}
//clear_cache();
if (!ret) {
task_callback(AsstMsg::TaskChainError, callback_json, this);
}
else if (m_tasks_queue.empty() || cur_taskchain != m_tasks_queue.front()->get_task_chain()) {
task_callback(AsstMsg::TaskChainCompleted, callback_json, this);
}
if (m_tasks_queue.empty()) {
task_callback(AsstMsg::AllTasksCompleted, callback_json, this);
}
auto& delay = Resrc.cfg().get_options().task_delay;
m_condvar.wait_for(lock, std::chrono::milliseconds(delay),
@@ -562,7 +554,6 @@ void Assistant::working_proc()
pre_taskchain.clear();
m_thread_idle = true;
Log.flush();
//controller.set_idle(true);
m_condvar.wait(lock);
}
}
@@ -600,13 +591,14 @@ void Assistant::task_callback(AsstMsg msg, const json::value& detail, void* cust
Assistant* p_this = (Assistant*)custom_arg;
json::value more_detail = detail;
switch (msg) {
case AsstMsg::PtrIsNull:
case AsstMsg::ImageIsEmpty:
case AsstMsg::InternalError:
case AsstMsg::InitFailed:
case AsstMsg::ConnectionError:
p_this->stop(false);
break;
case AsstMsg::StageDrops:
more_detail = p_this->organize_stage_drop(more_detail);
break;
//case AsstMsg::StageDrops:
// more_detail = p_this->organize_stage_drop(more_detail);
// break;
default:
break;
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include <functional>
#include <memory>
#include <ostream>
#include <unordered_map>
@@ -11,84 +10,41 @@ namespace asst
{
enum class AsstMsg
{
/* Error Msg */
PtrIsNull, // 指针为空
ImageIsEmpty, // 图像为空
WindowMinimized, // [已弃用] 窗口被最小化了
InitFaild, // 初始化失败
TaskError, // 任务错误任务一直出错retry次数达到上限
OcrResultError, // Ocr识别结果错误
/* Info Msg: about Task */
TaskStart = 1000, // 任务开始
TaskMatched, // 任务匹配成功
ReachedLimit, // 单个原子任务达到次数上限
ReadyToSleep, // 准备开始睡眠
EndOfSleep, // 睡眠结束
AppendProcessTask, // [已弃用] 新增流程任务Assistant内部消息外部不需要处理
AppendTask, // [已弃用] 新增任务Assistant内部消息外部不需要处理
TaskCompleted, // 单个原子任务完成
PrintWindow, // 截图消息
ProcessTaskStopAction, // 流程任务执行到了Stop的动作
TaskChainCompleted, // 任务链完成
ProcessTaskNotMatched, // 流程任务识别错误
AllTasksCompleted, // 所有任务完成
TaskChainStart, // 开始任务链
/* Info Msg: about Identify */
TextDetected = 2000, // 识别到文字
ImageFindResult, // 查找图像的结果
ImageMatched, // 图像匹配成功
StageDrops, // 关卡掉落信息
/* Open Recruit Msg */
RecruitTagsDetected = 3000, // 公招识别到了Tags
RecruitSpecialTag, // 公招识别到了特殊的Tag
RecruitResult, // 公开招募结果
RecruitSelected, // 选择了Tags
RecruitError, // 公招错误
/* Infrast Msg */
InfrastSkillsDetected = 4000, // 识别到了基建技能(当前页面)
InfrastSkillsResult, // 识别到的所有可用技能
InfrastComb, // 当前房间的最优干员组合
EnterFacility, // 进入某个房间
FacilityInfo, // 当前设施信息
/* Global Info */
InternalError = 0, // 内部错误
InitFailed, // 初始化失败
ConnectionError, // 连接相关错误
AllTasksCompleted, // 全部任务完成
/* TaskChain Info */
TaskChainError = 10000, // 任务链执行/识别错误
TaskChainStart, // 任务链开始
TaskChainCompleted, // 任务链完成
TaskChainExtraInfo, // 任务链额外信息
/* SubTask Info */
SubTaskError = 20000, // 原子任务执行/识别错误
SubTaskStart, // 原子任务开始
SubTaskCompleted, // 原子任务完成
SubTaskExtraInfo // 原子任务额外信息
};
inline std::ostream& operator<<(std::ostream& os, const AsstMsg& type)
{
static const std::unordered_map<AsstMsg, std::string> _type_name = {
{ AsstMsg::PtrIsNull, "PtrIsNull" },
{ AsstMsg::ImageIsEmpty, "ImageIsEmpty" },
{ AsstMsg::RecruitSelected, "RecruitSelected" },
{ AsstMsg::WindowMinimized, "WindowMinimized" },
{ AsstMsg::InitFaild, "InitFaild" },
{ AsstMsg::TaskStart, "TaskStart" },
{ AsstMsg::ImageFindResult, "ImageFindResult" },
{ AsstMsg::ImageMatched, "ImageMatched" },
{ AsstMsg::StageDrops, "StageDrops" },
{ AsstMsg::TaskMatched, "TaskMatched" },
{ AsstMsg::RecruitError, "RecruitError" },
{ AsstMsg::ReachedLimit, "ReachedLimit" },
{ AsstMsg::ReadyToSleep, "ReadyToSleep" },
{ AsstMsg::EndOfSleep, "EndOfSleep" },
{ AsstMsg::AppendProcessTask, "AppendProcessTask" },
{ AsstMsg::TaskCompleted, "TaskCompleted" },
{ AsstMsg::TaskChainCompleted, "TaskChainCompleted" },
{ AsstMsg::TaskChainStart, "TaskChainStart" },
/* Global Info */
{ AsstMsg::InternalError, "InternalError" },
{ AsstMsg::InitFailed, "InitFailed" },
{ AsstMsg::ConnectionError, "ConnectionError" },
{ AsstMsg::AllTasksCompleted, "AllTasksCompleted" },
{ AsstMsg::PrintWindow, "PrintWindow" },
{ AsstMsg::TaskError, "TaskError" },
{ AsstMsg::ProcessTaskNotMatched, "ProcessTaskNotMatched" },
{ AsstMsg::ProcessTaskStopAction, "ProcessTaskStopAction" },
{ AsstMsg::TextDetected, "TextDetected" },
{ AsstMsg::RecruitTagsDetected, "RecruitTagsDetected" },
{ AsstMsg::OcrResultError, "OcrResultError" },
{ AsstMsg::RecruitSpecialTag, "RecruitSpecialTag" },
{ AsstMsg::RecruitResult, "RecruitResult" },
{ AsstMsg::AppendTask, "AppendTask" },
{ AsstMsg::InfrastSkillsDetected, "InfrastSkillsDetected" },
{ AsstMsg::InfrastSkillsResult, "InfrastSkillsResult" },
{ AsstMsg::InfrastComb, "InfrastComb" },
{ AsstMsg::EnterFacility, "EnterFacility" },
{ AsstMsg::FacilityInfo, "FacilityInfo" }
/* TaskChain Info */
{ AsstMsg::TaskChainError, "TaskChainError" },
{ AsstMsg::TaskChainStart, "TaskChainStart" },
{ AsstMsg::TaskChainCompleted, "TaskChainCompleted" },
{ AsstMsg::TaskChainExtraInfo, "TaskChainExtraInfo" },
/* SubTask Info */
{ AsstMsg::SubTaskError, "SubTaskError" },
{ AsstMsg::SubTaskStart, "SubTaskStart" },
{ AsstMsg::SubTaskCompleted, "SubTaskCompleted" },
{ AsstMsg::SubTaskExtraInfo, "SubTaskExtraInfo" },
};
return os << _type_name.at(type);
}

View File

@@ -7,39 +7,38 @@
#include "ProcessTask.h"
#include "RecruitTask.h"
void asst::AutoRecruitTask::set_select_level(std::vector<int> select_level) noexcept
asst::AutoRecruitTask& asst::AutoRecruitTask::set_select_level(std::vector<int> select_level) noexcept
{
m_select_level = std::move(select_level);
return *this;
}
void asst::AutoRecruitTask::set_confirm_level(std::vector<int> confirm_level) noexcept
asst::AutoRecruitTask& asst::AutoRecruitTask::set_confirm_level(std::vector<int> confirm_level) noexcept
{
m_confirm_level = std::move(confirm_level);
return *this;
}
void asst::AutoRecruitTask::set_need_refresh(bool need_refresh) noexcept
asst::AutoRecruitTask& asst::AutoRecruitTask::set_need_refresh(bool need_refresh) noexcept
{
m_need_refresh = need_refresh;
return *this;
}
void asst::AutoRecruitTask::set_max_times(int max_times) noexcept
asst::AutoRecruitTask& asst::AutoRecruitTask::set_max_times(int max_times) noexcept
{
m_max_times = max_times;
return *this;
}
void asst::AutoRecruitTask::set_use_expedited(bool use_or_not) noexcept
asst::AutoRecruitTask& asst::AutoRecruitTask::set_use_expedited(bool use_or_not) noexcept
{
m_use_expedited = use_or_not;
return *this;
}
bool asst::AutoRecruitTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "RecruitTask" },
{ "task_chain", m_task_chain },
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
if (!check_recruit_home_page()) {
return false;
}
@@ -110,14 +109,13 @@ bool asst::AutoRecruitTask::recruit_index(size_t index)
bool asst::AutoRecruitTask::calc_and_recruit()
{
RecruitTask recurit_task(m_callback, m_callback_arg);
RecruitTask recurit_task(m_callback, m_callback_arg, m_task_chain);
recurit_task.set_retry_times(m_retry_times);
recurit_task.set_param(m_select_level, true);
recurit_task.set_task_chain(m_task_chain);
// 识别错误,放弃这个公招位,直接返回
if (!recurit_task.run()) {
m_callback(AsstMsg::RecruitError, json::value(), m_callback_arg);
m_callback(AsstMsg::SubTaskError, basic_info(), m_callback_arg);
click_return_button();
return true;
}

View File

@@ -11,11 +11,11 @@ namespace asst
using AbstractTask::AbstractTask;
virtual ~AutoRecruitTask() = default;
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;
void set_use_expedited(bool use_or_not) noexcept;
AutoRecruitTask& set_select_level(std::vector<int> select_level) noexcept;
AutoRecruitTask& set_confirm_level(std::vector<int> confirm_level) noexcept;
AutoRecruitTask& set_need_refresh(bool need_refresh) noexcept;
AutoRecruitTask& set_max_times(int max_times) noexcept;
AutoRecruitTask& set_use_expedited(bool use_or_not) noexcept;
protected:
virtual bool _run() override;

View File

@@ -13,12 +13,6 @@
bool asst::CreditShoppingTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "CreditShoppingTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
const cv::Mat image = Ctrler.get_image();
CreditShopImageAnalyzer shop_analyzer(image);
@@ -78,6 +72,5 @@ bool asst::CreditShoppingTask::_run()
Ctrler.click(buy_it_rect);
sleep(rare_delay);
}
return true;
}

View File

@@ -12,8 +12,8 @@
int asst::InfrastAbstractTask::m_face_hash_thres = 0;
int asst::InfrastAbstractTask::m_name_hash_thres = 0;
asst::InfrastAbstractTask::InfrastAbstractTask(AsstCallback callback, void* callback_arg)
: AbstractTask(callback, callback_arg)
asst::InfrastAbstractTask::InfrastAbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain)
: AbstractTask(callback, callback_arg, std::move(task_chain))
{
if (m_face_hash_thres == 0) {
m_face_hash_thres = static_cast<int>(std::dynamic_pointer_cast<MatchTaskInfo>(
@@ -25,7 +25,7 @@ asst::InfrastAbstractTask::InfrastAbstractTask(AsstCallback callback, void* call
}
}
void asst::InfrastAbstractTask::set_work_mode(infrast::WorkMode work_mode) noexcept
asst::InfrastAbstractTask& asst::InfrastAbstractTask::set_work_mode(infrast::WorkMode work_mode) noexcept
{
m_work_mode = work_mode;
switch (work_mode) {
@@ -42,11 +42,13 @@ void asst::InfrastAbstractTask::set_work_mode(infrast::WorkMode work_mode) noexc
m_work_mode_name.clear();
break;
}
return *this;
}
void asst::InfrastAbstractTask::set_mood_threshold(double mood_thres) noexcept
asst::InfrastAbstractTask& asst::InfrastAbstractTask::set_mood_threshold(double mood_thres) noexcept
{
m_mood_threshold = mood_thres;
return *this;
}
bool asst::InfrastAbstractTask::on_run_fails()
@@ -60,12 +62,13 @@ bool asst::InfrastAbstractTask::on_run_fails()
bool asst::InfrastAbstractTask::enter_facility(const std::string& facility, int index)
{
LogTraceFunction;
json::value enter_json = json::object{
json::value info = basic_info();
info["what"] = "EnterFacility";
info["details"] = json::object{
{ "facility", facility },
{ "index", index }
};
m_callback(AsstMsg::EnterFacility, enter_json, m_callback_arg);
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
const auto image = Ctrler.get_image();
@@ -103,14 +106,14 @@ 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 basic_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");
Log.trace("the stationed basic_info button found");
Ctrler.click(station_analyzer.get_result().front().rect);
sleep(stationedinfo_task_ptr->rear_delay);
// 点开了按钮之后,再识别一次右边的
@@ -122,7 +125,7 @@ bool asst::InfrastAbstractTask::enter_oper_list_page()
}
}
else {
Log.error("no stationed info button");
Log.error("no stationed basic_info button");
return false;
}
}

View File

@@ -9,11 +9,11 @@ namespace asst
{
public:
using AbstractTask::AbstractTask;
InfrastAbstractTask(AsstCallback callback, void* callback_arg);
InfrastAbstractTask(AsstCallback callback, void* callback_arg, std::string task_chain);
virtual ~InfrastAbstractTask() = default;
virtual void set_work_mode(infrast::WorkMode work_mode) noexcept;
virtual void set_mood_threshold(double mood_thres) noexcept;
virtual InfrastAbstractTask& set_work_mode(infrast::WorkMode work_mode) noexcept;
virtual InfrastAbstractTask& set_mood_threshold(double mood_thres) noexcept;
constexpr static int OperSelectRetryTimes = 3;
protected:

View File

@@ -4,12 +4,6 @@ const std::string asst::InfrastControlTask::FacilityName = "Control";
bool asst::InfrastControlTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastControlTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
set_facility(FacilityName);
m_all_available_opers.clear();

View File

@@ -11,12 +11,6 @@ const std::string asst::InfrastDormTask::FacilityName = "Dorm";
bool asst::InfrastDormTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastDormTask" },
{ "task_chain", m_task_chain }
};
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;

View File

@@ -8,12 +8,6 @@
bool asst::InfrastInfoTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastInfoTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
swipe_to_the_left_of_main_ui();
const auto image = Ctrler.get_image();

View File

@@ -8,12 +8,6 @@ const std::string asst::InfrastMfgTask::FacilityName = "Mfg";
bool asst::InfrastMfgTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastMfgTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
set_facility(FacilityName);
m_all_available_opers.clear();

View File

@@ -6,12 +6,6 @@ const std::string asst::InfrastOfficeTask::FacilityName = "Office";
bool asst::InfrastOfficeTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastOfficeTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
set_facility(FacilityName);
m_all_available_opers.clear();

View File

@@ -6,12 +6,6 @@ const std::string asst::InfrastPowerTask::FacilityName = "Power";
bool asst::InfrastPowerTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastPowerTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
set_facility(FacilityName);
m_all_available_opers.clear();

View File

@@ -14,6 +14,24 @@
#include "RuntimeStatus.h"
#include "ProcessTask.h"
asst::InfrastProductionTask& asst::InfrastProductionTask::set_uses_of_drone(std::string uses_of_drones) noexcept
{
m_uses_of_drones = std::move(uses_of_drones);
return *this;
}
asst::InfrastProductionTask& asst::InfrastProductionTask::set_facility(std::string facility_name) noexcept
{
m_facility = std::move(facility_name);
return *this;
}
asst::InfrastProductionTask& asst::InfrastProductionTask::set_product(std::string product_name) noexcept
{
m_product = std::move(product_name);
return *this;
}
bool asst::InfrastProductionTask::shift_facility_list()
{
LogTraceFunction;
@@ -41,11 +59,13 @@ bool asst::InfrastProductionTask::shift_facility_list()
return false;
}
if (index != 0) {
json::value enter_json = json::object{
json::value info = basic_info();
info["what"] = "EnterFacility";
info["details"] = json::object{
{ "facility", m_facility },
{ "index", index }
};
m_callback(AsstMsg::EnterFacility, enter_json, m_callback_arg);
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
}
++index;

View File

@@ -13,24 +13,16 @@ namespace asst
using InfrastAbstractTask::InfrastAbstractTask;
virtual ~InfrastProductionTask() = default;
void set_uses_of_drone(std::string uses_of_drones) noexcept
{
m_uses_of_drones = std::move(uses_of_drones);
}
InfrastProductionTask& set_uses_of_drone(std::string uses_of_drones) noexcept;
#ifdef ASST_DEBUG
public:
#else
// 为了方便调试把这两个个接口拿到public来了
protected:
#endif
void set_facility(std::string facility_name) noexcept
{
m_facility = std::move(facility_name);
}
void set_product(std::string product_name) noexcept
{
m_product = std::move(product_name);
}
InfrastProductionTask& set_facility(std::string facility_name) noexcept;
InfrastProductionTask& set_product(std::string product_name) noexcept;
protected:
bool shift_facility_list();

View File

@@ -12,12 +12,6 @@ const std::string asst::InfrastReceptionTask::FacilityName = "Reception";
bool asst::InfrastReceptionTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastReceptionTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
set_facility(FacilityName);
m_all_available_opers.clear();

View File

@@ -4,12 +4,6 @@ const std::string asst::InfrastTradeTask::FacilityName = "Trade";
bool asst::InfrastTradeTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "InfrastTradeTask" },
{ "task_chain", m_task_chain }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
set_facility(FacilityName);
m_all_available_opers.clear();

View File

@@ -25,20 +25,53 @@ asst::ProcessTask::ProcessTask(AbstractTask&& abs, std::vector<std::string> task
m_cur_tasks_name(std::move(tasks_name))
{}
bool asst::ProcessTask::run()
{
for (m_cur_retry = 0; m_cur_retry < m_retry_times; ++m_cur_retry) {
if (_run()) {
return true;
}
if (need_exit()) {
return false;
}
int delay = Resrc.cfg().get_options().task_delay;
sleep(delay);
if (!on_run_fails()) {
return false;
}
}
m_callback(AsstMsg::SubTaskError, basic_info(), m_callback_arg);
return false;
}
asst::ProcessTask& asst::ProcessTask::set_tasks(std::vector<std::string> tasks_name) noexcept
{
m_cur_tasks_name = std::move(tasks_name);
return *this;
}
ProcessTask& asst::ProcessTask::set_times_limit(std::string name, int limit)
{
m_times_limit.emplace(std::move(name), limit);
return *this;
}
bool ProcessTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "ProcessTask" },
{ "task_chain", m_task_chain },
{ "tasks", json::array(m_cur_tasks_name) }
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
LogTraceFunction;
auto& task_delay = Resrc.cfg().get_options().task_delay;
while (!m_cur_tasks_name.empty()) {
if (need_exit()) {
return false;
}
json::value info = basic_info();
info["details"] = json::object{
{"to_be_recognized", json::array(m_cur_tasks_name)}
};
Log.info(info.to_string());
Rect rect;
// 如果第一个任务是JustReturn的那就没必要再截图并计算了
if (auto front_task_ptr = Task.get(m_cur_tasks_name.front());
@@ -69,39 +102,29 @@ bool ProcessTask::_run()
int& exec_times = m_exec_times[cur_name];
json::value callback_json = json::object{
{ "name", cur_name },
{ "type", static_cast<int>(m_cur_task_ptr->action) },
{ "exec_times", exec_times },
{ "max_times", m_cur_task_ptr->max_times },
{ "task_type", "ProcessTask" },
{ "algorithm", static_cast<int>(m_cur_task_ptr->algorithm) }
};
m_callback(AsstMsg::TaskMatched, callback_json, m_callback_arg);
int max_times = m_cur_task_ptr->max_times;
if (auto iter = m_times_limit.find(cur_name);
iter != m_times_limit.cend()) {
max_times = iter->second;
callback_json["times_limit"] = max_times;
}
info["details"] = json::object{
{ "task", cur_name },
{ "action", static_cast<int>(m_cur_task_ptr->action) },
{ "exec_times", exec_times },
{ "max_times", max_times },
{ "algorithm", static_cast<int>(m_cur_task_ptr->algorithm) }
};
if (exec_times >= max_times) {
m_callback(AsstMsg::ReachedLimit, callback_json, m_callback_arg);
json::value next_json = callback_json;
next_json["tasks"] = json::array(m_cur_task_ptr->exceeded_next);
next_json["retry_times"] = m_retry_times;
next_json["task_chain"] = m_task_chain;
//m_callback(AsstMsg::AppendProcessTask, next_json, m_callback_arg);
//return true;
Log.trace(next_json.to_string());
Log.info("exec times exceeds the limit", info.to_string());
set_tasks(m_cur_task_ptr->exceeded_next);
sleep(task_delay);
continue;
}
m_callback(AsstMsg::SubTaskStart, info, m_callback_arg);
// 前置固定延时
if (!sleep(m_cur_task_ptr->pre_delay)) {
return false;
@@ -127,7 +150,7 @@ bool ProcessTask::_run()
case ProcessTaskAction::DoNothing:
break;
case ProcessTaskAction::Stop:
m_callback(AsstMsg::ProcessTaskStopAction, json::object{ { "task_chain", m_task_chain } }, m_callback_arg);
Log.info("stop action", info.to_string());
need_stop = true;
break;
case ProcessTaskAction::StageDrops: {
@@ -137,7 +160,6 @@ bool ProcessTask::_run()
break;
}
m_cur_retry = 0;
++exec_times;
Status.set("Last" + cur_name, time(nullptr));
@@ -149,12 +171,8 @@ bool ProcessTask::_run()
--m_exec_times[reduce];
}
if (need_stop) {
return true;
}
callback_json["exec_times"] = exec_times;
m_callback(AsstMsg::TaskCompleted, callback_json, m_callback_arg);
info["details"]["exec_times"] = exec_times;
m_callback(AsstMsg::SubTaskCompleted, info, m_callback_arg);
// 后置固定延时
int rear_delay = m_cur_task_ptr->rear_delay;
@@ -166,12 +184,9 @@ bool ProcessTask::_run()
return false;
}
json::value next_json = callback_json;
next_json["task_chain"] = m_task_chain;
next_json["retry_times"] = m_retry_times;
next_json["tasks"] = json::array(m_cur_task_ptr->next);
Log.trace(next_json.to_string());
if (need_stop) {
return true;
}
set_tasks(m_cur_task_ptr->next);
sleep(task_delay);
}
@@ -183,7 +198,12 @@ void asst::ProcessTask::exec_stage_drops()
{
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);
json::value info = basic_info();
info["what"] = "StageDrops";
info["details"] = json::parse(res).value();
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
if (m_rear_delay.find("StartButton2") == m_rear_delay.cend()) {
int64_t start_times = Status.get("LastStartButton2");

View File

@@ -15,17 +15,14 @@ namespace asst
virtual ~ProcessTask() = default;
void set_tasks(std::vector<std::string> tasks_name) noexcept
{
m_cur_tasks_name = std::move(tasks_name);
}
void set_times_limit(std::string name, int limit)
{
m_times_limit.emplace(std::move(name), limit);
}
virtual bool run() override;
ProcessTask& set_tasks(std::vector<std::string> tasks_name) noexcept;
ProcessTask& set_times_limit(std::string name, int limit);
protected:
virtual bool _run() override;
void exec_stage_drops();
void exec_click_task(const Rect& matched_rect);
void exec_swipe_task(ProcessTaskAction action);

View File

@@ -12,22 +12,11 @@ using namespace asst;
bool RecruitTask::_run()
{
json::value task_start_json = json::object{
{ "task_type", "RecruitTask_run" },
{ "task_chain", m_task_chain },
};
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
m_maybe_level = 0;
m_has_special_tag = false;
m_has_refresh = false;
const cv::Mat image = Ctrler.get_image();
if (image.empty()) {
m_callback(AsstMsg::ImageIsEmpty, task_start_json, m_callback_arg);
return false;
}
RecruitImageAnalyzer analyzer(image);
if (!analyzer.analyze()) {
@@ -48,29 +37,29 @@ bool RecruitTask::_run()
all_tags_name.emplace(text_area.text);
all_tags_json_vector.emplace_back(text_area.text);
}
json::value all_tags_json;
all_tags_json["tags"] = json::array(all_tags_json_vector);
all_tags_json["task_chain"] = m_task_chain;
/* 过滤tags数量不足的情况可能是识别漏了 */
if (all_tags.size() != RecruitConfiger::CorrectNumberOfTags) {
//all_tags_json["type"] = "OpenRecruit";
//m_callback(AsstMsg::OcrResultError, all_tags_json, m_callback_arg);
return false;
}
m_callback(AsstMsg::RecruitTagsDetected, all_tags_json, m_callback_arg);
json::value info = basic_info();
info["what"] = "RecruitTagsDetected";
info["details"] = json::object{
{ "tags", json::array(all_tags_json_vector) }
};
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
/* 针对特殊Tag的额外回调消息 */
static const std::string SeniorOper = "高级资深干员";
static const std::string SupportMachine = "支援机械";
const std::vector<std::string> SpecialTags = { SeniorOper, SupportMachine };
const std::vector<std::string> SpecialTags = { SeniorOper, "资深干员" };
auto special_iter = std::find_first_of(SpecialTags.cbegin(), SpecialTags.cend(), all_tags_name.cbegin(), all_tags_name.cend());
if (special_iter != SpecialTags.cend()) {
json::value special_tag_json;
special_tag_json["tag"] = *special_iter;
m_callback(AsstMsg::RecruitSpecialTag, special_tag_json, m_callback_arg);
info["what"] = "RecruitSpecialTag";
info["details"] = json::object{
{ "tag", *special_iter }
};
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
m_has_special_tag = true;
}
@@ -174,8 +163,7 @@ bool RecruitTask::_run()
/* 整理识别结果Json */
json::value results_json;
results_json["result"] = json::array();
results_json["maybe_level"] = m_maybe_level;
results_json["task_chain"] = m_task_chain;
results_json["level"] = m_maybe_level;
std::vector<json::value> result_json_vector;
for (const auto& comb : result_vec) {
@@ -196,10 +184,12 @@ bool RecruitTask::_run()
opers_json_vector.emplace_back(std::move(oper_json));
}
comb_json["opers"] = json::array(std::move(opers_json_vector));
comb_json["tag_level"] = comb.min_level;
comb_json["level"] = comb.min_level;
results_json["result"].as_array().emplace_back(std::move(comb_json));
}
m_callback(AsstMsg::RecruitResult, results_json, m_callback_arg);
info["what"] = "RecruitResult";
info["details"] = results_json;
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
if (!result_vec.empty()) {
/* 点击最优解的tags */
@@ -212,18 +202,20 @@ bool RecruitTask::_run()
}
}
json::value selected_json;
selected_json["tags"] = json::array(final_tags_name);
selected_json["task_chain"] = m_task_chain;
m_callback(AsstMsg::RecruitSelected, selected_json, m_callback_arg);
info["what"] = "RecruitTagsSelected";
info["details"] = json::object{
{ "tags", json::array(final_tags_name) }
};
m_callback(AsstMsg::SubTaskExtraInfo, info, m_callback_arg);
}
}
return true;
}
void RecruitTask::set_param(std::vector<int> select_level, bool set_time) noexcept
RecruitTask& RecruitTask::set_param(std::vector<int> select_level, bool set_time) noexcept
{
m_select_level = std::move(select_level);
m_set_time = set_time;
return *this;
}

View File

@@ -12,7 +12,7 @@ namespace asst
using AbstractTask::AbstractTask;
virtual ~RecruitTask() = default;
void set_param(std::vector<int> select_level, bool set_time = true) noexcept;
RecruitTask& set_param(std::vector<int> select_level, bool set_time = true) noexcept;
bool get_has_special_tag() const noexcept
{

View File

@@ -23,7 +23,7 @@ namespace MeoAsstGui
{
private delegate void CallbackDelegate(int msg, IntPtr json_buffer, IntPtr custom_arg);
private delegate void ProcCallbckMsg(AsstMsg msg, JObject detail);
private delegate void ProcCallbckMsg(AsstMsg msg, JObject details);
[DllImport("MeoAssistant.dll")] private static extern IntPtr AsstCreate(string dirname);
@@ -80,7 +80,6 @@ namespace MeoAsstGui
tvm.Idle = true;
}
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
internal static extern int lstrlenA(IntPtr ptr);
@@ -105,7 +104,7 @@ namespace MeoAsstGui
string json_str = PtrToStringCustom(json_buffer, System.Text.Encoding.UTF8);
//Console.WriteLine(json_str);
JObject json = (JObject)JsonConvert.DeserializeObject(json_str);
ProcCallbckMsg dlg = new ProcCallbckMsg(proc_msg);
ProcCallbckMsg dlg = new ProcCallbckMsg(procMsg);
Execute.OnUIThread(() =>
{
dlg((AsstMsg)msg, json);
@@ -116,80 +115,166 @@ namespace MeoAsstGui
private readonly IContainer _container;
private IntPtr _ptr;
private void proc_msg(AsstMsg msg, JObject detail)
private void procMsg(AsstMsg msg, JObject details)
{
var tvm = _container.Get<TaskQueueViewModel>();
switch (msg)
{
case AsstMsg.TaskStart:
case AsstMsg.InternalError:
break;
case AsstMsg.InitFailed:
_windowManager.ShowMessageBox("初始化错误!请检查是否使用了中文路径", "错误");
Environment.Exit(0);
break;
case AsstMsg.ConnectionError:
break;
case AsstMsg.TaskChainError:
case AsstMsg.TaskChainStart:
case AsstMsg.TaskChainExtraInfo:
case AsstMsg.AllTasksCompleted:
procTaskChainMsg(msg, details);
break;
case AsstMsg.SubTaskError:
case AsstMsg.SubTaskStart:
case AsstMsg.SubTaskCompleted:
case AsstMsg.SubTaskExtraInfo:
procSubTaskMsg(msg, details);
break;
}
}
private void procTaskChainMsg(AsstMsg msg, JObject details)
{
string taskChain = details["taskchain"].ToString();
if (taskChain == "RecruitCalc")
{
if (msg == AsstMsg.TaskChainError)
{
var recruitModel = _container.Get<RecruitViewModel>();
recruitModel.RecruitInfo = "识别错误!";
}
return;
}
var mainModel = _container.Get<TaskQueueViewModel>();
switch (msg)
{
case AsstMsg.TaskChainError:
mainModel.AddLog("任务出错:" + taskChain, "darkred");
break;
case AsstMsg.TaskChainStart:
{
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
{
break;
}
tvm.AddLog("开始任务:" + taskChain);
}
mainModel.AddLog("开始任务:" + taskChain);
break;
case AsstMsg.TaskCompleted:
{
string taskName = detail["name"].ToString();
if (taskName == "StartButton2")
{
tvm.AddLog("已开始行动 " + (int)detail["exec_times"] + " 次", "darkcyan");
}
else if (taskName == "MedicineConfirm")
{
tvm.AddLog("已吃药 " + (int)detail["exec_times"] + " 个", "darkcyan");
}
else if (taskName == "StoneConfirm")
{
tvm.AddLog("已碎石 " + (int)detail["exec_times"] + " 颗", "darkcyan");
}
else if (taskName == "RecruitRefreshConfirm")
{
tvm.AddLog("已刷新标签", "darkcyan");
}
else if (taskName == "RecruitConfirm")
{
tvm.AddLog("已确认招募", "darkcyan");
}
}
break;
case AsstMsg.TaskChainCompleted:
{
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
{
break;
}
tvm.AddLog("完成任务:" + taskChain);
}
case AsstMsg.TaskChainExtraInfo:
break;
case AsstMsg.AllTasksCompleted:
{
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
{
break;
}
tvm.Idle = true;
tvm.AddLog("任务已全部完成");
new ToastContentBuilder().AddText("任务已全部完成!").Show();
tvm.CheckAndShutdown();
}
mainModel.Idle = true;
mainModel.AddLog("任务已全部完成");
new ToastContentBuilder().AddText("任务已全部完成!").Show();
mainModel.CheckAndShutdown();
break;
}
}
private void procSubTaskMsg(AsstMsg msg, JObject details)
{
string taskChain = details["taskchain"].ToString();
string classType = details["class"].ToString();
var mainModel = _container.Get<TaskQueueViewModel>();
switch (msg)
{
case AsstMsg.SubTaskError:
procSubTaskError(details);
break;
case AsstMsg.StageDrops:
case AsstMsg.SubTaskStart:
break;
case AsstMsg.SubTaskCompleted:
procSubTaskCompleted(details);
break;
case AsstMsg.SubTaskExtraInfo:
procSubTaskExtraInfo(details);
break;
}
}
private void procSubTaskError(JObject details)
{
string classType = details["class"].ToString();
var mainModel = _container.Get<TaskQueueViewModel>();
if (classType == "class asst::AutoRecruitTask")
{
mainModel.AddLog("公招识别错误,已返回", "darkred");
}
}
private void procSubTaskCompleted(JObject details)
{
string classType = details["class"].ToString();
var mainModel = _container.Get<TaskQueueViewModel>();
if (classType == "class asst::ProcessTask")
{
string taskName = details["details"]["task"].ToString();
int execTimes = (int)details["details"]["exec_times"];
switch (taskName)
{
case "StartButton2":
mainModel.AddLog("已开始行动 " + execTimes + " 次", "darkcyan");
break;
case "MedicineConfirm":
mainModel.AddLog("已吃药 " + execTimes + " 个", "darkcyan");
break;
case "StoneConfirm":
mainModel.AddLog("已碎石 " + execTimes + " 颗", "darkcyan");
break;
case "RecruitRefreshConfirm":
mainModel.AddLog("已刷新标签", "darkcyan");
break;
case "RecruitConfirm":
mainModel.AddLog("已确认招募", "darkcyan");
break;
}
}
}
private void procSubTaskExtraInfo(JObject details)
{
string taskChain = details["taskchain"].ToString();
if (taskChain == "RecruitCalc")
{
procRecruitCalcMsg(details);
return;
}
string what = details["what"].ToString();
var subTaskDetails = details["details"];
var mainModel = _container.Get<TaskQueueViewModel>();
switch (what)
{
case "StageDrops":
{
string cur_drops = "";
JArray drops = (JArray)detail["drops"];
JArray drops = (JArray)subTaskDetails["drops"];
foreach (var item in drops)
{
string itemName = item["itemName"].ToString();
@@ -197,10 +282,10 @@ namespace MeoAsstGui
cur_drops += $"{itemName} : {count}\n";
}
cur_drops = cur_drops.EndsWith("\n") ? cur_drops.TrimEnd('\n') : "无";
tvm.AddLog("当次掉落:\n" + cur_drops);
mainModel.AddLog("当次掉落:\n" + cur_drops);
string all_drops = "";
JArray statistics = (JArray)detail["statistics"];
JArray statistics = (JArray)details["statistics"];
foreach (var item in statistics)
{
string itemName = item["itemName"].ToString();
@@ -208,128 +293,103 @@ namespace MeoAsstGui
all_drops += $"{itemName} : {count}\n";
}
all_drops = all_drops.EndsWith("\n") ? all_drops.TrimEnd('\n') : "无";
tvm.AddLog("掉落统计:\n" + all_drops);
mainModel.AddLog("掉落统计:\n" + all_drops);
}
break;
case AsstMsg.TextDetected:
case "EnterFacility":
mainModel.AddLog("当前设施:" + subTaskDetails["facility"] + " " + (int)subTaskDetails["index"]);
break;
case AsstMsg.RecruitTagsDetected:
case AsstMsg.OcrResultError:
case AsstMsg.RecruitSpecialTag:
case AsstMsg.RecruitResult:
case AsstMsg.RecruitSelected:
case AsstMsg.RecruitError:
recruit_proc_msg(msg, detail);
break;
/* Infrast Msg */
case AsstMsg.InfrastSkillsDetected:
case AsstMsg.InfrastSkillsResult:
case AsstMsg.InfrastComb:
case AsstMsg.EnterFacility:
case AsstMsg.FacilityInfo:
infrast_proc_msg(msg, detail);
break;
case AsstMsg.TaskError:
case "RecruitTagsDetected":
{
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
JArray tags = (JArray)subTaskDetails["tags"];
string log_content = "";
foreach (var tag_name in tags)
{
var rvm = _container.Get<RecruitViewModel>();
rvm.RecruitInfo = "识别错误!";
string tag_str = tag_name.ToString();
log_content += tag_str + "\n";
}
log_content = log_content.EndsWith("\n") ? log_content.TrimEnd('\n') : "错误";
mainModel.AddLog("公招识别结果:\n" + log_content);
}
break;
case "RecruitSpecialTag":
{
string special = subTaskDetails["tag"].ToString();
new ToastContentBuilder().AddText("公招提示:" + special).Show();
}
break;
case "RecruitResult":
{
int level = (int)subTaskDetails["level"];
if (level >= 5)
{
new ToastContentBuilder().AddText("公招出 " + level + " 星了哦!").Show();
mainModel.AddLog(level + " 星 Tags", "darkorange", "Bold");
}
else
{
tvm.AddLog("任务出错:" + detail["task_chain"].ToString(), "darkred");
mainModel.AddLog(level + " 星 Tags", "darkcyan");
}
}
break;
case AsstMsg.InitFaild:
_windowManager.ShowMessageBox("初始化错误!请检查是否使用了中文路径", "错误");
Environment.Exit(0);
break;
}
}
private void infrast_proc_msg(AsstMsg msg, JObject detail)
{
var tvm = _container.Get<TaskQueueViewModel>();
switch (msg)
{
case AsstMsg.InfrastSkillsDetected:
break;
case AsstMsg.InfrastSkillsResult:
break;
case AsstMsg.InfrastComb:
break;
case AsstMsg.EnterFacility:
tvm.AddLog("当前设施:" + detail["facility"] + " " + (int)detail["index"]);
break;
case AsstMsg.FacilityInfo:
break;
case AsstMsg.TaskChainCompleted:
break;
}
}
private void recruit_proc_msg(AsstMsg msg, JObject detail)
{
var rvm = _container.Get<RecruitViewModel>();
var tvm = _container.Get<TaskQueueViewModel>();
switch (msg)
{
case AsstMsg.TextDetected:
break;
case AsstMsg.RecruitTagsDetected:
case "RecruitTagsSelected":
{
JArray tags = (JArray)detail["tags"];
string log_content = "";
JArray selected = (JArray)details["tags"];
string selected_log = "";
foreach (var tag in selected)
{
selected_log += tag.ToString() + "\n";
}
selected_log = selected_log.EndsWith("\n") ? selected_log.TrimEnd('\n') : "无";
mainModel.AddLog("选择 Tags\n" + selected_log);
}
break;
}
}
private void procRecruitCalcMsg(JObject details)
{
string what = details["what"].ToString();
var subTaskDetails = details["details"];
var recruitModel = _container.Get<RecruitViewModel>();
switch (what)
{
case "RecruitTagsDetected":
{
JArray tags = (JArray)subTaskDetails["tags"];
string info_content = "识别结果: ";
foreach (var tag_name in tags)
{
string tag_str = tag_name.ToString();
info_content += tag_str + " ";
log_content += tag_str + "\n";
}
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
{
rvm.RecruitInfo = info_content;
}
else
{
log_content = log_content.EndsWith("\n") ? log_content.TrimEnd('\n') : "错误";
tvm.AddLog("公招识别结果:\n" + log_content);
}
recruitModel.RecruitInfo = info_content;
}
break;
case AsstMsg.OcrResultError:
rvm.RecruitInfo = "识别错误!";
case "RecruitSpecialTag":
{
string special = subTaskDetails["tag"].ToString();
new ToastContentBuilder().AddText("公招提示:" + special).Show();
}
break;
case AsstMsg.RecruitSpecialTag:
string special = detail["tag"].ToString();
new ToastContentBuilder().AddText("公招提示:" + special).Show();
break;
case AsstMsg.RecruitResult:
case "RecruitResult":
{
string resultContent = "";
JArray result_array = (JArray)detail["result"];
int combs_level = (int)detail["maybe_level"];
JArray result_array = (JArray)subTaskDetails["result"];
int level = (int)subTaskDetails["level"];
foreach (var combs in result_array)
{
int tag_level = (int)combs["tag_level"];
int tag_level = (int)combs["level"];
resultContent += tag_level + "星Tags: ";
foreach (var tag in (JArray)combs["tags"])
{
@@ -342,50 +402,12 @@ namespace MeoAsstGui
}
resultContent += "\n\n";
}
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
recruitModel.RecruitResult = resultContent;
if (level >= 5)
{
rvm.RecruitResult = resultContent;
}
if (combs_level >= 5)
{
new ToastContentBuilder().AddText("公招出 " + combs_level + " 星了哦!").Show();
if (taskChain != "RecruitCalc")
{
tvm.AddLog(combs_level + " 星Tags", "darkorange", "Bold");
}
}
else
{
if (taskChain != "RecruitCalc")
{
tvm.AddLog(combs_level + " 星Tags", "darkcyan");
}
new ToastContentBuilder().AddText("公招出 " + level + " 星了哦!").Show();
}
}
break;
case AsstMsg.RecruitSelected:
{
string taskChain = detail["task_chain"].ToString();
if (taskChain == "RecruitCalc")
{
break;
}
JArray selected = (JArray)detail["tags"];
string selected_log = "";
foreach (var tag in selected)
{
selected_log += tag.ToString() + "\n";
}
selected_log = selected_log.EndsWith("\n") ? selected_log.TrimEnd('\n') : "无";
tvm.AddLog("选择Tags\n" + selected_log);
break;
}
case AsstMsg.RecruitError:
tvm.AddLog("公招识别错误,已返回", "darkred");
break;
}
}
@@ -467,45 +489,21 @@ namespace MeoAsstGui
public enum AsstMsg
{
/* Error Msg */
PtrIsNull, // 指针为空
ImageIsEmpty, // 图像为空
WindowMinimized, // [已弃用] 窗口被最小化了
InitFaild, // 初始化失败
TaskError, // 任务错误任务一直出错retry次数达到上限
OcrResultError, // Ocr识别结果错误
/* Info Msg: about Task */
TaskStart = 1000, // 任务开始
TaskMatched, // 任务匹配成功
ReachedLimit, // 单个原子任务达到次数上限
ReadyToSleep, // 准备开始睡眠
EndOfSleep, // 睡眠结束
AppendProcessTask, // 新增流程任务Assistant内部消息外部不需要处理
AppendTask, // 新增任务Assistant内部消息外部不需要处理
TaskCompleted, // 单个原子任务完成
PrintWindow, // 截图消息
ProcessTaskStopAction, // 流程任务执行到了Stop的动作
TaskChainCompleted, // 任务链完成
ProcessTaskNotMatched, // 流程任务识别错误
AllTasksCompleted, // 所有任务完成
TaskChainStart, // 开始任务链
/* Info Msg: about Identify */
TextDetected = 2000, // 识别到文字
ImageFindResult, // 查找图像的结果
ImageMatched, // 图像匹配成功
StageDrops, // 关卡掉落信息
/* Open Recruit Msg */
RecruitTagsDetected = 3000, // 公招识别到了Tags
RecruitSpecialTag, // 公招识别到了特殊的Tag
RecruitResult, // 公开招募结果
RecruitSelected, // 选择了Tags
RecruitError, // 公招错误
/* Infrast Msg */
InfrastSkillsDetected = 4000, // 识别到了基建技能(当前页面)
InfrastSkillsResult, // 识别到的所有可用技能
InfrastComb, // 当前房间的最优干员组合
EnterFacility, // 进入某个房间
FacilityInfo, // 当前设施信息
/* Global Info */
InternalError = 0, // 内部错误
InitFailed, // 初始化失败
ConnectionError, // 连接相关错误
AllTasksCompleted, // 全部任务完成
/* TaskChain Info */
TaskChainError = 10000, // 任务链执行/识别错误
TaskChainStart, // 任务链开始
TaskChainCompleted, // 任务链完成
TaskChainExtraInfo, // 任务链额外信息
/* SubTask Info */
SubTaskError = 20000, // 原子任务执行/识别错误
SubTaskStart, // 原子任务开始
SubTaskCompleted, // 原子任务完成
SubTaskExtraInfo // 原子任务额外信息
};
public enum InfrastWorkMode

View File

@@ -4,256 +4,30 @@ from enum import Enum, unique, auto
@unique
class Message(Enum):
"""
回调消息类型
回调消息
注释部分仅展示常用消息的回调JSON格式完全的回调JSON请参考C++侧实现代码
请参考 https://github.com/MistEO/MeoAssistantArknights/wiki/%E5%9B%9E%E8%B0%83%E6%B6%88%E6%81%AF
"""
InternalError = 0
PtrIsNull = 0
"""
指针为空
"""
InitFailed = auto()
ImageIsEmpty = auto()
"""
图像为空
"""
WindowMinimized = auto()
"""
[已弃用] 窗口被最小化了
"""
InitFaild = auto()
"""
初始化失败
"""
TaskError = auto()
"""
任务错误任务一直出错retry次数达到上限
"""
OcrResultError = auto()
"""
Ocr识别结果错误
"""
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()
"""
流程任务识别错误
"""
ConnectionError = auto()
AllTasksCompleted = auto()
"""
所有任务完成
:Json格式:
null
"""
TaskChainError = 10000
TaskChainStart = auto()
"""
开始任务链
:Json格式:
{ "task_chain": string }
:字段解释:
``task_chain`` 任务链名称
:常见值:
"Fight" 刷理智
"Award" 领取每日奖励
"Visit" 访问好友
"Mall" 信用商店
"Infrast" 基建
"Recruit" 自动公招
"RecruitCalc" 公招计算
"""
TaskChainCompleted = auto()
TextDetected = 2000
"""
识别到文字
"""
TaskChainExtraInfo = auto()
ImageFindResult = auto()
"""
查找图像的结果
"""
SubTaskError = 20000
ImageMatched = auto()
"""
图像匹配成功
"""
SubTaskStart = auto()
StageDrops = auto()
"""
关卡掉落信息
SubTaskCompleted = 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":["术师干员","减速"]}
"""
RecruitError = auto()
"""
公招识别错误。
"""
InfrastSkillsDetected = 4000
"""
识别到了基建技能(当前页面)
"""
InfrastSkillsResult = auto()
"""
识别到的所有可用技能
"""
InfrastComb = auto()
"""
当前房间的最优干员组合
"""
EnterFacility = auto()
"""
进入某个房间
:Json格式:
{ "facility": string, "index": int }
:字段解释:
``facility`` 房间名
``index`` 第几个该类房间
"""
#
FacilityInfo = auto()
"""
当前设施信息
"""
SubTaskExtraInfo = auto()

View File

@@ -1,2 +1 @@
MSBuild.exe ..\MeoAssistantArknights.sln /p:Configuration=Release /p:Platform=x64 /t:Rebuild
sh zip_release.sh
MSBuild.exe ..\MeoAssistantArknights.sln /p:Configuration=Release /p:Platform=x64 /t:Rebuild

View File

@@ -1,2 +0,0 @@
xcopy /e /y /i ..\resource ..\x64\RelWithDebInfo\resource
xcopy /e /y /i ..\3rdparty\resource ..\x64\RelWithDebInfo\resource

View File

@@ -1,3 +1,14 @@
mkdir -p ../build/Resource
cp -r ../resource/* ../build/Resource
cp -r ../3rdparty/resource/* ../build/Resource
#!/bin/sh
TargetDir=""
if [ $1 ]; then
TargetDir=$1
else
echo "Please enter TargetDir"
exit 1
fi
mkdir -p $TargetDir
cp -r "../resource/" "../3rdparty/resource/" $TargetDir
exit 0

View File

@@ -0,0 +1 @@
sh ./update_resource.sh ..\x64\RelWithDebInfo

View File

@@ -0,0 +1 @@
sh ./update_resource.sh ..\x64\Release

View File

@@ -1,2 +0,0 @@
xcopy /e /y /i ..\resource ..\x64\Release\resource
xcopy /e /y /i ..\3rdparty\resource ..\x64\Release\resource

1
tools/zip_release.bat Normal file
View File

@@ -0,0 +1 @@
sh ./zip_release.sh

View File

@@ -1,3 +1,5 @@
#!/bin/sh
TargetDir="../x64/Release"
LatestTag=$(git describe --tags $(git rev-list --tags --max-count=1))
Package="../x64/MeoAssistantArknights_"$LatestTag".zip"