Merge pull request #2116 from MaaAssistantArknights/feat/at

feat: 增加模板任务逻辑
This commit is contained in:
MistEO
2022-10-09 00:05:48 +08:00
committed by GitHub
6 changed files with 524 additions and 998 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -9,12 +9,7 @@ asst::StartUpTask::StartUpTask(AsstCallback callback, void* callback_arg)
m_start_game_task_ptr(std::make_shared<StartGameTaskPlugin>(m_callback, m_callback_arg, TaskType)),
m_start_up_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType))
{
m_start_up_task_ptr->set_tasks({ "StartUp" })
.set_times_limit("ReturnToTerminal", 0)
.set_times_limit("Terminal", 0)
.set_times_limit("EndOfAction", 0)
.set_task_delay(1000)
.set_retry_times(30);
m_start_up_task_ptr->set_tasks({ "StartUp" }).set_task_delay(1000).set_retry_times(30);
m_subtasks.emplace_back(m_start_game_task_ptr);
m_subtasks.emplace_back(m_start_up_task_ptr);
}

View File

@@ -135,12 +135,7 @@ bool ProcessTask::_run()
int& exec_times = m_exec_times[cur_name];
int max_times = m_cur_task_ptr->max_times;
TimesLimitType limit_type = TimesLimitType::Pre;
if (auto iter = m_times_limit.find(cur_name); iter != m_times_limit.cend()) {
max_times = iter->second.times;
limit_type = iter->second.type;
}
auto [max_times, limit_type] = calc_time_limit();
if (limit_type == TimesLimitType::Pre && exec_times >= max_times) {
info["what"] = "ExceededLimit";
@@ -287,6 +282,21 @@ bool asst::ProcessTask::on_run_fails()
return run();
}
std::pair<int, asst::ProcessTask::TimesLimitType> asst::ProcessTask::calc_time_limit() const
{
// eg. "C@B@A" 的 max_times 取 "C@B@A", "B@A", "A" 中有 max_times 定义的最靠前者
for (std::string cur_base_name = m_cur_task_ptr->name;;) {
if (auto iter = m_times_limit.find(cur_base_name); iter != m_times_limit.cend()) {
return { iter->second.times, iter->second.type };
}
size_t at_pos = cur_base_name.find('@');
if (at_pos == std::string::npos) {
return { m_cur_task_ptr->max_times, TimesLimitType::Pre };
}
cur_base_name = cur_base_name.substr(at_pos + 1);
}
}
json::value asst::ProcessTask::basic_info() const
{
return AbstractTask::basic_info() |

View File

@@ -6,7 +6,7 @@
namespace asst
{
// 流程任务,按照配置文件里的设置的流程运行
class ProcessTask : public AbstractTask
class ProcessTask final : public AbstractTask
{
public:
enum class TimesLimitType
@@ -40,6 +40,7 @@ namespace asst
virtual bool on_run_fails() override;
virtual json::value basic_info() const override;
std::pair<int, TimesLimitType> calc_time_limit() const;
void exec_click_task(const Rect& matched_rect);
void exec_swipe_task(ProcessTaskAction action);
void exec_slowly_swipe_task(ProcessTaskAction action);

View File

@@ -170,7 +170,7 @@ bool asst::TaskData::parse(const json::value& json)
#ifdef ASST_DEBUG
for (const auto& [name, task] : m_all_tasks_info) {
for (const auto& next : task->next) {
if (m_all_tasks_info.find(next) == m_all_tasks_info.cend()) {
if (get(next) == nullptr) {
Log.error(name, "'s next", next, "is null");
return false;
}

View File

@@ -7,6 +7,9 @@
#include <unordered_set>
#include "Utils/AsstTypes.h"
#ifdef ASST_DEBUG
#include "Utils/Logger.hpp"
#endif
namespace asst
{
@@ -14,33 +17,112 @@ namespace asst
class TaskData final : public SingletonHolder<TaskData>, public AbstractConfigerWithTempl
{
private:
static std::shared_ptr<TaskInfo> generate_task_info(const std::shared_ptr<TaskInfo>& base_ptr,
const std::string& task_prefix)
{
std::shared_ptr<TaskInfo> task_info_ptr;
switch (base_ptr->algorithm) {
case AlgorithmType::MatchTemplate:
task_info_ptr = std::make_shared<MatchTaskInfo>(*std::dynamic_pointer_cast<MatchTaskInfo>(base_ptr));
break;
case AlgorithmType::OcrDetect:
task_info_ptr = std::make_shared<OcrTaskInfo>(*std::dynamic_pointer_cast<OcrTaskInfo>(base_ptr));
break;
case AlgorithmType::Hash:
task_info_ptr = std::make_shared<HashTaskInfo>(*std::dynamic_pointer_cast<HashTaskInfo>(base_ptr));
break;
default:
task_info_ptr = std::make_shared<TaskInfo>(*base_ptr);
break;
}
using tasklist_t = std::vector<std::string>;
auto generate_tasks = [&](tasklist_t& task_list, const tasklist_t& base_task_list) {
task_list = {};
for (const std::string& base : base_task_list) {
std::string_view base_view = base;
size_t l = 0;
bool has_same_prefix = false;
// base 任务里已经存在相同前缀,则不加前缀
// https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/2116#issuecomment-1270115238
for (size_t r = base_view.find('@'); r != std::string_view::npos; r = base_view.find('@', l)) {
if (task_prefix == base_view.substr(l, r - l)) {
has_same_prefix = true;
break;
}
l = r + 1;
}
if (has_same_prefix) {
task_list.emplace_back(base);
}
else {
task_list.emplace_back(task_prefix + "@" + base);
}
}
};
generate_tasks(task_info_ptr->next, base_ptr->next);
generate_tasks(task_info_ptr->exceeded_next, base_ptr->exceeded_next);
generate_tasks(task_info_ptr->on_error_next, base_ptr->on_error_next);
generate_tasks(task_info_ptr->reduce_other_times, base_ptr->reduce_other_times);
return task_info_ptr;
}
public:
virtual ~TaskData() override = default;
virtual const std::unordered_set<std::string>& get_templ_required() const noexcept override;
template <typename TargetTaskInfoType>
requires std::derived_from<TargetTaskInfoType, TaskInfo> &&
(!std::same_as<TargetTaskInfoType, TaskInfo>) // Parameter must be a TaskInfo and not same as TaskInfo
std::shared_ptr<TargetTaskInfoType> get(const std::string& name)
{
auto it = m_all_tasks_info.find(name);
if (it == m_all_tasks_info.cend()) {
return nullptr;
}
return std::dynamic_pointer_cast<TargetTaskInfoType>(it->second);
}
template <typename TargetTaskInfoType = TaskInfo>
requires std::same_as<TargetTaskInfoType, TaskInfo> // Parameter must be a TaskInfo
requires(std::derived_from<TargetTaskInfoType, TaskInfo> ||
std::same_as<TargetTaskInfoType, TaskInfo>) // Parameter must be a TaskInfo
std::shared_ptr<TargetTaskInfoType> get(const std::string& name)
{
auto it = m_all_tasks_info.find(name);
if (it == m_all_tasks_info.cend()) {
// 普通 task 或已经生成过的 `@` 型 task
if (auto it = m_all_tasks_info.find(name); it != m_all_tasks_info.cend()) [[likely]] {
if constexpr (std::same_as<TargetTaskInfoType, TaskInfo>) {
return it->second;
}
else {
return std::dynamic_pointer_cast<TargetTaskInfoType>(it->second);
}
}
size_t at_pos = name.find('@');
if (at_pos == std::string::npos) [[unlikely]] {
return nullptr;
}
return it->second;
// `@` 前面的字符长度
size_t name_len = at_pos;
auto base_task_iter = get(name.substr(name_len + 1));
if (base_task_iter == nullptr) [[unlikely]] {
return nullptr;
}
std::string derived_task_name = name.substr(0, name_len);
auto task_info_ptr = generate_task_info(base_task_iter, derived_task_name);
if (task_info_ptr == nullptr) [[unlikely]] {
return nullptr;
}
// tasks 个数超过上限时不再 emplace返回临时值
constexpr size_t MAX_TASKS_SIZE = 65535;
if (m_all_tasks_info.size() < MAX_TASKS_SIZE) {
m_all_tasks_info.emplace(name, task_info_ptr);
}
#ifdef ASST_DEBUG
else {
Log.debug("Task count has exceeded the upper limit:", MAX_TASKS_SIZE, "current task:", name);
}
#endif // ASST_DEBUG
if constexpr (std::same_as<TargetTaskInfoType, TaskInfo>) {
return task_info_ptr;
}
else {
return std::dynamic_pointer_cast<TargetTaskInfoType>(task_info_ptr);
}
}
protected: