#pragma once #include "Resource/AbstractConfigerWithTempl.h" #include #include #include #include "Utils/AsstTypes.h" #ifdef ASST_DEBUG #include "Utils/Logger.hpp" #endif namespace asst { struct TaskInfo; class TaskData final : public SingletonHolder, public AbstractConfigerWithTempl { private: std::shared_ptr _default_match_task_info(); std::shared_ptr _default_ocr_task_info(); std::shared_ptr _default_hash_task_info(); std::shared_ptr _default_task_info(); // 从模板任务生成 const std::shared_ptr default_match_task_info_ptr = _default_match_task_info(); const std::shared_ptr default_ocr_task_info_ptr = _default_ocr_task_info(); const std::shared_ptr default_hash_task_info_ptr = _default_hash_task_info(); const std::shared_ptr default_task_info_ptr = _default_task_info(); // 这是下面几个函数的封装 std::shared_ptr generate_task_info(const std::string& name, const json::value&, std::shared_ptr default_ptr, std::string_view task_prefix = ""); std::shared_ptr generate_match_task_info(const std::string& name, const json::value&, std::shared_ptr default_ptr); std::shared_ptr generate_ocr_task_info(const std::string& name, const json::value&, std::shared_ptr default_ptr); std::shared_ptr generate_hash_task_info(const std::string& name, const json::value&, std::shared_ptr default_ptr); // TaskInfo 的基础成员 bool append_base_task_info(std::shared_ptr task_info_ptr, const std::string& name, const json::value& task_json, std::shared_ptr default_ptr, std::string_view task_prefix = ""); static std::vector append_prefix(const std::vector& base_task_list, std::string_view task_prefix) { if (task_prefix.empty()) { return base_task_list; } std::vector 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(std::string(task_prefix) + "@" + base); } } return task_list; }; // 运行时动态生成任务 static std::shared_ptr _generate_task_info(const std::shared_ptr& base_ptr, const std::string& task_prefix) { std::shared_ptr task_info_ptr; switch (base_ptr->algorithm) { case AlgorithmType::MatchTemplate: task_info_ptr = std::make_shared(*std::dynamic_pointer_cast(base_ptr)); break; case AlgorithmType::OcrDetect: task_info_ptr = std::make_shared(*std::dynamic_pointer_cast(base_ptr)); break; case AlgorithmType::Hash: task_info_ptr = std::make_shared(*std::dynamic_pointer_cast(base_ptr)); break; default: task_info_ptr = std::make_shared(*base_ptr); break; } task_info_ptr->name = task_prefix + "@" + base_ptr->name; 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; } public: virtual ~TaskData() override = default; virtual const std::unordered_set& get_templ_required() const noexcept override; template requires(std::derived_from || std::same_as) // Parameter must be a TaskInfo std::shared_ptr get(const std::string& name, bool with_emplace = true) { // 普通 task 或已经生成过的 `@` 型 task if (auto it = m_all_tasks_info.find(name); it != m_all_tasks_info.cend()) [[likely]] { if constexpr (std::same_as) { return it->second; } else { return std::dynamic_pointer_cast(it->second); } } size_t at_pos = name.find('@'); if (at_pos == std::string::npos) [[unlikely]] { return nullptr; } // `@` 前面的字符长度 size_t name_len = at_pos; auto base_task_iter = get(name.substr(name_len + 1), with_emplace); 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 (with_emplace) { 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) { return task_info_ptr; } else { return std::dynamic_pointer_cast(task_info_ptr); } } protected: virtual bool parse(const json::value& json) override; private: static AlgorithmType get_algorithm_type(std::string_view algorithm_str) { if (algorithm_str == "matchtemplate") { return AlgorithmType::MatchTemplate; } else if (algorithm_str == "justreturn") { return AlgorithmType::JustReturn; } else if (algorithm_str == "ocrdetect") { return AlgorithmType::OcrDetect; } else if (algorithm_str == "hash") { return AlgorithmType::Hash; } return AlgorithmType::Invalid; } static ProcessTaskAction get_action_type(std::string_view action_str) { if (action_str == "clickself") { return ProcessTaskAction::ClickSelf; } else if (action_str == "clickrand") { return ProcessTaskAction::ClickRand; } else if (action_str == "donothing" || action_str.empty()) { return ProcessTaskAction::DoNothing; } else if (action_str == "stop") { return ProcessTaskAction::Stop; } else if (action_str == "clickrect") { return ProcessTaskAction::ClickRect; } else if (action_str == "swipetotheleft") { return ProcessTaskAction::SwipeToTheLeft; } else if (action_str == "swipetotheright") { return ProcessTaskAction::SwipeToTheRight; } else if (action_str == "slowlyswipetotheleft") { return ProcessTaskAction::SlowlySwipeToTheLeft; } else if (action_str == "slowlyswipetotheright") { return ProcessTaskAction::SlowlySwipeToTheRight; } return ProcessTaskAction::Invalid; } #ifdef ASST_DEBUG bool syntax_check(const std::string& task_name, const json::value& task_json); #endif protected: std::unordered_map> m_all_tasks_info; std::unordered_set m_templ_required; }; inline static auto& Task = TaskData::get_instance(); } // namespace asst