feat: 支持全部主线关卡导航(仅 core 部分)

This commit is contained in:
MistEO
2022-08-11 00:04:24 +08:00
parent eae1ce7a43
commit 028f55558e
8 changed files with 124 additions and 8 deletions

View File

@@ -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, // 指定次数,可选,默认无穷大

View File

@@ -39,6 +39,12 @@
"SwipeRightToStage1-7"
]
},
"EpisodeStageNameOcr": {
"algorithm": "OcrDetect",
"fullMatch": true,
"text": [],
"maxTimes": 10
},
"Episode10": {
"algorithm": "JustReturn",
"action": "DoNothing",

View File

@@ -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<ProcessTask>(m_callback, m_callback_arg, TaskType)),
m_stage_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType)),
m_last_battle_task_ptr(std::make_shared<ProcessTask>(m_callback, m_callback_arg, TaskType)),
m_stage_navigation_task_ptr(std::make_shared<StageNavigationTask>(m_callback, m_callback_arg, TaskType)),
m_fight_task_ptr(std::make_shared<ProcessTask>(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);
}
}

View File

@@ -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<ProcessTask> m_start_up_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_stage_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_last_battle_task_ptr = nullptr;
std::shared_ptr<StageNavigationTask> m_stage_navigation_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_fight_task_ptr = nullptr;
std::shared_ptr<StageDropsTaskPlugin> m_stage_drops_plugin_ptr = nullptr;
std::shared_ptr<GameCrashRestartTaskPlugin> m_game_restart_plugin_ptr = nullptr;

View File

@@ -99,6 +99,7 @@
<ClInclude Include="StageDropsConfiger.h" />
<ClInclude Include="StageDropsImageAnalyzer.h" />
<ClInclude Include="StageDropsTaskPlugin.h" />
<ClInclude Include="StageNavigationTask.h" />
<ClInclude Include="StartGameTaskPlugin.h" />
<ClInclude Include="StartUpTask.h" />
<ClInclude Include="StopGameTaskPlugin.h" />
@@ -189,6 +190,7 @@
<ClCompile Include="StageDropsConfiger.cpp" />
<ClCompile Include="StageDropsImageAnalyzer.cpp" />
<ClCompile Include="StageDropsTaskPlugin.cpp" />
<ClCompile Include="StageNavigationTask.cpp" />
<ClCompile Include="StartGameTaskPlugin.cpp" />
<ClCompile Include="StartUpTask.cpp" />
<ClCompile Include="StopGameTaskPlugin.cpp" />

View File

@@ -378,6 +378,9 @@
<ClInclude Include="NoWarningCVMat.h">
<Filter>头文件\Utils</Filter>
</ClInclude>
<ClInclude Include="StageNavigationTask.h">
<Filter>头文件\Task\Sub</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Controller.cpp">
@@ -644,6 +647,9 @@
<ClCompile Include="RoguelikeResetTaskPlugin.cpp">
<Filter>源文件\Task\Plugin\Roguelike</Filter>
</ClCompile>
<ClCompile Include="StageNavigationTask.cpp">
<Filter>源文件\Task\Sub</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\resource\config.json">

View File

@@ -0,0 +1,67 @@
#include "StageNavigationTask.h"
#include <regex>
#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;
}

View File

@@ -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;
};
}