diff --git a/docs/集成文档.md b/docs/集成文档.md index a041e0f4f3..4b4c3e180e 100644 --- a/docs/集成文档.md +++ b/docs/集成文档.md @@ -52,6 +52,8 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p { "enable": bool, // 是否启用本任务,可选,默认为 true "stage": string, // 关卡名,可选,默认为空,识别当前/上次的关卡。不支持运行中设置 + // 支持全部主线关卡,如 "1-7"、"S3-2"等 + // 另支持少部分资源关卡,如 "CE-6" 等(请参考 C# 集成示例) "medicine": int, // 最大使用理智药数量,可选,默认 0 "stone": int, // 最大吃石头数量,可选,默认 0 "times": int, // 指定次数,可选,默认无穷大 diff --git a/resource/tasks.json b/resource/tasks.json index 2c8eb93622..5e0929e4f8 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -39,6 +39,12 @@ "SwipeRightToStage1-7" ] }, + "EpisodeStageNameOcr": { + "algorithm": "OcrDetect", + "fullMatch": true, + "text": [], + "maxTimes": 10 + }, "Episode10": { "algorithm": "JustReturn", "action": "DoNothing", diff --git a/src/MeoAssistant/FightTask.cpp b/src/MeoAssistant/FightTask.cpp index 87084f9aa4..69035cc6b4 100644 --- a/src/MeoAssistant/FightTask.cpp +++ b/src/MeoAssistant/FightTask.cpp @@ -5,16 +5,18 @@ #include "ProcessTask.h" #include "StageDropsTaskPlugin.h" #include "GameCrashRestartTaskPlugin.h" +#include "StageNavigationTask.h" asst::FightTask::FightTask(AsstCallback callback, void* callback_arg) : PackageTask(std::move(callback), callback_arg, TaskType), m_start_up_task_ptr(std::make_shared(m_callback, m_callback_arg, TaskType)), - m_stage_task_ptr(std::make_shared(m_callback, m_callback_arg, TaskType)), + m_last_battle_task_ptr(std::make_shared(m_callback, m_callback_arg, TaskType)), + m_stage_navigation_task_ptr(std::make_shared(m_callback, m_callback_arg, TaskType)), m_fight_task_ptr(std::make_shared(m_callback, m_callback_arg, TaskType)) { // 进入选关界面(主界面的“终端”点进去) m_start_up_task_ptr-> - set_times_limit("GoLastBattle", 0) + set_times_limit("GoLastBattle", 0) .set_times_limit("StartButton1", 0) .set_times_limit("StartButton2", 0) .set_times_limit("MedicineConfirm", 0) @@ -22,14 +24,17 @@ asst::FightTask::FightTask(AsstCallback callback, void* callback_arg) .set_times_limit("StageSNReturnFlag", 0) .set_ignore_error(false); - // 进入对应的关卡 - m_stage_task_ptr->set_times_limit("StartButton1", 0) + // 进入上次战斗 + m_last_battle_task_ptr->set_tasks({ "UsePrts", "UsePrts-StageSN", "StartButton1", "LastBattle" }); + m_last_battle_task_ptr->set_times_limit("StartButton1", 0) .set_times_limit("StartButton2", 0) .set_times_limit("MedicineConfirm", 0) .set_times_limit("StoneConfirm", 0) .set_times_limit("StageSNReturnFlag", 0) .set_ignore_error(false); + m_stage_navigation_task_ptr->set_enable(false); + // 开始战斗任务 m_fight_task_ptr->set_tasks({ "FightBegin" }) .set_times_limit("MedicineConfirm", 0) @@ -44,7 +49,8 @@ asst::FightTask::FightTask(AsstCallback callback, void* callback_arg) m_game_restart_plugin_ptr->set_retry_times(0); m_subtasks.emplace_back(m_start_up_task_ptr); - m_subtasks.emplace_back(m_stage_task_ptr); + m_subtasks.emplace_back(m_last_battle_task_ptr); + m_subtasks.emplace_back(m_stage_navigation_task_ptr); m_subtasks.emplace_back(m_fight_task_ptr); } @@ -70,11 +76,14 @@ bool asst::FightTask::set_params(const json::value& params) if (!m_finished) { if (stage.empty()) { m_start_up_task_ptr->set_tasks({ "UsePrts", "UsePrts-StageSN", "StartButton1", "StageBegin" }); - m_stage_task_ptr->set_tasks({ "UsePrts", "UsePrts-StageSN", "StartButton1", "LastBattle" }); + m_last_battle_task_ptr->set_enable(true); + m_stage_navigation_task_ptr->set_enable(false); } else { m_start_up_task_ptr->set_tasks({ "StageBegin" }); - m_stage_task_ptr->set_tasks({ stage }); + m_last_battle_task_ptr->set_enable(false); + m_stage_navigation_task_ptr->set_stage_name(stage); + m_stage_navigation_task_ptr->set_enable(true); } } diff --git a/src/MeoAssistant/FightTask.h b/src/MeoAssistant/FightTask.h index f484d851f6..8b323ab91d 100644 --- a/src/MeoAssistant/FightTask.h +++ b/src/MeoAssistant/FightTask.h @@ -8,6 +8,7 @@ namespace asst class ProcessTask; class StageDropsTaskPlugin; class GameCrashRestartTaskPlugin; + class StageNavigationTask; class FightTask final : public PackageTask { @@ -21,7 +22,8 @@ namespace asst protected: std::shared_ptr m_start_up_task_ptr = nullptr; - std::shared_ptr m_stage_task_ptr = nullptr; + std::shared_ptr m_last_battle_task_ptr = nullptr; + std::shared_ptr m_stage_navigation_task_ptr = nullptr; std::shared_ptr m_fight_task_ptr = nullptr; std::shared_ptr m_stage_drops_plugin_ptr = nullptr; std::shared_ptr m_game_restart_plugin_ptr = nullptr; diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index a013a1d6e3..b03da15120 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -99,6 +99,7 @@ + @@ -189,6 +190,7 @@ + diff --git a/src/MeoAssistant/MeoAssistant.vcxproj.filters b/src/MeoAssistant/MeoAssistant.vcxproj.filters index 221ba6a24e..9b5360ce89 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj.filters +++ b/src/MeoAssistant/MeoAssistant.vcxproj.filters @@ -378,6 +378,9 @@ 头文件\Utils + + 头文件\Task\Sub + @@ -644,6 +647,9 @@ 源文件\Task\Plugin\Roguelike + + 源文件\Task\Sub + diff --git a/src/MeoAssistant/StageNavigationTask.cpp b/src/MeoAssistant/StageNavigationTask.cpp new file mode 100644 index 0000000000..075d405b6a --- /dev/null +++ b/src/MeoAssistant/StageNavigationTask.cpp @@ -0,0 +1,67 @@ +#include "StageNavigationTask.h" + +#include + +#include "TaskData.h" +#include "Controller.h" +#include "OcrImageAnalyzer.h" +#include "ProcessTask.h" +#include "Logger.hpp" + +void asst::StageNavigationTask::set_stage_name(std::string stage_name) +{ + m_stage_name = std::move(stage_name); +} + +bool asst::StageNavigationTask::_run() +{ + LogTraceFunction; + + // 已有关卡优先使用 tasks.json 中的逻辑 + if (Task.get(m_stage_name)) { + return ProcessTask(*this, { m_stage_name }).run(); + } + + return chapter_wayfinding() + && swipe_and_find_stage(); +} + +bool asst::StageNavigationTask::chapter_wayfinding() +{ + LogTraceFunction; + + static const std::regex EpisodeRegex(R"(^[A-Z]*(\d+)-\d+$)"); + std::smatch episode_sm; + if (!std::regex_match(m_stage_name, episode_sm, EpisodeRegex)) { + Log.error("Unkown stage", m_stage_name); + return false; + } + + static const std::string EpisodeTaskPrefix = "Episode"; + std::string episode_task_name = EpisodeTaskPrefix + episode_sm[1].str(); + + Log.info("capter name", episode_task_name); + + return Task.get(episode_task_name) + && ProcessTask(*this, { episode_task_name }).run(); +} + +bool asst::StageNavigationTask::swipe_and_find_stage() +{ + LogTraceFunction; + + ProcessTask(*this, { "SwipeToTheRight" }).run(); + + auto task_ptr = Task.get("EpisodeStageNameOcr"); + for (int i = 0; i < task_ptr->max_times; ++i) { + OcrImageAnalyzer analyzer(m_ctrler->get_image()); + analyzer.set_task_info(task_ptr); + analyzer.set_required({ m_stage_name }); + if (analyzer.analyze()) { + m_ctrler->click(analyzer.get_result().front().rect); + return true; + } + ProcessTask(*this, { "SlowlySwipeToTheLeft" }).run(); + } + return false; +} diff --git a/src/MeoAssistant/StageNavigationTask.h b/src/MeoAssistant/StageNavigationTask.h new file mode 100644 index 0000000000..eaaffaedb3 --- /dev/null +++ b/src/MeoAssistant/StageNavigationTask.h @@ -0,0 +1,22 @@ +#pragma once +#include "AbstractTask.h" + +namespace asst +{ + class StageNavigationTask : public AbstractTask + { + public: + using AbstractTask::AbstractTask; + virtual ~StageNavigationTask() noexcept override = default; + + void set_stage_name(std::string stage_name); + + protected: + virtual bool _run() override; + + bool chapter_wayfinding(); + bool swipe_and_find_stage(); + + std::string m_stage_name; + }; +}