mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-20 02:55:38 +08:00
feat: 多文件任务从 json 层面合并后再重新解析 (#6478)
现在如果有 CN 任务
```json
"base": { "text": [ "CN" ], "next": [ "aaa" ] },
"A": { "baseTask": "base", "next": [ "bbb" ] }
"B": { "baseTask": "base", "next": [ "ccc" ] }
```
只需要在 EN 文件中重新定义 base:
```json
"base": { "text": [ "EN" ] }
```
就等价于
```json
"base": { "text": [ "EN" ], "next": [ "aaa" ] },
"A": { "text": [ "EN" ], "next": [ "bbb" ] }
"B": { "text": [ "EN" ], "next": [ "ccc" ] }
```
不必再 copy 重复文件内容。外服适配不再是难题!
close #6313
This commit is contained in:
@@ -170,10 +170,10 @@ Base task 的逻辑优先于 template task。这意味着 `"B@A": { "baseTask":
|
||||
|
||||
#### 多文件任务
|
||||
|
||||
- 后加载的任务文件 (例如外服 `tasks.json`; 下称文件二) 中定义的同名任务直接继承先加载的任务文件 (例如国服 `tasks.json`; 下称文件一) 的参数。
|
||||
- 后加载的任务文件 (例如外服 `tasks.json`; 下称文件二) 中定义的同名任务直接继承先加载的任务文件 (例如国服 `tasks.json`; 下称文件一) 的字段。
|
||||
- 如果文件二中定义的任务在文件一中也定义了同名任务,那么:
|
||||
1. 如果文件二中任务没有 `baseTask` 字段,则直接继承文件一中同名任务的参数。
|
||||
2. 如果文件二中任务有字段 `"baseTask": "#none"`,则不继承文件一中同名任务的参数。
|
||||
1. 如果文件二中任务没有 `baseTask` 字段,则直接继承文件一中同名任务的字段。
|
||||
2. 如果文件二中任务有字段 `"baseTask": "#none"`,则不继承文件一中同名任务的字段。
|
||||
- **若有定义任务 "A",则以 template task 的逻辑处理 "B@A"**
|
||||
- 若未定义任务 "A",则以普通任务的逻辑处理 "B@A"
|
||||
|
||||
|
||||
@@ -163,10 +163,10 @@ Any parameter that is not explicitly defined uses the value of the `baseTask` pa
|
||||
|
||||
#### Multi-File Task
|
||||
|
||||
- A task with the same name defined in a later loaded task file (e.g. `tasks.json` for foreign services; hereinafter called File 2) inherits directly from the parameters of the first loaded task file (e.g. `tasks.json` for official services; hereinafter called File 1).
|
||||
- A task with the same name defined in a later loaded task file (e.g. `tasks.json` for foreign services; hereinafter called File 2) inherits directly from the fields of the first loaded task file (e.g. `tasks.json` for official services; hereinafter called File 1).
|
||||
- If a task defined in File 2 also has a task of the same name defined in File 1, then.
|
||||
1. if the task in File 2 does not have a `baseTask` field, then it inherits the parameters of the task with the same name in File 1 directly.
|
||||
2. If the task in File 2 has the field `"baseTask": "#none"`, then it does not inherit the parameters of the task with the same name in File 1.
|
||||
1. if the task in File 2 does not have a `baseTask` field, then it inherits the fields of the task with the same name in File 1 directly.
|
||||
2. If the task in File 2 has the field `"baseTask": "#none"`, then it does not inherit the fields of the task with the same name in File 1.
|
||||
- **If task "A" is defined, then "B@A" will be treated as template task**
|
||||
- If task "A" is not defined, then "B@A" will be treated as a normal task
|
||||
|
||||
|
||||
@@ -157,16 +157,18 @@ Base task and template task are collectively called **template task**.
|
||||
|
||||
A task with the field `baseTask` is a base task.
|
||||
|
||||
Any parameter that is not explicitly defined uses the parameter of the corresponding task if `baseTask` is not explicitly defined, except for `template` which remains `"taskName.png"`. (without prefix)
|
||||
Base task takes precedence over template task. This means that `"B@A": { "baseTask": "C", ... }` has no relevance to task A.
|
||||
|
||||
#### Other related
|
||||
Any parameter that is not explicitly defined uses the value of the `baseTask` parameter for the corresponding task without a prefix, except for `template` which remains `"taskName.png"` if it is not explicitly defined.
|
||||
|
||||
- Tasks with the same name defined in `tasks.json` in foreign service inherit directly from `tasks.json` in national service, equivalent to `"A": { "baseTask": "A in national service" }`
|
||||
- If task "B@A" is defined in national service `tasks.json` and "B@A" is defined in foreign service `tasks.json`, then
|
||||
1. if foreign service "B@A" has field `"baseTask": ""`, then it does not inherit from national service "B@A"
|
||||
- If there is a defined task "A", then "B@A" is handled with the logic of template task
|
||||
- If there is no defined task "A", then handle "B@A" with the logic of normal task
|
||||
2. If there is no `baseTask` for foreign "B@A", then inherit the parameters of national "B@A" directly
|
||||
#### Multi-File Task
|
||||
|
||||
- A task with the same name defined in a later loaded task file (e.g. `tasks.json` for foreign services; hereinafter called File 2) inherits directly from the fields of the first loaded task file (e.g. `tasks.json` for official services; hereinafter called File 1).
|
||||
- If a task defined in File 2 also has a task of the same name defined in File 1, then.
|
||||
1. if the task in File 2 does not have a `baseTask` field, then it inherits the fields of the task with the same name in File 1 directly.
|
||||
2. If the task in File 2 has the field `"baseTask": "#none"`, then it does not inherit the fields of the task with the same name in File 1.
|
||||
- **If task "A" is defined, then "B@A" will be treated as template task**
|
||||
- If task "A" is not defined, then "B@A" will be treated as a normal task
|
||||
|
||||
### Virtual Task
|
||||
|
||||
@@ -224,6 +226,19 @@ Task.get_raw("B@Loading")->next = { "B#self", "B#next", "B#back" };
|
||||
|
||||
In this case above, `"C@B" -> next` (i.e. `C@A#next`) is `["N1"]` instead of `["C@N0"]`.
|
||||
|
||||
## Expression Calculation
|
||||
|
||||
| Symbol | Meaning | Example |
|
||||
|:---------:|:---:|:--------:|
|
||||
| `@` | Template task | `Fight@ReturnTo` |
|
||||
| `#` (unary) | Virtual task | `#self` |
|
||||
| `#` (binary) | Virtual task | `StartUpThemes#next` |
|
||||
| `*` | Repeat tasks | `(ClickCornerAfterPRTS+ClickCorner)*5` |
|
||||
| `+` | Task list merge | `A+B` |
|
||||
| `^` | Task list difference (in the former but not in the latter, the order remains the same) | `(A+A+B+C)^(A+B+D)` (= `C`) |
|
||||
|
||||
The operators `@`, `#`, `*`, `+`, `^` have priority: `#` (unary) > `@` = `#` (binary) > `*` > `+` = `^`.
|
||||
|
||||
## Schema Check
|
||||
|
||||
This project configures a json schema check for `tasks.json`, the schema file is `docs/maa_tasks_schema.json`.
|
||||
|
||||
@@ -170,10 +170,10 @@ Base task 的邏輯優先於 template task。這代表 `"B@A": { "baseTask": "C"
|
||||
|
||||
#### 多檔任務
|
||||
|
||||
- 後載入的任務檔案(例如外服 `tasks.json`,下稱文件二)中定義的同名任務直接繼承先載入的任務檔案(例如國服 `tasks.json`,下稱文件一)的參數。
|
||||
- 後載入的任務檔案(例如外服 `tasks.json`,下稱文件二)中定義的同名任務直接繼承先載入的任務檔案(例如國服 `tasks.json`,下稱文件一)的欄位。
|
||||
- 如果文件二中定義的任務在文件一中也定義了同名任務,那麼:
|
||||
1. 如果文件二中任務沒有 `baseTask` 欄位,則直接繼承文件一中同名任務的參數。
|
||||
2. 如果文件二中任務有欄位 `"baseTask": "#none"`,則不繼承文件一中同名任務的參數。
|
||||
1. 如果文件二中任務沒有 `baseTask` 欄位,則直接繼承文件一中同名任務的欄位。
|
||||
2. 如果文件二中任務有欄位 `"baseTask": "#none"`,則不繼承文件一中同名任務的欄位。
|
||||
- **若有定義任務 "A",則以 template task 的邏輯處理 "B@A"**
|
||||
- 若未定義任務 "A",則以普通任務的邏輯處理 "B@A"
|
||||
|
||||
|
||||
@@ -23,12 +23,6 @@
|
||||
"PRTS"
|
||||
]
|
||||
},
|
||||
"ChapterDifficultyHard": {
|
||||
"baseTask": "LevelOfDifficulty"
|
||||
},
|
||||
"ChapterDifficultyNormal": {
|
||||
"baseTask": "LevelOfDifficulty"
|
||||
},
|
||||
"EnterChapterDifficultyHard": {
|
||||
"text": [
|
||||
"Start Operation"
|
||||
@@ -39,15 +33,6 @@
|
||||
"Start Operation"
|
||||
]
|
||||
},
|
||||
"ClickedCorrectStageOrSwipe": {
|
||||
"action": "DoNothing",
|
||||
"baseTask": "StartButton1",
|
||||
"next": [
|
||||
"ClickedCorrectStage",
|
||||
"FullStageNavigation"
|
||||
],
|
||||
"reduceOtherTimes": []
|
||||
},
|
||||
"SideStoryReopen": {
|
||||
"roi": [
|
||||
0,
|
||||
@@ -59,22 +44,6 @@
|
||||
"Rerun"
|
||||
]
|
||||
},
|
||||
"StageQueue@StartButton1": {
|
||||
"Doc": "StartButton1",
|
||||
"action": "DoNothing",
|
||||
"baseTask": "StartButton1",
|
||||
"exceededNext": [],
|
||||
"maxTimes": 1,
|
||||
"next": [
|
||||
"StageQueue@StartButton2",
|
||||
"StageQueue@StartButton2Adverse",
|
||||
"StageQueue@UseMedicine",
|
||||
"StageQueue@UseStone",
|
||||
"StageQueue@NoStone",
|
||||
"StageQueue@OfflineConfirm",
|
||||
"StageQueue@StartButton1TryAgain"
|
||||
]
|
||||
},
|
||||
"CF-Open": {
|
||||
"text": [
|
||||
"Event <A Flurry to the Flame> is now",
|
||||
@@ -2135,22 +2104,6 @@
|
||||
"Start"
|
||||
]
|
||||
},
|
||||
"StartButton1TryAgain": {
|
||||
"baseTask": "StartButton1",
|
||||
"exceededNext": [],
|
||||
"next": [
|
||||
"StartButton1#next"
|
||||
],
|
||||
"preDelay": 0,
|
||||
"rectMove": [
|
||||
38,
|
||||
0,
|
||||
35,
|
||||
17
|
||||
],
|
||||
"rectMoveDoc": "Click on 'Actions' to avoid clicking on StartButton2 the second time.",
|
||||
"reduceOtherTimes": []
|
||||
},
|
||||
"PRTS2": {
|
||||
"text": [
|
||||
"Takeover"
|
||||
@@ -5921,8 +5874,6 @@
|
||||
]
|
||||
},
|
||||
"Reclamation@ManufactureStatus": {
|
||||
"Doc": "base_task",
|
||||
"algorithm": "OcrDetect",
|
||||
"roi": [
|
||||
1021,
|
||||
336,
|
||||
@@ -5932,49 +5883,28 @@
|
||||
"text": []
|
||||
},
|
||||
"Reclamation@ManufactureIncrease": {
|
||||
"action": "ClickRect",
|
||||
"baseTask": "Reclamation@ManufactureStatus",
|
||||
"specificRect": [
|
||||
1120,
|
||||
86,
|
||||
111,
|
||||
26
|
||||
],
|
||||
"text": [
|
||||
"Craft"
|
||||
]
|
||||
},
|
||||
"Reclamation@ManufactureDecrease": {
|
||||
"action": "ClickRect",
|
||||
"baseTask": "Reclamation@ManufactureStatus",
|
||||
"specificRect": [
|
||||
1096,
|
||||
288,
|
||||
139,
|
||||
28
|
||||
],
|
||||
"text": [
|
||||
"Insufficient",
|
||||
"materials"
|
||||
]
|
||||
},
|
||||
"Reclamation@DoManufacture": {
|
||||
"action": "ClickSelf",
|
||||
"baseTask": "Reclamation@ManufactureStatus",
|
||||
"postDelay": 1000,
|
||||
"text": [
|
||||
"Craft"
|
||||
]
|
||||
},
|
||||
"Reclamation@ManufactureInsufficientMaterial": {
|
||||
"baseTask": "Reclamation@ManufactureStatus",
|
||||
"text": [
|
||||
"Insufficient",
|
||||
"materials"
|
||||
]
|
||||
},
|
||||
"Reclamation@ManufactureSufficientMaterial": {
|
||||
"baseTask": "Reclamation@ManufactureStatus",
|
||||
"text": [
|
||||
"Craft"
|
||||
]
|
||||
@@ -5992,20 +5922,6 @@
|
||||
"Skip"
|
||||
]
|
||||
},
|
||||
"StartWithDefaultFormation@Reclamation@ConfirmStart": {
|
||||
"baseTask": "Reclamation@ConfirmStart",
|
||||
"next": [],
|
||||
"next_Old": [
|
||||
"Stop"
|
||||
],
|
||||
"next_Old_Doc": "这里原先有个stop,但是会导致StartWithDefaultFormation@Reclamation@Begin中间多出一个Stop,姑且当成是不小心加的删了。"
|
||||
},
|
||||
"StartActionEnter@Reclamation@StartActionEnter": {
|
||||
"baseTask": "Reclamation@StartActionEnter",
|
||||
"next": [
|
||||
"Stop"
|
||||
]
|
||||
},
|
||||
"GachaLastOnceResult": {
|
||||
"text": [
|
||||
"Certificate",
|
||||
|
||||
@@ -51,21 +51,12 @@ std::shared_ptr<asst::TaskInfo> asst::TaskData::get(std::string_view name)
|
||||
return expand_task(name, get_raw(name)).value_or(nullptr);
|
||||
}
|
||||
|
||||
#ifndef ASST_DEBUG
|
||||
const bool forcedReloadResource = std::ifstream("DEBUG").good() || std::ifstream("DEBUG.txt").good();
|
||||
#endif // !ASST_DEBUG
|
||||
|
||||
bool asst::TaskData::parse(const json::value& json)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
#ifndef ASST_DEBUG
|
||||
if (forcedReloadResource) {
|
||||
m_all_tasks_info.clear();
|
||||
}
|
||||
#endif // !ASST_DEBUG
|
||||
|
||||
const auto& json_obj = json.as_object();
|
||||
m_all_tasks_info.clear();
|
||||
const auto& json_obj = m_json_all_tasks_info;
|
||||
|
||||
{
|
||||
enum TaskStatus
|
||||
@@ -76,103 +67,98 @@ bool asst::TaskData::parse(const json::value& json)
|
||||
NotExists, // 不存在的资源
|
||||
};
|
||||
std::unordered_map<std::string_view, TaskStatus> task_status;
|
||||
for (const std::string& name : json_obj | views::keys) {
|
||||
task_status[task_name_view(name)] = ToBeGenerate;
|
||||
|
||||
for (const auto& [name, task_json] : json.as_object()) {
|
||||
std::string_view name_view = task_name_view(name);
|
||||
if (task_json.get("baseTask", "") == "#none") {
|
||||
// 不继承同名任务参数
|
||||
m_json_all_tasks_info[name_view] = task_json.as_object();
|
||||
m_json_all_tasks_info[name_view].erase("baseTask");
|
||||
continue;
|
||||
}
|
||||
if (m_json_all_tasks_info.find(name_view) == m_json_all_tasks_info.cend()) {
|
||||
m_json_all_tasks_info.emplace(name_view, task_json.as_object());
|
||||
continue;
|
||||
}
|
||||
for (const auto& [key, value] : task_json.as_object()) {
|
||||
m_json_all_tasks_info[name_view][key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
auto generate_task_and_its_base = [&](const std::string& name) -> bool {
|
||||
auto generate_task = [&](const std::string& 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;
|
||||
for (std::string_view name : m_json_all_tasks_info | views::keys) {
|
||||
task_status[name] = ToBeGenerate;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
task_status[task_name_view(name)] = NotToBeGenerate;
|
||||
insert_or_assign_raw_task(name, task_info_ptr);
|
||||
return true;
|
||||
};
|
||||
std::function<bool(std::string_view, bool)> generate_task_and_its_base;
|
||||
generate_task_and_its_base = [&](std::string_view name, bool must_true) -> bool {
|
||||
switch (task_status[task_name_view(name)]) {
|
||||
case NotToBeGenerate:
|
||||
// 已经显式生成
|
||||
if (m_raw_all_tasks_info.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
task_status[task_name_view(name)] = NotToBeGenerate;
|
||||
insert_or_assign_raw_task(name, task_info_ptr);
|
||||
return true;
|
||||
};
|
||||
std::function<bool(const std::string&, bool)> generate_fun;
|
||||
generate_fun = [&](const std::string& name, bool must_true) -> bool {
|
||||
switch (task_status[task_name_view(name)]) {
|
||||
case NotToBeGenerate:
|
||||
// 已经显式生成 或 曾经显式生成(外服隐式引用国服资源)
|
||||
if (m_raw_all_tasks_info.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 隐式生成的资源
|
||||
if (size_t p = name.find('@'); p != std::string::npos) {
|
||||
return generate_fun(name.substr(p + 1), must_true);
|
||||
}
|
||||
// 隐式生成的资源
|
||||
if (size_t p = name.find('@'); p != std::string::npos) {
|
||||
return generate_task_and_its_base(name.substr(p + 1), must_true);
|
||||
}
|
||||
|
||||
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);
|
||||
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 = m_json_all_tasks_info.at(name);
|
||||
|
||||
if (auto opt = task_json.find<std::string>("baseTask")) {
|
||||
// BaseTask
|
||||
std::string base = opt.value();
|
||||
if (base == "#none") {
|
||||
// `"baseTask": "#none"` 表示不使用已生成的同名任务
|
||||
}
|
||||
else if (base.empty()) {
|
||||
Log.warn("Use `\"baseTask\": \"#none\"` instead of `\"baseTask\": \"\"` in Task", name);
|
||||
}
|
||||
else {
|
||||
return generate_fun(base, must_true) && generate_task(name, "", get_raw(base), task_json);
|
||||
}
|
||||
}
|
||||
else if (m_raw_all_tasks_info.contains(name)) {
|
||||
// 已生成(外服覆写国服资源)
|
||||
return generate_task(name, "", get_raw(name), task_json);
|
||||
}
|
||||
// BaseTask
|
||||
if (auto opt = task_json.find<std::string>("baseTask")) {
|
||||
std::string base = opt.value();
|
||||
return generate_task_and_its_base(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)) {
|
||||
// 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 (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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
return generate_fun(name, true);
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
for (const std::string& name : json_obj | views::keys) {
|
||||
generate_task_and_its_base(name);
|
||||
for (std::string_view name : json_obj | views::keys) {
|
||||
generate_task_and_its_base(name, true);
|
||||
}
|
||||
|
||||
// 延迟展开,等到一个任务被第一次 get 的时候才展开
|
||||
// debug 时为了做语法检查,会 *提前* 展开
|
||||
/*
|
||||
// 展开 # 型任务
|
||||
for (const auto& [name, old_task] : m_raw_all_tasks_info) {
|
||||
expand_task(name, old_task);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#ifdef ASST_DEBUG
|
||||
@@ -681,7 +667,7 @@ std::optional<asst::TaskData::taskptr_t> asst::TaskData::expand_task(std::string
|
||||
}
|
||||
}
|
||||
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_task_info(const std::string& name, const json::value& task_json,
|
||||
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)
|
||||
{
|
||||
if (default_ptr == nullptr) {
|
||||
@@ -731,7 +717,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_task_info(const std::string&
|
||||
return task_info_ptr;
|
||||
}
|
||||
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(const std::string& name,
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(std::string_view name,
|
||||
const json::value& task_json,
|
||||
std::shared_ptr<MatchTaskInfo> default_ptr)
|
||||
{
|
||||
@@ -740,12 +726,12 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(const std::st
|
||||
}
|
||||
auto match_task_info_ptr = std::make_shared<MatchTaskInfo>();
|
||||
#ifdef ASST_DEBUG
|
||||
if (task_json.get("template", "") == name + ".png") {
|
||||
if (task_json.get("template", "") == std::string(name) + ".png") {
|
||||
Log.warn("template name of task", name, "could be omitted.");
|
||||
}
|
||||
#endif
|
||||
// template 留空时不从模板任务继承
|
||||
match_task_info_ptr->templ_name = task_json.get("template", name + ".png");
|
||||
match_task_info_ptr->templ_name = task_json.get("template", std::string(name) + ".png");
|
||||
m_templ_required.emplace(match_task_info_ptr->templ_name);
|
||||
|
||||
// 其余若留空则继承模板任务
|
||||
@@ -761,7 +747,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_match_task_info(const std::st
|
||||
return match_task_info_ptr;
|
||||
}
|
||||
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info([[maybe_unused]] const std::string& name,
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info([[maybe_unused]] std::string_view name,
|
||||
const json::value& task_json,
|
||||
std::shared_ptr<OcrTaskInfo> default_ptr)
|
||||
{
|
||||
@@ -792,7 +778,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_ocr_task_info([[maybe_unused]
|
||||
return ocr_task_info_ptr;
|
||||
}
|
||||
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info([[maybe_unused]] const std::string& name,
|
||||
asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info([[maybe_unused]] std::string_view name,
|
||||
const json::value& task_json,
|
||||
std::shared_ptr<HashTaskInfo> default_ptr)
|
||||
{
|
||||
@@ -823,7 +809,7 @@ asst::TaskData::taskptr_t asst::TaskData::generate_hash_task_info([[maybe_unused
|
||||
return hash_task_info_ptr;
|
||||
}
|
||||
|
||||
bool asst::TaskData::append_base_task_info(taskptr_t task_info_ptr, const std::string& name,
|
||||
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)
|
||||
{
|
||||
@@ -954,7 +940,7 @@ asst::TaskData::taskptr_t asst::TaskData::_default_task_info()
|
||||
#ifdef ASST_DEBUG
|
||||
// 为了解决类似 beddc7c828126c678391e0b4da288db6d2c2d58a 导致的问题,加载的时候做一个语法检查
|
||||
// 主要是处理是否包含未知键值的问题
|
||||
bool asst::TaskData::syntax_check(const std::string& task_name, const json::value& task_json)
|
||||
bool asst::TaskData::syntax_check(std::string_view task_name, const json::value& task_json)
|
||||
{
|
||||
// clang-format off
|
||||
// 以下按字典序排序
|
||||
|
||||
@@ -32,33 +32,33 @@ namespace asst
|
||||
const taskptr_t default_task_info_ptr = _default_task_info();
|
||||
|
||||
// 这是下面几个函数的封装
|
||||
taskptr_t generate_task_info(const std::string& name, const json::value&, taskptr_t default_ptr,
|
||||
taskptr_t generate_task_info(std::string_view name, const json::value&, taskptr_t default_ptr,
|
||||
std::string_view task_prefix = "");
|
||||
|
||||
taskptr_t generate_match_task_info(const std::string& name, const json::value&,
|
||||
taskptr_t generate_match_task_info(std::string_view name, const json::value&,
|
||||
std::shared_ptr<MatchTaskInfo> default_ptr);
|
||||
taskptr_t generate_ocr_task_info(const std::string& name, const json::value&,
|
||||
taskptr_t generate_ocr_task_info(std::string_view name, const json::value&,
|
||||
std::shared_ptr<OcrTaskInfo> default_ptr);
|
||||
taskptr_t generate_hash_task_info(const std::string& name, const json::value&,
|
||||
taskptr_t generate_hash_task_info(std::string_view name, const json::value&,
|
||||
std::shared_ptr<HashTaskInfo> default_ptr);
|
||||
// TaskInfo 的基础成员
|
||||
bool append_base_task_info(taskptr_t task_info_ptr, const std::string& name, const json::value& task_json,
|
||||
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(const std::string& task_name, 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 task_name;
|
||||
return std::string(task_name);
|
||||
}
|
||||
if (task_name.empty()) {
|
||||
return std::string(task_prefix);
|
||||
}
|
||||
if (task_name.starts_with('#')) {
|
||||
return std::string(task_prefix) + task_name;
|
||||
return std::string(task_prefix) + std::string(task_name);
|
||||
}
|
||||
return std::string(task_prefix) + '@' + 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_view)
|
||||
{
|
||||
@@ -83,11 +83,7 @@ namespace asst
|
||||
}
|
||||
l = r + 1;
|
||||
}
|
||||
if (has_same_prefix) [[unlikely]] {
|
||||
task_list.emplace_back(base);
|
||||
continue;
|
||||
}
|
||||
task_list.emplace_back(append_prefix(base, task_prefix));
|
||||
task_list.emplace_back(has_same_prefix ? base : append_prefix(base, task_prefix));
|
||||
}
|
||||
return task_list;
|
||||
};
|
||||
@@ -146,7 +142,7 @@ namespace asst
|
||||
bool& task_changed, bool multi);
|
||||
std::optional<taskptr_t> expand_task(std::string_view name, taskptr_t old_task);
|
||||
#ifdef ASST_DEBUG
|
||||
bool syntax_check(const std::string& task_name, const json::value& task_json);
|
||||
bool syntax_check(std::string_view task_name, const json::value& task_json);
|
||||
#endif
|
||||
std::shared_ptr<TaskInfo> get_raw(std::string_view name) const;
|
||||
template <typename TargetTaskInfoType>
|
||||
@@ -176,6 +172,7 @@ namespace asst
|
||||
std::unordered_set<std::string> m_task_names;
|
||||
std::unordered_map<std::string_view, taskptr_t> m_raw_all_tasks_info;
|
||||
std::unordered_map<std::string_view, taskptr_t> m_all_tasks_info;
|
||||
std::unordered_map<std::string_view, json::object> m_json_all_tasks_info;
|
||||
std::unordered_set<std::string> m_templ_required;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user