diff --git a/src/MaaCore/Common/AsstTypes.h b/src/MaaCore/Common/AsstTypes.h index 17465ade2c..d7b708e378 100644 --- a/src/MaaCore/Common/AsstTypes.h +++ b/src/MaaCore/Common/AsstTypes.h @@ -335,53 +335,106 @@ namespace asst } return "Invalid"; } + + enum class TaskDerivedType + { + Invalid = -1, + Raw, // 原始任务 + BaseTask, // BaseTask + Implicit, // 隐式 TemplateTask + Template, // 显式 TemplateTask + }; + + inline std::string enum_to_string(TaskDerivedType task_derived_type) + { + static const std::unordered_map task_derived_type_map = { + { TaskDerivedType::Raw, "Raw" }, + { TaskDerivedType::BaseTask, "BaseTask" }, + { TaskDerivedType::Implicit, "Implicit" }, + { TaskDerivedType::Template, "Template" }, + }; + if (auto it = task_derived_type_map.find(task_derived_type); it != task_derived_type_map.end()) { + return it->second; + } + return "Invalid"; + } } // namespace asst namespace asst { - // 任务信息 - struct TaskInfo + using TaskList = std::vector; + + // 任务流程信息 + struct TaskPipelineInfo { - TaskInfo() = default; - virtual ~TaskInfo() = default; - TaskInfo(const TaskInfo&) = default; - TaskInfo(TaskInfo&&) noexcept = default; - TaskInfo& operator=(const TaskInfo&) = default; - TaskInfo& operator=(TaskInfo&&) noexcept = default; - std::string name; // 任务名 - AlgorithmType algorithm = // 图像算法类型 - AlgorithmType::Invalid; - ProcessTaskAction action = // 要进行的操作 - ProcessTaskAction::Invalid; - std::vector sub; // 子任务(列表) - bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务 - std::vector next; // 下一个可能的任务(列表) - int max_times = INT_MAX; // 任务最多执行多少次 - std::vector exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表) - std::vector on_error_next; // 任务出错之后要去执行什么 - std::vector reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。 - // 例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效, - // 所以蓝色开始行动要-1 - Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域 - int pre_delay = 0; // 执行该任务前的延时 - int post_delay = 0; // 执行该任务后的延时 - int retry_times = INT_MAX; // 未找到图像时的重试次数 - Rect roi; // 要识别的区域,若为0则全图识别 + constexpr TaskPipelineInfo() = default; + constexpr virtual ~TaskPipelineInfo() = default; + constexpr TaskPipelineInfo(const TaskPipelineInfo&) = default; + constexpr TaskPipelineInfo(TaskPipelineInfo&&) noexcept = default; + constexpr TaskPipelineInfo& operator=(const TaskPipelineInfo&) = default; + constexpr TaskPipelineInfo& operator=(TaskPipelineInfo&&) noexcept = default; + std::string name; // 任务名 + TaskList next; // 下一个可能的任务(列表) + TaskList sub; // 子任务(列表) + TaskList on_error_next; // 任务出错之后要去执行什么 + TaskList exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表) + TaskList reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药, + // 则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1 + }; + using TaskPipelinePtr = std::shared_ptr; + using TaskPipelineConstPtr = std::shared_ptr; + + // 任务继承信息 + struct TaskDerivedInfo : public TaskPipelineInfo + { + constexpr TaskDerivedInfo() = default; + constexpr virtual ~TaskDerivedInfo() = default; + constexpr TaskDerivedInfo(const TaskDerivedInfo&) = default; + constexpr TaskDerivedInfo(TaskDerivedInfo&&) noexcept = default; + constexpr TaskDerivedInfo& operator=(const TaskDerivedInfo&) = default; + constexpr TaskDerivedInfo& operator=(TaskDerivedInfo&&) noexcept = default; + TaskDerivedType type = TaskDerivedType::Raw; // 任务类型 + std::string base = ""; // 继承自哪个任务(Raw 任务不需要) + std::string prefix = ""; // 需要添加的前缀(仅对 TemplateTask 生效) + }; + using TaskDerivedPtr = std::shared_ptr; + using TaskDerivedConstPtr = std::shared_ptr; + + // 任务信息 + struct TaskInfo : public TaskPipelineInfo + { + constexpr TaskInfo() = default; + constexpr virtual ~TaskInfo() = default; + constexpr TaskInfo(const TaskInfo&) = default; + constexpr TaskInfo(TaskInfo&&) noexcept = default; + constexpr TaskInfo& operator=(const TaskInfo&) = default; + constexpr TaskInfo& operator=(TaskInfo&&) noexcept = default; + AlgorithmType algorithm = AlgorithmType::Invalid; // 图像算法类型 + ProcessTaskAction action = ProcessTaskAction::Invalid; // 要进行的操作 + bool sub_error_ignored = false; // 子任务如果失败了,是否继续执行剩下的任务 + int max_times = INT_MAX; // 任务最多执行多少次 + Rect specific_rect; // 指定区域,目前仅针对ClickRect任务有用,会点这个区域 + int pre_delay = 0; // 执行该任务前的延时 + int post_delay = 0; // 执行该任务后的延时 + int retry_times = INT_MAX; // 未找到图像时的重试次数 + Rect roi; // 要识别的区域,若为0则全图识别 Rect rect_move; // 识别结果移动:有些结果识别到的,和要点击的不是同一个位置。 // 即识别到了res,点击res + result_move的位置 bool cache = false; // 是否使用缓存区域 std::vector special_params; // 某些任务会用到的特殊参数 }; + using TaskPtr = std::shared_ptr; + using TaskConstPtr = std::shared_ptr; // 文字识别任务的信息 struct OcrTaskInfo : public TaskInfo { - OcrTaskInfo() = default; - virtual ~OcrTaskInfo() override = default; - OcrTaskInfo(const OcrTaskInfo&) = default; - OcrTaskInfo(OcrTaskInfo&&) noexcept = default; - OcrTaskInfo& operator=(const OcrTaskInfo&) = default; - OcrTaskInfo& operator=(OcrTaskInfo&&) noexcept = default; + constexpr OcrTaskInfo() = default; + constexpr virtual ~OcrTaskInfo() override = default; + constexpr OcrTaskInfo(const OcrTaskInfo&) = default; + constexpr OcrTaskInfo(OcrTaskInfo&&) noexcept = default; + constexpr OcrTaskInfo& operator=(const OcrTaskInfo&) = default; + constexpr OcrTaskInfo& operator=(OcrTaskInfo&&) noexcept = default; std::vector text; // 文字的容器,匹配到这里面任一个,就算匹配上了 bool full_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了 bool is_ascii = false; // 是否启用字符数字模型 @@ -390,35 +443,41 @@ namespace asst std::vector> replace_map; // 部分文字容易识别错,字符串强制replace之后,再进行匹配 }; + using OcrTaskPtr = std::shared_ptr; + using OcrTaskConstPtr = std::shared_ptr; // 图片匹配任务的信息 struct MatchTaskInfo : public TaskInfo { - MatchTaskInfo() = default; - virtual ~MatchTaskInfo() override = default; - MatchTaskInfo(const MatchTaskInfo&) = default; - MatchTaskInfo(MatchTaskInfo&&) noexcept = default; - MatchTaskInfo& operator=(const MatchTaskInfo&) = default; - MatchTaskInfo& operator=(MatchTaskInfo&&) noexcept = default; + constexpr MatchTaskInfo() = default; + constexpr virtual ~MatchTaskInfo() override = default; + constexpr MatchTaskInfo(const MatchTaskInfo&) = default; + constexpr MatchTaskInfo(MatchTaskInfo&&) noexcept = default; + constexpr MatchTaskInfo& operator=(const MatchTaskInfo&) = default; + constexpr MatchTaskInfo& operator=(MatchTaskInfo&&) noexcept = default; std::vector templ_names; // 匹配模板图片文件名 std::vector templ_thresholds; // 模板匹配阈值 std::pair mask_range; // 掩码的二值化范围 }; + using MatchTaskPtr = std::shared_ptr; + using MatchTaskConstPtr = std::shared_ptr; // hash 计算任务的信息 struct HashTaskInfo : public TaskInfo { - HashTaskInfo() = default; - virtual ~HashTaskInfo() override = default; - HashTaskInfo(const HashTaskInfo&) = default; - HashTaskInfo(HashTaskInfo&&) noexcept = default; - HashTaskInfo& operator=(const HashTaskInfo&) = default; - HashTaskInfo& operator=(HashTaskInfo&&) noexcept = default; + constexpr HashTaskInfo() = default; + constexpr virtual ~HashTaskInfo() override = default; + constexpr HashTaskInfo(const HashTaskInfo&) = default; + constexpr HashTaskInfo(HashTaskInfo&&) noexcept = default; + constexpr HashTaskInfo& operator=(const HashTaskInfo&) = default; + constexpr HashTaskInfo& operator=(HashTaskInfo&&) noexcept = default; std::vector hashes; // 需要多个哈希值 int dist_threshold = 0; // 汉明距离阈值 std::pair mask_range; // 掩码的二值化范围 bool bound = false; // 是否裁剪周围黑边 }; + using HashTaskPtr = std::shared_ptr; + using HashTaskConstPtr = std::shared_ptr; inline static const std::string UploadDataSource = "MeoAssistant"; } // namespace asst diff --git a/src/MaaCore/Config/TaskData.cpp b/src/MaaCore/Config/TaskData.cpp index 7e2ec2abb3..304bb14eba 100644 --- a/src/MaaCore/Config/TaskData.cpp +++ b/src/MaaCore/Config/TaskData.cpp @@ -10,7 +10,7 @@ #include "Common/AsstTypes.h" #include "GeneralConfig.h" #include "TaskData/TaskDataSymbolStream.h" -#include "TaskData/TaskDataTypes.hpp" +#include "TaskData/TaskDataTypes.h" #include "TemplResource.h" #include "Utils/JsonMisc.hpp" #include "Utils/Logger.hpp" @@ -21,9 +21,9 @@ const std::unordered_set& asst::TaskData::get_templ_required() cons { return m_templ_required; } -asst::TaskData::taskptr_t asst::TaskData::get_raw(std::string_view name) +asst::TaskDerivedConstPtr asst::TaskData::get_raw(std::string_view name) { - if (!generate_task_and_its_base(name, true)) [[unlikely]] { + if (!generate_raw_task_and_base(name, true)) [[unlikely]] { return nullptr; } @@ -37,35 +37,27 @@ asst::TaskData::taskptr_t asst::TaskData::get_raw(std::string_view name) return nullptr; } - // 隐式 TemplateTask - if (auto base_task_iter = get_raw(name.substr(name_len + 1))) { - return _generate_task_info(base_task_iter, name.substr(0, name_len)); - } - return nullptr; } -asst::TaskData::taskptr_t asst::TaskData::get(std::string_view name) +asst::TaskPtr asst::TaskData::get(std::string_view name) { // 普通任务 或 已经生成过的高级任务 - if (auto it = m_all_tasks_info.find(name); it != m_all_tasks_info.cend()) [[likely]] { + if (auto it = m_all_tasks_info.find(name); it != m_all_tasks_info.cend()) { return it->second; } - auto raw_task = get_raw(name); - auto task = _generate_task_info(raw_task); + auto task = generate_task_info(name); if (!task) [[unlikely]] { return nullptr; } - bool changed = false; // 任务列表是否发生变化(是否包含虚任务) -#define ASST_TASKDATA_GET_IF_BRANCH(list, m) \ - if (auto opt = compile_tasklist(raw_task->list, name, m); !opt) [[unlikely]] { \ - Log.error("Generate task_list", std::string(name) + "->" #list, "failed.", opt.what()); \ - return nullptr; \ - } \ - else { \ - changed |= opt.value().task_changed; \ - task->list = std::move(opt.value().tasks); \ +#define ASST_TASKDATA_GET_IF_BRANCH(list, m) \ + if (auto opt = compile_tasklist(task->list, name, m); !opt) [[unlikely]] { \ + Log.error("Generate task_list", std::string(name) + "->" #list, "failed.", opt.error()); \ + return nullptr; \ + } \ + else { \ + task->list = std::move(opt.value().tasks); \ } // 展开五个任务列表中的虚任务 ASST_TASKDATA_GET_IF_BRANCH(next, false); @@ -78,12 +70,12 @@ asst::TaskData::taskptr_t asst::TaskData::get(std::string_view name) constexpr size_t MAX_TASKS_SIZE = 65535; if (m_all_tasks_info.size() < MAX_TASKS_SIZE) [[likely]] { // 保存最终生成的任务,下次查询时可以直接返回 - return insert_or_assign_task(name, changed ? task : raw_task).first->second; + return insert_or_assign_task(name, task).first->second; } else { // 个数超过上限时不保存,直接返回,防止内存占用过大 Log.warn("Task count has exceeded the upper limit:", MAX_TASKS_SIZE, "current task:", name); - return changed ? task : raw_task; + return task; } } @@ -149,7 +141,7 @@ bool asst::TaskData::lazy_parse(const json::value& json) validity = false; continue; } - auto check_tasklist = [&](const tasklist_t& task_list, std::string_view list_type, + auto check_tasklist = [&](const TaskList& task_list, std::string_view list_type, bool enable_justreturn_check = false) { std::unordered_set tasks_set {}; std::string justreturn_task_name = ""; @@ -165,7 +157,7 @@ bool asst::TaskData::lazy_parse(const json::value& json) validity = false; } - if (auto ptr = get_raw(task_name); ptr == nullptr) [[unlikely]] { + if (auto ptr = get(task_name); ptr == nullptr) [[unlikely]] { Log.error(task_name, "in", (std::string(name) += "->") += list_type, "is null"); validity = false; continue; @@ -217,7 +209,7 @@ bool asst::TaskData::parse(const json::value& json) // 本来重构之后完全支持惰性加载,但是发现模板图片不支持( for (std::string_view name : m_json_all_tasks_info | views::keys) { - generate_task_and_its_base(name, true); + generate_raw_task_and_base(name, true); } return true; @@ -240,19 +232,37 @@ void asst::TaskData::set_task_base(const std::string_view task_name, std::string clear_tasks(); } -bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must_true) +bool asst::TaskData::generate_raw_task_info(std::string_view name, std::string_view prefix, std::string_view base, + const json::value& json, TaskDerivedType type) +{ + TaskPipelineConstPtr base_task = base.empty() ? nullptr : get_raw(base); + if (base_task == nullptr) { + base_task = default_task_info_ptr; + prefix = ""; + } + + TaskDerivedPtr task = std::make_shared(); + task->name = name; + task->type = type; + task->base = base; + task->prefix = prefix; + utils::get_value_or(name, json, "next", task->next, [&]() { return append_prefix(base_task->next, prefix); }); + utils::get_value_or(name, json, "sub", task->sub, [&]() { return append_prefix(base_task->sub, prefix); }); + utils::get_value_or(name, json, "exceededNext", task->exceeded_next, + [&]() { return append_prefix(base_task->exceeded_next, prefix); }); + utils::get_value_or(name, json, "onErrorNext", task->on_error_next, + [&]() { return append_prefix(base_task->on_error_next, prefix); }); + utils::get_value_or(name, json, "reduceOtherTimes", task->reduce_other_times, + [&]() { return append_prefix(base_task->reduce_other_times, prefix); }); + m_task_status[task_name_view(name)] = NotToBeGenerate; + + // 保存虚任务未展开的任务 + insert_or_assign_raw_task(name, task); + return true; +} + +bool asst::TaskData::generate_raw_task_and_base(std::string_view name, bool must_true) { - auto generate_task = [&](std::string_view name, std::string_view prefix, taskptr_t base_ptr, - const json::value& task_json) { - auto task_info_ptr = generate_task_info(name, task_json, base_ptr, prefix); - if (task_info_ptr == nullptr) { - return false; - } - m_task_status[task_name_view(name)] = NotToBeGenerate; - // 保存虚任务未展开的任务 - insert_or_assign_raw_task(name, task_info_ptr); - return true; - }; switch (m_task_status[task_name_view(name)]) { case NotToBeGenerate: // 已经显式生成 @@ -262,7 +272,12 @@ bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must // 隐式生成的资源 if (size_t p = name.find('@'); p != std::string::npos) { - return generate_task_and_its_base(name.substr(p + 1), must_true); + if (generate_raw_task_and_base(name.substr(p + 1), must_true)) { + // 隐式 TemplateTask + generate_raw_task_info(name, name.substr(0, p), name.substr(p + 1), {}, TaskDerivedType::Implicit); + return true; + } + return false; } m_task_status[name] = NotExists; @@ -288,22 +303,17 @@ bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must // BaseTask if (auto opt = task_json.find("baseTask")) { std::string base = opt.value(); - return generate_task_and_its_base(base, must_true) && generate_task(name, "", get_raw(base), task_json); + return generate_raw_task_and_base(base, must_true) && + generate_raw_task_info(name, "", base, task_json, TaskDerivedType::BaseTask); } // TemplateTask if (size_t p = name.find('@'); p != std::string::npos) { - if (std::string_view base = name.substr(p + 1); generate_task_and_its_base(base, false)) { -#ifdef ASST_DEBUG - if (task_json.as_object().empty() && get_raw(base)->algorithm != AlgorithmType::MatchTemplate) { - // 多余的空任务 - Log.warn("Task", name, "is a redundant empty task because it is not MatchTemplate"); - } -#endif - return generate_task(name, name.substr(0, p), get_raw(base), task_json); + if (std::string_view base = name.substr(p + 1); generate_raw_task_and_base(base, false)) { + return generate_raw_task_info(name, name.substr(0, p), base, task_json, TaskDerivedType::Template); } } - return generate_task(name, "", nullptr, task_json); + return generate_raw_task_info(name, "", "", task_json, TaskDerivedType::Raw); } [[unlikely]] case Generating: Log.error("Task", name, "is generated cyclically"); @@ -314,59 +324,123 @@ bool asst::TaskData::generate_task_and_its_base(std::string_view name, bool must } } -asst::TaskData::taskptr_t asst::TaskData::generate_task_info(std::string_view name, const json::value& task_json, - taskptr_t default_ptr, std::string_view task_prefix) +asst::TaskPtr asst::TaskData::generate_task_info(std::string_view name) { - if (default_ptr == nullptr) { - default_ptr = default_task_info_ptr; - task_prefix = ""; + auto raw = get_raw(name); + if (!raw) [[unlikely]] { + Log.error("Task", name, "not found"); + return nullptr; + } + + auto json_it = m_json_all_tasks_info.find(name); + const json::value& json = json_it == m_json_all_tasks_info.cend() ? json::value {} : json_it->second; + if (raw->type == TaskDerivedType::Raw && json_it == m_json_all_tasks_info.cend()) [[unlikely]] { + Log.error("Task", name, "of type Raw has no json"); + return nullptr; + } + if (raw->type == TaskDerivedType::Raw && !raw->base.empty()) [[unlikely]] { + Log.error("Task", name, "of type Raw has base", raw->base); + return nullptr; + } + if (raw->type != TaskDerivedType::Raw && raw->base.empty()) [[unlikely]] { + Log.error("Task", name, "of type", enum_to_string(raw->type), "has no base"); + return nullptr; + } + if ((raw->type == TaskDerivedType::Implicit || raw->type == TaskDerivedType::Template) && raw->prefix.empty()) + [[unlikely]] { + Log.error("Task", name, "of type", enum_to_string(raw->type), "has no prefix"); + return nullptr; + } + if ((raw->type == TaskDerivedType::Raw || raw->type == TaskDerivedType::BaseTask) && !raw->prefix.empty()) + [[unlikely]] { + Log.error("Task", name, "of type", enum_to_string(raw->type), "has prefix", raw->prefix); + return nullptr; + } + + TaskConstPtr base = default_task_info_ptr; + if (!raw->base.empty()) { + base = get(raw->base); + if (!base) [[unlikely]] { + Log.error("Base task", raw->base, "of task", name, "not found"); + return nullptr; + } } // 获取 algorithm 并按照 algorithm 生成 TaskInfo AlgorithmType algorithm; - utils::get_value_or(name, task_json, "algorithm", algorithm, default_ptr->algorithm); - - taskptr_t task_ptr = nullptr; + utils::get_value_or(name, json, "algorithm", algorithm, base->algorithm); + TaskPtr task = nullptr; switch (algorithm) { case AlgorithmType::MatchTemplate: - task_ptr = generate_match_task_info(name, task_json, std::dynamic_pointer_cast(default_ptr)); + task = generate_match_task_info(name, json, std::dynamic_pointer_cast(base), raw->type); break; case AlgorithmType::OcrDetect: - task_ptr = generate_ocr_task_info(name, task_json, std::dynamic_pointer_cast(default_ptr)); + task = generate_ocr_task_info(name, json, std::dynamic_pointer_cast(base)); break; case AlgorithmType::Hash: - task_ptr = generate_hash_task_info(name, task_json, std::dynamic_pointer_cast(default_ptr)); + task = generate_hash_task_info(name, json, std::dynamic_pointer_cast(base)); break; case AlgorithmType::JustReturn: - task_ptr = std::make_shared(); + task = std::make_shared(); break; default: Log.error("Unknown algorithm in task", name); return nullptr; } - if (task_ptr == nullptr) { + if (task == nullptr) { return nullptr; } - // 不管什么algorithm,都有基础成员(next, roi, 等等) - if (!append_base_task_info(task_ptr, name, task_json, default_ptr, task_prefix)) { - return nullptr; + const auto& prefix = raw->prefix; + +#define ASST_TASKDATA_GET_VALUE_OR(key, value) utils::get_value_or(name, json, key, task->value, base->value) +#define ASST_TASKDATA_GET_VALUE_OR_LAZY(key, value) \ + utils::get_value_or(name, json, key, task->value, [&]() { return append_prefix(base->value, prefix); }) + + ASST_TASKDATA_GET_VALUE_OR("action", action); + ASST_TASKDATA_GET_VALUE_OR("cache", cache); + ASST_TASKDATA_GET_VALUE_OR("maxTimes", max_times); + ASST_TASKDATA_GET_VALUE_OR("preDelay", pre_delay); + ASST_TASKDATA_GET_VALUE_OR("postDelay", post_delay); + ASST_TASKDATA_GET_VALUE_OR("roi", roi); + ASST_TASKDATA_GET_VALUE_OR("subErrorIgnored", sub_error_ignored); + ASST_TASKDATA_GET_VALUE_OR("rectMove", rect_move); + ASST_TASKDATA_GET_VALUE_OR("specificRect", specific_rect); + ASST_TASKDATA_GET_VALUE_OR("specialParams", special_params); + ASST_TASKDATA_GET_VALUE_OR_LAZY("next", next); + ASST_TASKDATA_GET_VALUE_OR_LAZY("sub", sub); + ASST_TASKDATA_GET_VALUE_OR_LAZY("exceededNext", exceeded_next); + ASST_TASKDATA_GET_VALUE_OR_LAZY("onErrorNext", on_error_next); + ASST_TASKDATA_GET_VALUE_OR_LAZY("reduceOtherTimes", reduce_other_times); + +#undef ASST_TASKDATA_GET_VALUE_OR +#undef ASST_TASKDATA_GET_VALUE_OR_LAZY + +#ifdef ASST_DEBUG + // Debug 模式下检查 roi 是否超出边界 + if (auto [x, y, w, h] = task->roi; x + w > WindowWidthDefault || y + h > WindowHeightDefault) { + Log.warn(name, "roi is out of bounds"); } - task_ptr->algorithm = algorithm; - task_ptr->name = name; - return task_ptr; +#endif + task->algorithm = algorithm; + task->name = name; + + return task; } -asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_view name, const json::value& task_json, - std::shared_ptr default_ptr) +asst::TaskPtr asst::TaskData::generate_match_task_info(std::string_view name, const json::value& task_json, + MatchTaskConstPtr default_ptr, TaskDerivedType derived_type) { if (default_ptr == nullptr) { default_ptr = default_match_task_info_ptr; } auto match_task_info_ptr = std::make_shared(); - if (!utils::get_value_or(name, task_json, "template", match_task_info_ptr->templ_names, - [&]() { return std::vector { std::string(name) + ".png" }; })) { + if (!utils::get_value_or(name, task_json, "template", match_task_info_ptr->templ_names, [&]() { + return derived_type == TaskDerivedType::Implicit // 隐式 Template Task 时继承,其它时默认值使用任务名 + ? default_ptr->templ_names + : std::vector { std::string(name) + ".png" }; + })) { return nullptr; } @@ -386,7 +460,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_v threshold_opt->as_double()); } else if (threshold_opt->is_array()) { - ranges::copy(threshold_opt->as_array() | views::transform(&ranges::range_value_t::as_double), + ranges::copy(threshold_opt->as_array() | views::transform(&json::value::as_double), std::back_inserter(match_task_info_ptr->templ_thresholds)); } else { @@ -408,8 +482,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_v return match_task_info_ptr; } -asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info(std::string_view name, const json::value& task_json, - std::shared_ptr default_ptr) +asst::TaskPtr asst::TaskData::generate_ocr_task_info(std::string_view name, const json::value& task_json, + OcrTaskConstPtr default_ptr) { if (default_ptr == nullptr) { default_ptr = default_ocr_task_info_ptr; @@ -432,8 +506,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info(std::string_vie return ocr_task_info_ptr; } -asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info(std::string_view name, const json::value& task_json, - std::shared_ptr default_ptr) +asst::TaskPtr asst::TaskData::generate_hash_task_info(std::string_view name, const json::value& task_json, + HashTaskConstPtr default_ptr) { if (default_ptr == nullptr) { default_ptr = default_hash_task_info_ptr; @@ -453,91 +527,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info(std::string_vi return hash_task_info_ptr; } -bool asst::TaskData::append_base_task_info(taskptr_t task_info_ptr, std::string_view name, const json::value& task_json, - taskptr_t default_ptr, std::string_view task_prefix) -{ - if (default_ptr == nullptr) { - default_ptr = default_task_info_ptr; - } - - utils::get_value_or(name, task_json, "action", task_info_ptr->action, default_ptr->action); - utils::get_value_or(name, task_json, "cache", task_info_ptr->cache, default_ptr->cache); - utils::get_value_or(name, task_json, "maxTimes", task_info_ptr->max_times, default_ptr->max_times); - utils::get_value_or(name, task_json, "exceededNext", task_info_ptr->exceeded_next, - [&]() { return append_prefix(default_ptr->exceeded_next, task_prefix); }); - utils::get_value_or(name, task_json, "onErrorNext", task_info_ptr->on_error_next, - [&]() { return append_prefix(default_ptr->on_error_next, task_prefix); }); - utils::get_value_or(name, task_json, "preDelay", task_info_ptr->pre_delay, default_ptr->pre_delay); - utils::get_value_or(name, task_json, "postDelay", task_info_ptr->post_delay, default_ptr->post_delay); - utils::get_value_or(name, task_json, "reduceOtherTimes", task_info_ptr->reduce_other_times, - [&]() { return append_prefix(default_ptr->reduce_other_times, task_prefix); }); - utils::get_value_or(name, task_json, "roi", task_info_ptr->roi, default_ptr->roi); - utils::get_value_or(name, task_json, "sub", task_info_ptr->sub, - [&]() { return append_prefix(default_ptr->sub, task_prefix); }); - utils::get_value_or(name, task_json, "subErrorIgnored", task_info_ptr->sub_error_ignored, - default_ptr->sub_error_ignored); - utils::get_value_or(name, task_json, "next", task_info_ptr->next, - [&]() { return append_prefix(default_ptr->next, task_prefix); }); - utils::get_value_or(name, task_json, "rectMove", task_info_ptr->rect_move, default_ptr->rect_move); - utils::get_value_or(name, task_json, "specificRect", task_info_ptr->specific_rect, default_ptr->specific_rect); - utils::get_value_or(name, task_json, "specialParams", task_info_ptr->special_params, default_ptr->special_params); -#ifdef ASST_DEBUG - // Debug 模式下检查 roi 是否超出边界 - if (auto [x, y, w, h] = task_info_ptr->roi; x + w > WindowWidthDefault || y + h > WindowHeightDefault) { - Log.warn(name, "roi is out of bounds"); - } -#endif - return true; -} - -std::shared_ptr asst::TaskData::_default_match_task_info() -{ - auto match_task_info_ptr = std::make_shared(); - match_task_info_ptr->templ_names = { "__INVALID__" }; - match_task_info_ptr->templ_thresholds = { TemplThresholdDefault }; - - return match_task_info_ptr; -} - -std::shared_ptr asst::TaskData::_default_ocr_task_info() -{ - auto ocr_task_info_ptr = std::make_shared(); - ocr_task_info_ptr->full_match = false; - ocr_task_info_ptr->is_ascii = false; - ocr_task_info_ptr->without_det = false; - ocr_task_info_ptr->replace_full = false; - - return ocr_task_info_ptr; -} - -std::shared_ptr asst::TaskData::_default_hash_task_info() -{ - auto hash_task_info_ptr = std::make_shared(); - hash_task_info_ptr->dist_threshold = 0; - hash_task_info_ptr->bound = true; - - return hash_task_info_ptr; -} - -asst::TaskData::taskptr_t asst::TaskData::_default_task_info() -{ - auto task_info_ptr = std::make_shared(); - task_info_ptr->algorithm = AlgorithmType::MatchTemplate; - task_info_ptr->action = ProcessTaskAction::DoNothing; - task_info_ptr->cache = true; - task_info_ptr->max_times = INT_MAX; - task_info_ptr->pre_delay = 0; - task_info_ptr->post_delay = 0; - task_info_ptr->roi = Rect(); - task_info_ptr->sub_error_ignored = false; - task_info_ptr->rect_move = Rect(); - task_info_ptr->specific_rect = Rect(); - - return task_info_ptr; -} - asst::ResultOrError asst::TaskData::compile_raw_tasklist( - const tasklist_t& raw_tasks, std::string_view self_name, std::function get_raw, + const TaskList& raw_tasks, std::string_view self_name, std::function get_raw, bool allow_duplicate) { RawCompileResult ret { .task_changed = false, .symbols = {} }; @@ -554,14 +545,14 @@ asst::ResultOrError asst::TaskData::compile_ra ret.task_changed = ret.task_changed || opt.value(); } else { - return { std::nullopt, std::move(opt.what()) }; + return { std::nullopt, std::move(opt.error()) }; } auto opt = symbol_stream.decode( [&](const TaskDataSymbol& symbol, const TaskDataSymbol& prefix) -> TaskDataSymbol::SymbolsOrError { return TaskDataSymbol::append_prefix( symbol, prefix, self_name, get_raw, - [&](const tasklist_t& raw_or_empty) -> TaskDataSymbol::SymbolsOrError { + [&](const TaskList& raw_or_empty) -> TaskDataSymbol::SymbolsOrError { if (auto opt = compile_raw_tasklist(raw_or_empty, self_name, get_raw, allow_duplicate)) { return opt.value().symbols; } @@ -572,7 +563,7 @@ asst::ResultOrError asst::TaskData::compile_ra // 记号流处理 if (!opt) { - return { std::nullopt, std::move(opt.what()) }; + return { std::nullopt, std::move(opt.error()) }; } for (const auto& task : *opt) { @@ -589,7 +580,7 @@ asst::ResultOrError asst::TaskData::compile_ra return ret; } -asst::ResultOrError asst::TaskData::compile_tasklist(const tasklist_t& raw_tasks, +asst::ResultOrError asst::TaskData::compile_tasklist(const TaskList& raw_tasks, std::string_view self_name, bool allow_duplicate) { @@ -598,7 +589,7 @@ asst::ResultOrError asst::TaskData::compile_taskl if (auto opt = compile_raw_tasklist( raw_tasks, self_name, [&](std::string_view name) { return get_raw(name); }, allow_duplicate); !opt) { - return { std::nullopt, std::move(opt.what()) }; + return { std::nullopt, std::move(opt.error()) }; } else { new_symbols = std::move(opt.value().symbols); @@ -634,6 +625,96 @@ asst::ResultOrError asst::TaskData::compile_taskl return ret; } +std::string asst::TaskData::append_prefix(std::string_view task_name, std::string_view task_prefix) +{ + if (task_prefix.ends_with('@')) [[unlikely]] { + task_prefix.remove_suffix(1); + } + if (task_prefix.empty()) [[unlikely]] { + return std::string(task_name); + } + if (task_name.empty()) { + return std::string(task_prefix); + } + if (task_name.starts_with('#')) { + return std::string(task_prefix) + std::string(task_name); + } + return std::string(task_prefix) + '@' + std::string(task_name); +} + +asst::TaskList asst::TaskData::append_prefix(const TaskList& base_task_list, std::string_view task_prefix) +{ + if (task_prefix.ends_with('@')) [[unlikely]] { + task_prefix.remove_suffix(1); + } + if (task_prefix.empty()) { + return base_task_list; + } + TaskList 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)) [[unlikely]] { + has_same_prefix = true; + break; + } + l = r + 1; + } + task_list.emplace_back(has_same_prefix ? base : append_prefix(base_view, task_prefix)); + } + return task_list; +} + +asst::MatchTaskConstPtr asst::TaskData::_default_match_task_info() +{ + auto match_task_info_ptr = std::make_shared(); + match_task_info_ptr->templ_names = { "__INVALID__" }; + match_task_info_ptr->templ_thresholds = { TemplThresholdDefault }; + + return match_task_info_ptr; +} + +asst::OcrTaskConstPtr asst::TaskData::_default_ocr_task_info() +{ + auto ocr_task_info_ptr = std::make_shared(); + ocr_task_info_ptr->full_match = false; + ocr_task_info_ptr->is_ascii = false; + ocr_task_info_ptr->without_det = false; + ocr_task_info_ptr->replace_full = false; + + return ocr_task_info_ptr; +} + +asst::HashTaskConstPtr asst::TaskData::_default_hash_task_info() +{ + auto hash_task_info_ptr = std::make_shared(); + hash_task_info_ptr->dist_threshold = 0; + hash_task_info_ptr->bound = true; + + return hash_task_info_ptr; +} + +asst::TaskConstPtr asst::TaskData::_default_task_info() +{ + auto task_info_ptr = std::make_shared(); + task_info_ptr->algorithm = AlgorithmType::MatchTemplate; + task_info_ptr->action = ProcessTaskAction::DoNothing; + task_info_ptr->cache = true; + task_info_ptr->max_times = INT_MAX; + task_info_ptr->pre_delay = 0; + task_info_ptr->post_delay = 0; + task_info_ptr->roi = Rect(); + task_info_ptr->sub_error_ignored = false; + task_info_ptr->rect_move = Rect(); + task_info_ptr->specific_rect = Rect(); + + return task_info_ptr; +} + #ifdef ASST_DEBUG // 为了解决类似 beddc7c828126c678391e0b4da288db6d2c2d58a 导致的问题,加载的时候做一个语法检查 // 主要是处理是否包含未知键值的问题 diff --git a/src/MaaCore/Config/TaskData.h b/src/MaaCore/Config/TaskData.h index 4b8a99a21d..682945e31f 100644 --- a/src/MaaCore/Config/TaskData.h +++ b/src/MaaCore/Config/TaskData.h @@ -2,8 +2,6 @@ #include "AbstractConfigWithTempl.h" -#include -#include #include #include @@ -12,166 +10,75 @@ namespace asst { - struct TaskInfo; - class TaskData final : public SingletonHolder, public AbstractConfigWithTempl { - public: - using tasklist_t = std::vector; - using tasklistptr_t = std::shared_ptr; - using taskptr_t = std::shared_ptr; - private: - static std::shared_ptr _default_match_task_info(); - static std::shared_ptr _default_ocr_task_info(); - static std::shared_ptr _default_hash_task_info(); - static taskptr_t _default_task_info(); + static MatchTaskConstPtr _default_match_task_info(); + static OcrTaskConstPtr _default_ocr_task_info(); + static HashTaskConstPtr _default_hash_task_info(); + static TaskConstPtr _default_task_info(); // 从模板任务生成 - static inline const std::shared_ptr default_match_task_info_ptr = _default_match_task_info(); - static inline const std::shared_ptr default_ocr_task_info_ptr = _default_ocr_task_info(); - static inline const std::shared_ptr default_hash_task_info_ptr = _default_hash_task_info(); - static inline const taskptr_t default_task_info_ptr = _default_task_info(); + static inline const MatchTaskConstPtr default_match_task_info_ptr = _default_match_task_info(); + static inline const OcrTaskConstPtr default_ocr_task_info_ptr = _default_ocr_task_info(); + static inline const HashTaskConstPtr default_hash_task_info_ptr = _default_hash_task_info(); + static inline const TaskConstPtr default_task_info_ptr = _default_task_info(); - // 这是下面几个函数的封装 - taskptr_t generate_task_info(std::string_view name, const json::value&, taskptr_t default_ptr, - std::string_view task_prefix = ""); + static std::string append_prefix(std::string_view task_name, std::string_view task_prefix); + static TaskList append_prefix(const TaskList& base_task_list, std::string_view task_prefix); - taskptr_t generate_match_task_info(std::string_view name, const json::value&, - std::shared_ptr default_ptr); - taskptr_t generate_ocr_task_info(std::string_view name, const json::value&, - std::shared_ptr default_ptr); - taskptr_t generate_hash_task_info(std::string_view name, const json::value&, - std::shared_ptr default_ptr); - // TaskInfo 的基础成员 - bool append_base_task_info(taskptr_t task_info_ptr, std::string_view name, const json::value& task_json, - taskptr_t default_ptr, std::string_view task_prefix = ""); - static std::string append_prefix(std::string_view task_name, std::string_view task_prefix) - { - if (task_prefix.ends_with('@')) [[unlikely]] { - task_prefix.remove_suffix(1); - } - if (task_prefix.empty()) [[unlikely]] { - return std::string(task_name); - } - if (task_name.empty()) { - return std::string(task_prefix); - } - if (task_name.starts_with('#')) { - return std::string(task_prefix) + std::string(task_name); - } - return std::string(task_prefix) + '@' + std::string(task_name); - } - static tasklist_t append_prefix(const tasklist_t& base_task_list, std::string_view task_prefix) - { - if (task_prefix.ends_with('@')) [[unlikely]] { - task_prefix.remove_suffix(1); - } - if (task_prefix.empty()) { - return base_task_list; - } - tasklist_t 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)) [[unlikely]] { - has_same_prefix = true; - break; - } - l = r + 1; - } - task_list.emplace_back(has_same_prefix ? base : append_prefix(base_view, task_prefix)); - } - return task_list; - }; - - // 运行时动态生成任务 - static taskptr_t _generate_task_info(const taskptr_t& base_ptr) - { - if (!base_ptr) [[unlikely]] { - return nullptr; - } - switch (base_ptr->algorithm) { - case AlgorithmType::MatchTemplate: - return std::make_shared(*std::dynamic_pointer_cast(base_ptr)); - case AlgorithmType::OcrDetect: - return std::make_shared(*std::dynamic_pointer_cast(base_ptr)); - case AlgorithmType::Hash: - return std::make_shared(*std::dynamic_pointer_cast(base_ptr)); - default: - return std::make_shared(*base_ptr); - } - } - static taskptr_t _generate_task_info(const taskptr_t& base_ptr, std::string_view task_prefix) - { - taskptr_t task_info_ptr = _generate_task_info(base_ptr); - if (!task_prefix.empty()) { - task_info_ptr->name = append_prefix(base_ptr->name, task_prefix); - task_info_ptr->sub = append_prefix(base_ptr->sub, task_prefix); - task_info_ptr->next = append_prefix(base_ptr->next, task_prefix); - task_info_ptr->exceeded_next = append_prefix(base_ptr->exceeded_next, task_prefix); - task_info_ptr->on_error_next = append_prefix(base_ptr->on_error_next, task_prefix); - task_info_ptr->reduce_other_times = append_prefix(base_ptr->reduce_other_times, task_prefix); - } - return task_info_ptr; - } template requires(!std::same_as, std::string> && requires { std::declval>().as_string(); }) - static tasklist_t to_string_list(const ListType& other_string_list) + static TaskList to_string_list(const ListType& other_string_list) { - tasklist_t task_list = {}; + TaskList task_list = {}; task_list.reserve(other_string_list.size()); ranges::copy(other_string_list | views::transform(&ranges::range_value_t::as_string), std::back_inserter(task_list)); return task_list; } - static std::string_view task_name_view(std::string_view task_name) - { - return *m_task_names.emplace(task_name).first; - } - decltype(auto) insert_or_assign_raw_task(std::string_view task_name, taskptr_t task_info_ptr) - { - return m_raw_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr); - } - decltype(auto) insert_or_assign_task(std::string_view task_name, taskptr_t task_info_ptr) - { - return m_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr); - } + static inline std::unordered_set m_task_names {}; + static const std::string& task_name_view(std::string_view name) { return *m_task_names.emplace(name).first; } struct RawCompileResult { bool task_changed; TaskDataSymbol::Symbols symbols; }; - static ResultOrError compile_raw_tasklist(const tasklist_t& raw_tasks, - std::string_view self_name, - std::function get_raw, - bool allow_duplicate); + static ResultOrError compile_raw_tasklist( + const TaskList& raw_tasks, std::string_view self_name, + std::function get_raw, bool allow_duplicate); + + private: + TaskPtr generate_task_info(std::string_view name); + TaskPtr generate_match_task_info(std::string_view name, const json::value&, MatchTaskConstPtr default_ptr, + TaskDerivedType derived_type); + TaskPtr generate_ocr_task_info(std::string_view name, const json::value&, OcrTaskConstPtr default_ptr); + TaskPtr generate_hash_task_info(std::string_view name, const json::value&, HashTaskConstPtr default_ptr); + decltype(auto) insert_or_assign_raw_task(std::string_view task_name, TaskDerivedPtr task_info_ptr) + { + return m_raw_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr); + } + decltype(auto) insert_or_assign_task(std::string_view task_name, TaskPtr task_info_ptr) + { + return m_all_tasks_info.insert_or_assign(task_name_view(task_name), task_info_ptr); + } struct CompileResult { bool task_changed; - tasklist_t tasks; + TaskList tasks; }; - ResultOrError compile_tasklist(const tasklist_t& raw_tasks, std::string_view self_name, + ResultOrError compile_tasklist(const TaskList& raw_tasks, std::string_view self_name, bool allow_duplicate); - bool generate_task_and_its_base(std::string_view name, bool must_true); + bool generate_raw_task_info(std::string_view name, std::string_view prefix, std::string_view base_name, + const json::value& task_json, TaskDerivedType type); + bool generate_raw_task_and_base(std::string_view name, bool must_true); #ifdef ASST_DEBUG bool syntax_check(std::string_view task_name, const json::value& task_json); #endif - taskptr_t get_raw(std::string_view name); - template - requires(std::derived_from && - !std::same_as) // Parameter must be a TaskInfo - std::shared_ptr get_raw(std::string_view name) - { - return std::dynamic_pointer_cast(get_raw(name)); - } + TaskDerivedConstPtr get_raw(std::string_view name); public: virtual ~TaskData() override = default; @@ -180,21 +87,15 @@ namespace asst void set_task_base(const std::string_view task_name, std::string base_task_name); bool lazy_parse(const json::value& json); - taskptr_t get(std::string_view name); + TaskPtr get(std::string_view name); template requires(std::derived_from && !std::same_as) // Parameter must be a TaskInfo std::shared_ptr get(std::string_view name) { + // TODO: should be const return std::dynamic_pointer_cast(get(name)); } - std::optional get_json(std::string_view name) const - { - if (m_json_all_tasks_info.find(name) != m_json_all_tasks_info.cend()) - return m_json_all_tasks_info.at(name); - else - return std::nullopt; - } protected: enum TaskStatus @@ -207,12 +108,11 @@ namespace asst virtual bool parse(const json::value& json) override; - static inline std::unordered_set m_task_names; std::unordered_set m_templ_required; std::unordered_map m_task_status; - std::unordered_map m_json_all_tasks_info; // 原始的 json 信息 - std::unordered_map m_raw_all_tasks_info; // 未展开虚任务的任务信息 - std::unordered_map m_all_tasks_info; // 已展开虚任务的任务信息 + std::unordered_map m_json_all_tasks_info; // 原始的 json 信息 + std::unordered_map m_raw_all_tasks_info; // 未展开虚任务的任务信息 + std::unordered_map m_all_tasks_info; // 已展开虚任务的任务信息 }; inline static auto& Task = TaskData::get_instance(); diff --git a/src/MaaCore/Config/TaskData/TaskDataSymbol.cpp b/src/MaaCore/Config/TaskData/TaskDataSymbol.cpp index b19cb90c03..0b3f2a1d82 100644 --- a/src/MaaCore/Config/TaskData/TaskDataSymbol.cpp +++ b/src/MaaCore/Config/TaskData/TaskDataSymbol.cpp @@ -2,11 +2,10 @@ asst::TaskDataSymbol::SymbolsOrError asst::TaskDataSymbol::append_prefix( const TaskDataSymbol& symbol, const TaskDataSymbol& prefix, std::string_view self_name, - std::function(std::string_view)> get_raw, - std::function&)> compile_tasklist) + std::function get_raw, + std::function compile_tasklist) { - // !!!注意: - // A@#self 是 A 而不是 A@self_name, #self@A 是 selfname@A 而不是 A + // 注意:A@#self 是 A 而不是 A@self_name, #self@A 是 self_name@A 而不是 A std::string_view prefix_name; if (prefix == SharpSelf) { prefix_name = self_name; diff --git a/src/MaaCore/Config/TaskData/TaskDataSymbol.h b/src/MaaCore/Config/TaskData/TaskDataSymbol.h index 7363d2b951..c4209a757e 100644 --- a/src/MaaCore/Config/TaskData/TaskDataSymbol.h +++ b/src/MaaCore/Config/TaskData/TaskDataSymbol.h @@ -5,9 +5,8 @@ #include #include -#include "TaskDataTypes.hpp" - #include "Common/AsstTypes.h" +#include "TaskDataTypes.h" #include "Utils/Logger.hpp" namespace asst @@ -122,10 +121,10 @@ namespace asst return pos == symbol_repr_to_type.end() ? Name : pos->second; } - static SymbolsOrError append_prefix( - const TaskDataSymbol& symbol, const TaskDataSymbol& prefix, std::string_view self_name, - std::function(std::string_view)> get_raw, - std::function&)> compile_tasklist); + static SymbolsOrError append_prefix(const TaskDataSymbol& symbol, const TaskDataSymbol& prefix, + std::string_view self_name, + std::function get_raw, + std::function compile_tasklist); bool is_name() const noexcept { return m_symbol == Name; } bool is_sharp_type() const noexcept { return is_sharp_type(m_symbol); } diff --git a/src/MaaCore/Config/TaskData/TaskDataSymbolStream.cpp b/src/MaaCore/Config/TaskData/TaskDataSymbolStream.cpp index ceccb50f48..6624b31bac 100644 --- a/src/MaaCore/Config/TaskData/TaskDataSymbolStream.cpp +++ b/src/MaaCore/Config/TaskData/TaskDataSymbolStream.cpp @@ -149,12 +149,11 @@ asst::TaskDataSymbolStream::SymbolsOrError asst::TaskDataSymbolStream::decode(Ap // self_name + #self ^ #self = #none // self_name + #self ^ self_name = #self if (ranges::any_of(y, [&](const auto& sy) { return sy == Symbol::SharpSelf; })) { - auto remove_ret = ranges::remove(x, self_name); - x.erase(remove_ret.begin(), remove_ret.end()); + std::erase(x, self_name); } - auto remove_ret = ranges::remove_if( - x, [&](const auto& sx) { return ranges::any_of(y, [&](const auto& sy) { return sx == sy; }); }); - x.erase(remove_ret.begin(), remove_ret.end()); + std::erase_if(x, [&](const auto& sx) { + return ranges::any_of(y, [&](const auto& sy) { return sx == sy; }); + }); } } return x; @@ -224,7 +223,7 @@ asst::TaskDataSymbolStream::SymbolsOrError asst::TaskDataSymbolStream::decode(Ap auto opt = append_prefix(sy, sx); if (!opt) { return { std::nullopt, - "decode_vtasks: failed while " + sx.name() + " @ " + sy.name() + ", " + opt.what() }; + "decode_vtasks: failed while " + sx.name() + " @ " + sy.name() + ", " + opt.error() }; } ranges::copy(*opt, std::back_inserter(x)); } diff --git a/src/MaaCore/Config/TaskData/TaskDataSymbolStream.h b/src/MaaCore/Config/TaskData/TaskDataSymbolStream.h index 4dd58fdb37..81a02a9061 100644 --- a/src/MaaCore/Config/TaskData/TaskDataSymbolStream.h +++ b/src/MaaCore/Config/TaskData/TaskDataSymbolStream.h @@ -5,7 +5,7 @@ #include "Config/TaskData.h" #include "TaskDataSymbol.h" -#include "TaskDataTypes.hpp" +#include "TaskDataTypes.h" namespace asst { diff --git a/src/MaaCore/Config/TaskData/TaskDataTypes.hpp b/src/MaaCore/Config/TaskData/TaskDataTypes.h similarity index 81% rename from src/MaaCore/Config/TaskData/TaskDataTypes.hpp rename to src/MaaCore/Config/TaskData/TaskDataTypes.h index 98fd6478b8..f185d8f541 100644 --- a/src/MaaCore/Config/TaskData/TaskDataTypes.hpp +++ b/src/MaaCore/Config/TaskData/TaskDataTypes.h @@ -37,9 +37,9 @@ namespace asst constexpr ResultT&& value() && { return std::move(std::get<0>(m_result_or_error)); } constexpr const ResultT&& value() const&& { return std::move(std::get<0>(m_result_or_error)); } - constexpr std::string& what() & { return std::get<1>(m_result_or_error); } - constexpr const std::string& what() const& { return std::get<1>(m_result_or_error); } - constexpr std::string&& what() && { return std::move(std::get<1>(m_result_or_error)); } - constexpr const std::string&& what() const&& { return std::move(std::get<1>(m_result_or_error)); } + constexpr std::string& error() & { return std::get<1>(m_result_or_error); } + constexpr const std::string& error() const& { return std::get<1>(m_result_or_error); } + constexpr std::string&& error() && { return std::move(std::get<1>(m_result_or_error)); } + constexpr const std::string&& error() const&& { return std::move(std::get<1>(m_result_or_error)); } }; } // namespace asst diff --git a/src/MaaCore/MaaCore.vcxproj b/src/MaaCore/MaaCore.vcxproj index c2f827c378..52d220e77e 100644 --- a/src/MaaCore/MaaCore.vcxproj +++ b/src/MaaCore/MaaCore.vcxproj @@ -50,7 +50,7 @@ - + diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index 141af70b06..bc079a14ad 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -690,7 +690,7 @@ Source\Resource\TaskData - + Source\Resource\TaskData