From 59eac9529dff7cba102aa273ddf596e955e6c457 Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Mon, 9 Oct 2023 23:03:35 +0800 Subject: [PATCH] =?UTF-8?q?rft:=20=E4=BB=8E=20TaskData=20=E4=B8=AD?= =?UTF-8?q?=E6=8B=86=E5=87=BA=20JsonMisc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MaaCore/Config/TaskData.cpp | 203 +++++----------------------- src/MaaCore/MaaCore.vcxproj | 1 + src/MaaCore/MaaCore.vcxproj.filters | 3 + src/MaaCore/Utils/JsonMisc.hpp | 151 +++++++++++++++++++++ 4 files changed, 191 insertions(+), 167 deletions(-) create mode 100644 src/MaaCore/Utils/JsonMisc.hpp diff --git a/src/MaaCore/Config/TaskData.cpp b/src/MaaCore/Config/TaskData.cpp index 2fe1372fb8..975147ac2c 100644 --- a/src/MaaCore/Config/TaskData.cpp +++ b/src/MaaCore/Config/TaskData.cpp @@ -10,143 +10,11 @@ #include "Common/AsstTypes.h" #include "GeneralConfig.h" #include "TemplResource.h" +#include "Utils/JsonMisc.hpp" #include "Utils/Logger.hpp" #include "Utils/Ranges.hpp" #include "Utils/StringMisc.hpp" -namespace asst -{ - // base types - template - requires(std::constructible_from) - bool parse_json_as(const json::value& input, OutT& output) - { - if (input.is()) { - output = input.as(); - return true; - } - return false; - } - - bool parse_json_as(const json::value& input, AlgorithmType& output) - { - if (input.is_string()) { - output = get_algorithm_type(input.as_string()); - return output != AlgorithmType::Invalid; - } - return false; - } - - bool parse_json_as(const json::value& input, ProcessTaskAction& output) - { - if (input.is_string()) { - output = get_action_type(input.as_string()); - return output != ProcessTaskAction::Invalid; - } - return false; - } - - // std::pair <- [first, second] - template - requires(requires(const json::value& input, FirstT x, SecondT y) { - parse_json_as(input, x) && parse_json_as(input, y); - }) - bool parse_json_as(const json::value& input, std::pair& output) - { - if (!input.is_array()) { - return false; - } - const auto& items = input.as_array(); - if (items.size() != 2) { - return false; - } - return parse_json_as(items[0], output.first) && parse_json_as(items[1], output.second); - } - - // std::vector <- val | [val, ...] - template - requires(requires(const json::value& input, ValT x) { parse_json_as(input, x); }) - bool parse_json_as(const json::value& input, std::vector& output) - { - if (!input.is_array()) { - if constexpr (std::constructible_from) { - if (input.is()) { - output = { input.as() }; - return true; - } - } - return false; - } - const auto& items = input.as_array(); - output.clear(); - for (const auto& item : items) { - ValT val; - if (!parse_json_as(item, val)) { - output.clear(); - return false; - } - output.emplace_back(std::move(val)); - } - return true; - } - - // asst::Rect <- [int, int, int, int] - bool parse_json_as(const json::value& input, asst::Rect& output) - { - if (!input.is_array()) { - return false; - } - const auto& items = input.as_array(); - if (items.size() != 4) { - return false; - } - return parse_json_as(items[0], output.x) && parse_json_as(items[1], output.y) && - parse_json_as(items[2], output.width) && parse_json_as(items[3], output.height); - } - - template - std::optional parse_json_as(const json::value& input) - { - OutT output; - return parse_json_as(input, output) ? output : std::nullopt; - } - - template - requires(std::constructible_from || std::constructible_from>) - bool get_value_or(std::string_view repr, const json::value& input, const std::string& key, OutT& output, - DefaultT&& default_val) - { - auto opt = input.find(key); - if (!opt) { - if constexpr (std::constructible_from) { - output = std::forward(default_val); - } - else { - output = default_val(); - } - return true; - } - if (parse_json_as(*opt, output)) { -#ifdef ASST_DEBUG - // 如果有默认值,检查是否与默认值相同 - if constexpr (std::constructible_from) { - if (output == default_val) { - Log.warn("Value of", key, "in", repr, "is same as default value"); - } - } - else { - if (output == default_val()) { - Log.warn("Value of", key, "in", repr, "is same as default value"); - } - } -#endif - return true; - } - Log.error("Invalid type of", key, "in", repr); - return false; - } -} // namespace asst - const std::unordered_set& asst::TaskData::get_templ_required() const noexcept { return m_templ_required; @@ -443,7 +311,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_task_info(std::string_view na // 获取 algorithm 并按照 algorithm 生成 TaskInfo AlgorithmType algorithm; - get_value_or(name, task_json, "algorithm", algorithm, default_ptr->algorithm); + utils::get_value_or(name, task_json, "algorithm", algorithm, default_ptr->algorithm); taskptr_t task_ptr = nullptr; switch (algorithm) { @@ -484,8 +352,8 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_v default_ptr = default_match_task_info_ptr; } auto match_task_info_ptr = std::make_shared(); - if (!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 std::vector { std::string(name) + ".png" }; })) { return nullptr; } @@ -523,7 +391,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_v return nullptr; } - get_value_or(name, task_json, "maskRange", match_task_info_ptr->mask_range, default_ptr->mask_range); + utils::get_value_or(name, task_json, "maskRange", match_task_info_ptr->mask_range, default_ptr->mask_range); return match_task_info_ptr; } @@ -535,7 +403,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info(std::string_vie } auto ocr_task_info_ptr = std::make_shared(); - // text 不允许为字符串,必须是字符串数组,不能用 get_value_or + // text 不允许为字符串,必须是字符串数组,不能用 utils::get_value_or auto array_opt = task_json.find("text"); ocr_task_info_ptr->text = array_opt ? to_string_list(array_opt.value()) : default_ptr->text; #ifdef ASST_DEBUG @@ -543,11 +411,11 @@ asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info(std::string_vie Log.warn("Ocr task", name, "has implicit empty text."); } #endif - get_value_or(name, task_json, "fullMatch", ocr_task_info_ptr->full_match, default_ptr->full_match); - get_value_or(name, task_json, "isAscii", ocr_task_info_ptr->is_ascii, default_ptr->is_ascii); - get_value_or(name, task_json, "withoutDet", ocr_task_info_ptr->without_det, default_ptr->without_det); - get_value_or(name, task_json, "replaceFull", ocr_task_info_ptr->replace_full, default_ptr->replace_full); - get_value_or(name, task_json, "ocrReplace", ocr_task_info_ptr->replace_map, default_ptr->replace_map); + utils::get_value_or(name, task_json, "fullMatch", ocr_task_info_ptr->full_match, default_ptr->full_match); + utils::get_value_or(name, task_json, "isAscii", ocr_task_info_ptr->is_ascii, default_ptr->is_ascii); + utils::get_value_or(name, task_json, "withoutDet", ocr_task_info_ptr->without_det, default_ptr->without_det); + utils::get_value_or(name, task_json, "replaceFull", ocr_task_info_ptr->replace_full, default_ptr->replace_full); + utils::get_value_or(name, task_json, "ocrReplace", ocr_task_info_ptr->replace_map, default_ptr->replace_map); return ocr_task_info_ptr; } @@ -558,7 +426,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info(std::string_vi default_ptr = default_hash_task_info_ptr; } auto hash_task_info_ptr = std::make_shared(); - // hash 不允许为字符串,必须是字符串数组,不能用 get_value_or + // hash 不允许为字符串,必须是字符串数组,不能用 utils::get_value_or auto array_opt = task_json.find("hash"); hash_task_info_ptr->hashes = array_opt ? to_string_list(array_opt.value()) : default_ptr->hashes; #ifdef ASST_DEBUG @@ -566,9 +434,9 @@ asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info(std::string_vi Log.warn("Hash task", name, "has implicit empty hashes."); } #endif - get_value_or(name, task_json, "threshold", hash_task_info_ptr->dist_threshold, default_ptr->dist_threshold); - get_value_or(name, task_json, "maskRange", hash_task_info_ptr->mask_range, default_ptr->mask_range); - get_value_or(name, task_json, "bound", hash_task_info_ptr->bound, default_ptr->bound); + utils::get_value_or(name, task_json, "threshold", hash_task_info_ptr->dist_threshold, default_ptr->dist_threshold); + utils::get_value_or(name, task_json, "maskRange", hash_task_info_ptr->mask_range, default_ptr->mask_range); + utils::get_value_or(name, task_json, "bound", hash_task_info_ptr->bound, default_ptr->bound); return hash_task_info_ptr; } @@ -579,26 +447,27 @@ bool asst::TaskData::append_base_task_info(taskptr_t task_info_ptr, std::string_ default_ptr = default_task_info_ptr; } - get_value_or(name, task_json, "action", task_info_ptr->action, default_ptr->action); - get_value_or(name, task_json, "cache", task_info_ptr->cache, default_ptr->cache); - get_value_or(name, task_json, "maxTimes", task_info_ptr->max_times, default_ptr->max_times); - get_value_or(name, task_json, "exceededNext", task_info_ptr->exceeded_next, - [&]() { return append_prefix(default_ptr->exceeded_next, task_prefix); }); - get_value_or(name, task_json, "onErrorNext", task_info_ptr->on_error_next, - [&]() { return append_prefix(default_ptr->on_error_next, task_prefix); }); - get_value_or(name, task_json, "preDelay", task_info_ptr->pre_delay, default_ptr->pre_delay); - get_value_or(name, task_json, "postDelay", task_info_ptr->post_delay, default_ptr->post_delay); - get_value_or(name, task_json, "reduceOtherTimes", task_info_ptr->reduce_other_times, - [&]() { return append_prefix(default_ptr->reduce_other_times, task_prefix); }); - get_value_or(name, task_json, "roi", task_info_ptr->roi, default_ptr->roi); - get_value_or(name, task_json, "sub", task_info_ptr->sub, - [&]() { return append_prefix(default_ptr->sub, task_prefix); }); - get_value_or(name, task_json, "subErrorIgnored", task_info_ptr->sub_error_ignored, default_ptr->sub_error_ignored); - get_value_or(name, task_json, "next", task_info_ptr->next, - [&]() { return append_prefix(default_ptr->next, task_prefix); }); - get_value_or(name, task_json, "rectMove", task_info_ptr->rect_move, default_ptr->rect_move); - get_value_or(name, task_json, "specificRect", task_info_ptr->specific_rect, default_ptr->specific_rect); - get_value_or(name, task_json, "specialParams", task_info_ptr->special_params, default_ptr->special_params); + 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) { diff --git a/src/MaaCore/MaaCore.vcxproj b/src/MaaCore/MaaCore.vcxproj index 39741b1b95..8775c01009 100644 --- a/src/MaaCore/MaaCore.vcxproj +++ b/src/MaaCore/MaaCore.vcxproj @@ -196,6 +196,7 @@ + diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index c2157f5ddc..172a36af45 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -309,6 +309,9 @@ Source\Utils + + Source\Utils + Source\Utils diff --git a/src/MaaCore/Utils/JsonMisc.hpp b/src/MaaCore/Utils/JsonMisc.hpp new file mode 100644 index 0000000000..4871d0392d --- /dev/null +++ b/src/MaaCore/Utils/JsonMisc.hpp @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include + +#include "Common/AsstTypes.h" +#include "Logger.hpp" + +namespace asst::utils +{ + // base types + template + requires(std::constructible_from) + bool parse_json_as(const json::value& input, OutT& output) + { + if (input.is()) { + output = input.as(); + return true; + } + return false; + } + + bool parse_json_as(const json::value& input, AlgorithmType& output) + { + if (input.is_string()) { + output = get_algorithm_type(input.as_string()); + return output != AlgorithmType::Invalid; + } + return false; + } + + bool parse_json_as(const json::value& input, ProcessTaskAction& output) + { + if (input.is_string()) { + output = get_action_type(input.as_string()); + return output != ProcessTaskAction::Invalid; + } + return false; + } + + // std::pair <- [first, second] + template + requires(requires(const json::value& input, FirstT x, SecondT y) { + parse_json_as(input, x) && parse_json_as(input, y); + }) + bool parse_json_as(const json::value& input, std::pair& output) + { + if (!input.is_array()) { + return false; + } + const auto& items = input.as_array(); + if (items.size() != 2) { + return false; + } + return parse_json_as(items[0], output.first) && parse_json_as(items[1], output.second); + } + + // std::vector <- val | [val, ...] + template + requires(requires(const json::value& input, ValT x) { parse_json_as(input, x); }) + bool parse_json_as(const json::value& input, std::vector& output) + { + if (!input.is_array()) { + if constexpr (std::constructible_from) { + if (input.is()) { + output = { input.as() }; + return true; + } + } + return false; + } + const auto& items = input.as_array(); + output.clear(); + for (const auto& item : items) { + ValT val; + if (!parse_json_as(item, val)) { + output.clear(); + return false; + } + output.emplace_back(std::move(val)); + } + return true; + } + + // asst::Rect <- [int, int, int, int] + bool parse_json_as(const json::value& input, asst::Rect& output) + { + if (!input.is_array()) { + return false; + } + const auto& items = input.as_array(); + if (items.size() != 4) { + return false; + } + return parse_json_as(items[0], output.x) && parse_json_as(items[1], output.y) && + parse_json_as(items[2], output.width) && parse_json_as(items[3], output.height); + } + + template + requires(requires(const json::value& input, OutT& output) { parse_json_as(input, output); }) + std::optional parse_json_as(const json::value& input) + { + OutT output; + return parse_json_as(input, output) ? output : std::nullopt; + } + + template + requires(std::constructible_from || std::constructible_from>) + bool get_value_or(std::string_view repr, const json::value& input, const std::string& key, OutT& output, + DefaultT&& default_val) + { + auto opt = input.find(key); + if (!opt) { + if constexpr (std::constructible_from) { + output = std::forward(default_val); + } + else { + output = default_val(); + } + return true; + } + if (parse_json_as(*opt, output)) { +#ifdef ASST_DEBUG + // 如果有默认值,检查是否与默认值相同 + if constexpr (std::constructible_from) { + if (output == default_val) { + Log.warn("Value of", key, "in", repr, "is same as default value"); + } + } + else { + if (output == default_val()) { + Log.warn("Value of", key, "in", repr, "is same as default value"); + } + } +#endif + return true; + } + Log.error("Invalid type of", key, "in", repr); + return false; + } + + template + requires(std::constructible_from || std::constructible_from>) + std::optional get_value_or(std::string_view repr, const json::value& input, const std::string& key, + DefaultT&& default_val) + { + OutT output; + return get_value_or(repr, input, key, output, std::forward(default_val)) ? output : std::nullopt; + } +} // namespace asst::utils