From c985cd0ca36fa0cd2261c5b19f4fce24a20563b0 Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Sun, 6 Nov 2022 01:38:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20baseTask=20=E5=AE=9A=E4=B9=89=E4=BD=86?= =?UTF-8?q?=E7=95=99=E7=A9=BA=E8=A1=A8=E7=A4=BA=E4=B8=8D=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=B7=B2=E7=94=9F=E6=88=90=E7=9A=84=E5=90=8C=E5=90=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 例如国际服覆写不使用同名国服任务 perf: 检测任务是否循环依赖(在此之前若循环依赖会直接 runtime error (递归爆栈)) 例如 `"A": { "baseTask": "A" }` --- src/MeoAssistant/TaskData.cpp | 84 ++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/src/MeoAssistant/TaskData.cpp b/src/MeoAssistant/TaskData.cpp index 0c00fc07b8..dc94087c05 100644 --- a/src/MeoAssistant/TaskData.cpp +++ b/src/MeoAssistant/TaskData.cpp @@ -54,9 +54,16 @@ bool asst::TaskData::parse(const json::value& json) const auto& json_obj = json.as_object(); { - std::unordered_map to_be_generated; + enum TaskStatus + { + NotToBeGenerate = 0, // 已经显式生成 或 不是待显式生成 的资源 + ToBeGenerate, // 待生成 的资源 + Generating, // 正在生成 的资源 + NotExists, // 不存在的资源 + }; + std::unordered_map task_status; for (const std::string& name : json_obj | views::keys) { - to_be_generated[task_name_view(name)] = true; + task_status[task_name_view(name)] = ToBeGenerate; } auto generate_task_and_its_base = [&](const std::string& name) -> bool { @@ -66,52 +73,65 @@ bool asst::TaskData::parse(const json::value& json) if (task_info_ptr == nullptr) { return false; } - to_be_generated[task_name_view(name)] = false; + task_status[task_name_view(name)] = NotToBeGenerate; insert_or_assign_raw_task(name, task_info_ptr); return true; }; std::function generate_fun; - // must_true 若为真,那么 return false 了就是炸了。 - // 否则可能只是某个 B@A 的任务没定义 A(这不是少见现象,例如 Roguelike@Abandon) generate_fun = [&](const std::string& name, bool must_true) -> bool { - // 不是需要 generate 的资源(不在 tasks.json 中) - if (!to_be_generated[task_name_view(name)]) { - // 已生成(它是之前加载过的某个资源的 base) + switch (task_status[task_name_view(name)]) { + case NotToBeGenerate: + // 已经显式生成 或 曾经显式生成(外服隐式引用国服资源) if (m_raw_all_tasks_info.contains(name)) { return true; } - // 不在 json 内且未生成(例如生成 C@B@A 时没有定义 B@A,而是定义了 A) + + // 隐式生成的资源 if (size_t p = name.find('@'); p != std::string::npos) { return generate_fun(name.substr(p + 1), must_true); } - // 例如 Roguelike@Abandon 在这里如果 must_true = true,会报 `Unknown task: Abandon` + + task_status[name] = NotExists; + [[fallthrough]]; + case NotExists: if (must_true) { + // 必须有名字为 name 的资源 Log.error("Unknown task:", name); } + // 不一定必须有名字为 name 的资源,例如 Roguelike@Abandon 不必有 Abandon. + return false; + case ToBeGenerate: { + task_status[name] = Generating; + const json::value& task_json = json_obj.at(name); + + if (auto opt = task_json.find("baseTask")) { + // BaseTask + std::string base = opt.value(); + if (!base.empty()) { + return generate_fun(base, must_true) && generate_task(name, "", get_raw(base), task_json); + } + // `"baseTask": ""` 表示不使用已生成的同名任务 + } + else if (m_raw_all_tasks_info.contains(name)) { + // 已生成(外服覆写国服资源) + return generate_task(name, "", get_raw(name), task_json); + } + + // TemplateTask + if (size_t p = name.find('@'); p != std::string::npos) { + if (std::string base = name.substr(p + 1); generate_fun(base, false)) { + return generate_task(name, name.substr(0, p), get_raw(base), task_json); + } + } + return generate_task(name, "", nullptr, task_json); + } + [[unlikely]] case Generating: + Log.error("Task", name, "is generated cyclically"); + return false; + [[unlikely]] default: + Log.error("Task", name, "has unknown status"); return false; } - const json::value& task_json = json_obj.at(name); - - // 已生成(例如国际服覆写国服资源) - if (m_raw_all_tasks_info.contains(name)) { - return generate_task(name, "", get_raw(name), task_json); - } - - // BaseTask - if (auto opt = task_json.find("baseTask")) { - std::string base = opt.value(); - return generate_fun(base, must_true) && generate_task(name, "", get_raw(base), task_json); - } - - // TemplateTask - if (size_t p = name.find('@'); p != std::string::npos) { - if (std::string base = name.substr(p + 1); generate_fun(base, false)) { - return generate_task(name, name.substr(0, p), get_raw(base), task_json); - } - // 这类任务有点多,非必要不输出( - // Log.debug("Task", name, "based on unknown task, just use task_json."); - } - return generate_task(name, "", nullptr, task_json); }; return generate_fun(name, true); };