mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-18 18:20:39 +08:00
合并master和infrast,修改匹配算法参数
This commit is contained in:
68
MeoAssistance/InfrastConfiger.cpp
Normal file
68
MeoAssistance/InfrastConfiger.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "InfrastConfiger.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <json.h>
|
||||
#include "Logger.hpp"
|
||||
|
||||
using namespace asst;
|
||||
|
||||
bool InfrastConfiger::load(const std::string& filename)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
DebugTrace("Configer::load | ", filename);
|
||||
|
||||
InfrastConfiger temp;
|
||||
if (temp._load(filename)) {
|
||||
*this = std::move(temp);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool InfrastConfiger::_load(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
return false;
|
||||
}
|
||||
std::stringstream iss;
|
||||
iss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
std::string content(iss.str());
|
||||
|
||||
auto&& ret = json::parser::parse(content);
|
||||
if (!ret) {
|
||||
DebugTrace("parse error", content);
|
||||
return false;
|
||||
}
|
||||
|
||||
json::value root = ret.value();
|
||||
try {
|
||||
// ÖÆÔìÕ¾
|
||||
for (json::value& comb_info : root["Manufacturing"]["combs"].as_array())
|
||||
{
|
||||
std::vector<std::string> comb_vec;
|
||||
for (json::value& oper_name : comb_info["comb"].as_array())
|
||||
{
|
||||
std::string oper_name_str = oper_name.as_string();
|
||||
m_mfg_opers.emplace(oper_name_str);
|
||||
comb_vec.emplace_back(std::move(oper_name_str));
|
||||
}
|
||||
m_mfg_combs.emplace_back(std::move(comb_vec));
|
||||
}
|
||||
m_mfg_end = root["Manufacturing"]["end"].as_string();
|
||||
|
||||
// óÒ×Õ¾ TODO¡¡
|
||||
}
|
||||
catch (json::exception& e) {
|
||||
DebugTraceError("Load config json error!", e.what());
|
||||
return false;
|
||||
}
|
||||
DebugTrace("Load config succeed");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -26,25 +26,28 @@
|
||||
<ClInclude Include="include\AsstPort.h" />
|
||||
<ClInclude Include="include\Configer.h" />
|
||||
<ClInclude Include="include\Identify.h" />
|
||||
<ClInclude Include="include\InfrastConfiger.h" />
|
||||
<ClInclude Include="include\Logger.hpp" />
|
||||
<ClInclude Include="include\OpenRecruitConfiger.h" />
|
||||
<ClInclude Include="include\RecruitConfiger.h" />
|
||||
<ClInclude Include="include\Task.h" />
|
||||
<ClInclude Include="include\Updater.h" />
|
||||
<ClInclude Include="include\Version.h" />
|
||||
<ClInclude Include="include\WinMacro.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="InfrastConfiger.cpp" />
|
||||
<ClCompile Include="src\Assistance.cpp" />
|
||||
<ClCompile Include="src\AsstCaller.cpp" />
|
||||
<ClCompile Include="src\Configer.cpp" />
|
||||
<ClCompile Include="src\Identify.cpp" />
|
||||
<ClCompile Include="src\OpenRecruitConfiger.cpp" />
|
||||
<ClCompile Include="src\RecruitConfiger.cpp" />
|
||||
<ClCompile Include="src\Task.cpp" />
|
||||
<ClCompile Include="src\Updater.cpp" />
|
||||
<ClCompile Include="src\WinMacro.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\resource\operInfo.json" />
|
||||
<None Include="..\resource\infrast.json" />
|
||||
<None Include="..\resource\recruit.json" />
|
||||
<None Include="..\resource\config.json" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
@@ -155,7 +158,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;CSHARP_API;MEO_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;MEO_DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
||||
@@ -196,7 +199,7 @@ xcopy /e /y /i $(SolutionDir)3rdPart\resource $(TargetDir)resource</Command>
|
||||
</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;CSHARP_API;MEO_DLL_EXPORTS;LOG_TRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;MEO_DLL_EXPORTS;LOG_TRACE;DEBUG_API;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
||||
|
||||
@@ -13,20 +13,23 @@
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件\configer">
|
||||
<UniqueIdentifier>{07a812fe-6b28-4be0-b6d4-33554824d3c5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="源文件\configer">
|
||||
<UniqueIdentifier>{74bd94e1-4973-412a-a17a-d8457de387af}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="头文件\type">
|
||||
<UniqueIdentifier>{87c9dee5-847b-41e6-818e-387a6385ea8b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\Configer.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Identify.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\WinMacro.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\AsstDef.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Assistance.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
@@ -36,32 +39,35 @@
|
||||
<ClInclude Include="include\Updater.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Logger.hpp">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\AsstAux.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\AsstPort.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\OpenRecruitConfiger.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Version.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Task.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\InfrastConfiger.h">
|
||||
<Filter>头文件\configer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\RecruitConfiger.h">
|
||||
<Filter>头文件\configer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Configer.h">
|
||||
<Filter>头文件\configer</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\AsstDef.h">
|
||||
<Filter>头文件\type</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\AsstAux.h">
|
||||
<Filter>头文件\type</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\AsstPort.h">
|
||||
<Filter>头文件\type</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Version.h">
|
||||
<Filter>头文件\type</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\Logger.hpp">
|
||||
<Filter>头文件\type</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Configer.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Identify.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\WinMacro.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
@@ -74,18 +80,30 @@
|
||||
<ClCompile Include="src\Updater.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\OpenRecruitConfiger.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Task.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InfrastConfiger.cpp">
|
||||
<Filter>源文件\configer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Identify.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\RecruitConfiger.cpp">
|
||||
<Filter>源文件\configer</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Configer.cpp">
|
||||
<Filter>源文件\configer</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\resource\config.json">
|
||||
<Filter>资源文件</Filter>
|
||||
</None>
|
||||
<None Include="..\resource\operInfo.json">
|
||||
<None Include="..\resource\recruit.json">
|
||||
<Filter>资源文件</Filter>
|
||||
</None>
|
||||
<None Include="..\resource\infrast.json">
|
||||
<Filter>资源文件</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -29,11 +29,14 @@ namespace asst {
|
||||
|
||||
// 开始刷理智
|
||||
bool start_sanity();
|
||||
// 开始访问基建
|
||||
// 开始访问好友基建
|
||||
bool start_visit();
|
||||
|
||||
// 开始公开招募操作
|
||||
bool start_open_recruit(const std::vector<int>& required_level, bool set_time = true);
|
||||
// 开始基建换班任务
|
||||
bool start_infrast();
|
||||
|
||||
// 开始匹配任务,调试用
|
||||
bool start_match_task(const std::string& task, int retry_times = ProcessTaskRetryTimesDefault, bool block = true);
|
||||
// 开始OCR测试,调试用
|
||||
@@ -43,6 +46,9 @@ namespace asst {
|
||||
|
||||
bool set_param(const std::string& type, const std::string& param, const std::string& value);
|
||||
|
||||
// 滑动操作,调试用
|
||||
bool swipe(const Point& p1, const Point& p2);
|
||||
|
||||
static constexpr int ProcessTaskRetryTimesDefault = 20;
|
||||
static constexpr int OpenRecruitTaskRetyrTimesDefault = 5;
|
||||
|
||||
|
||||
@@ -18,10 +18,12 @@ extern "C" {
|
||||
MEOAPI_PORT void AsstStop(asst::Assistance* p_asst);
|
||||
MEOAPI_PORT bool AsstSetParam(asst::Assistance* p_asst, const char* type, const char* param, const char* value);
|
||||
MEOAPI_PORT bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bool set_time);
|
||||
MEOAPI_PORT bool AsstStartInfrast(asst::Assistance* p_asst);
|
||||
MEOAPI_PORT bool AsstTestOcr(asst::Assistance* p_asst, const char** text_array, int array_size, bool need_click);
|
||||
|
||||
MEOAPI_PORT bool CheckVersionUpdate(char* tag_buffer, int tag_bufsize, char* html_url_buffer, int html_bufsize, char* body_buffer, int body_bufsize);
|
||||
|
||||
MEOAPI_PORT bool AsstTestSwipe(asst::Assistance* p_asst, int x1, int y1, int x2, int y2);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -103,6 +103,7 @@ namespace asst {
|
||||
std::string path;
|
||||
std::string connect;
|
||||
std::string click;
|
||||
std::string swipe;
|
||||
std::string display;
|
||||
std::string display_regex;
|
||||
int display_width = 0;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
#include "AsstDef.h"
|
||||
@@ -22,9 +21,6 @@ namespace asst {
|
||||
|
||||
bool set_param(const std::string& type, const std::string& param, const std::string& value);
|
||||
|
||||
Configer& operator=(const Configer& rhs) = default;
|
||||
Configer& operator=(Configer&& rhs) noexcept = default;
|
||||
|
||||
constexpr static int DefaultWindowWidth = 1280;
|
||||
constexpr static int DefaultWindowHeight = 720;
|
||||
constexpr static double Defaulttempl_threshold = 0.9;
|
||||
@@ -42,6 +38,9 @@ namespace asst {
|
||||
Configer(const Configer& rhs) = default;
|
||||
Configer(Configer&& rhs) noexcept = default;
|
||||
|
||||
Configer& operator=(const Configer& rhs) = default;
|
||||
Configer& operator=(Configer && rhs) noexcept = default;
|
||||
|
||||
bool _load(const std::string& filename);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace asst {
|
||||
std::tuple<AlgorithmType, double, asst::Rect> find_image(const cv::Mat& image, const std::string& templ, double templ_threshold);
|
||||
|
||||
// for debug
|
||||
void feature_matching(const cv::Mat& mat);
|
||||
std::vector<TextArea> feature_matching(const cv::Mat& mat);
|
||||
|
||||
void clear_cache();
|
||||
|
||||
|
||||
36
MeoAssistance/include/InfrastConfiger.h
Normal file
36
MeoAssistance/include/InfrastConfiger.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst {
|
||||
class InfrastConfiger
|
||||
{
|
||||
public:
|
||||
~InfrastConfiger() = default;
|
||||
|
||||
static InfrastConfiger& get_instance() {
|
||||
static InfrastConfiger unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
bool load(const std::string& filename);
|
||||
|
||||
std::vector<std::vector<std::string>> m_mfg_combs; // 制造站组合
|
||||
std::unordered_set<std::string> m_mfg_opers; // 制造站所有干员
|
||||
std::string m_mfg_end; // 识别到这个词,就认为干员遍历结束,一般用排序里最后的那个干员(?)
|
||||
|
||||
private:
|
||||
InfrastConfiger() = default;
|
||||
InfrastConfiger(const InfrastConfiger& rhs) = default;
|
||||
InfrastConfiger(InfrastConfiger&& rhs) noexcept = default;
|
||||
|
||||
InfrastConfiger& operator=(const InfrastConfiger& rhs) = default;
|
||||
InfrastConfiger& operator=(InfrastConfiger && rhs) noexcept = default;
|
||||
|
||||
bool _load(const std::string& filename);
|
||||
};
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst {
|
||||
class OpenRecruitConfiger
|
||||
{
|
||||
public:
|
||||
~OpenRecruitConfiger() = default;
|
||||
|
||||
static OpenRecruitConfiger& get_instance() {
|
||||
static OpenRecruitConfiger unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
bool load(const std::string& filename);
|
||||
|
||||
OpenRecruitConfiger& operator=(const OpenRecruitConfiger& rhs) = default;
|
||||
OpenRecruitConfiger& operator=(OpenRecruitConfiger&& rhs) noexcept = default;
|
||||
|
||||
std::unordered_set<std::string> m_all_tags;
|
||||
std::unordered_set<std::string> m_all_types;
|
||||
|
||||
std::vector<OperInfo> m_all_opers;
|
||||
|
||||
constexpr static int CorrectNumberOfTags = 5;
|
||||
|
||||
private:
|
||||
OpenRecruitConfiger() = default;
|
||||
OpenRecruitConfiger(const OpenRecruitConfiger& rhs) = default;
|
||||
OpenRecruitConfiger(OpenRecruitConfiger&& rhs) noexcept = default;
|
||||
|
||||
bool _load(const std::string& filename);
|
||||
};
|
||||
}
|
||||
39
MeoAssistance/include/RecruitConfiger.h
Normal file
39
MeoAssistance/include/RecruitConfiger.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace asst {
|
||||
class RecruitConfiger
|
||||
{
|
||||
public:
|
||||
~RecruitConfiger() = default;
|
||||
|
||||
static RecruitConfiger& get_instance() {
|
||||
static RecruitConfiger unique_instance;
|
||||
return unique_instance;
|
||||
}
|
||||
|
||||
bool load(const std::string& filename);
|
||||
|
||||
std::unordered_set<std::string> m_all_tags;
|
||||
std::unordered_set<std::string> m_all_types;
|
||||
|
||||
std::vector<OperInfo> m_all_opers;
|
||||
|
||||
constexpr static int CorrectNumberOfTags = 5;
|
||||
|
||||
private:
|
||||
RecruitConfiger() = default;
|
||||
RecruitConfiger(const RecruitConfiger& rhs) = default;
|
||||
RecruitConfiger(RecruitConfiger&& rhs) noexcept = default;
|
||||
|
||||
RecruitConfiger& operator=(const RecruitConfiger& rhs) = default;
|
||||
RecruitConfiger& operator=(RecruitConfiger && rhs) noexcept = default;
|
||||
|
||||
bool _load(const std::string& filename);
|
||||
};
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace asst {
|
||||
class WinMacro;
|
||||
class Identify;
|
||||
class Configer;
|
||||
class OpenRecruitConfiger;
|
||||
class RecruitConfiger;
|
||||
|
||||
enum TaskType {
|
||||
TaskTypeInvalid = 0,
|
||||
@@ -59,8 +59,25 @@ namespace asst {
|
||||
RecruitTagsDetected,
|
||||
OcrResultError,
|
||||
RecruitSpecialTag,
|
||||
RecruitResult
|
||||
RecruitResult,
|
||||
/* Infrast Msg*/
|
||||
InfrastOpers, // 识别到基建干员s
|
||||
InfrastComb // 当前设置的最优干员组合
|
||||
};
|
||||
|
||||
// 设施类型
|
||||
enum class FacilityType {
|
||||
Invalid,
|
||||
Manufacturing, // 制造站
|
||||
Trade, // 贸易站
|
||||
PowerStation, // 发电站
|
||||
ControlInterface, // 控制中枢
|
||||
ReceptionRoom, // 会客室
|
||||
Dormitory, // 宿舍
|
||||
Office // 办公室
|
||||
// 训练室和加工站用不上,不加了
|
||||
};
|
||||
|
||||
static std::ostream& operator<<(std::ostream& os, const AsstMsg& type)
|
||||
{
|
||||
static const std::unordered_map<AsstMsg, std::string> _type_name = {
|
||||
@@ -85,7 +102,10 @@ namespace asst {
|
||||
{AsstMsg::OcrResultError, "OcrResultError"},
|
||||
{AsstMsg::RecruitSpecialTag, "RecruitSpecialTag"},
|
||||
{AsstMsg::RecruitResult, "RecruitResult"},
|
||||
{AsstMsg::AppendTask, "AppendTask"}
|
||||
{AsstMsg::AppendTask, "AppendTask"},
|
||||
{AsstMsg::InfrastOpers, "InfrastOpers"},
|
||||
{AsstMsg::InfrastComb, "InfrastComb"}
|
||||
|
||||
};
|
||||
return os << _type_name.at(type);
|
||||
}
|
||||
@@ -121,7 +141,7 @@ namespace asst {
|
||||
protected:
|
||||
virtual cv::Mat get_format_image();
|
||||
virtual bool set_control_scale(int cur_width, int cur_height);
|
||||
virtual void sleep(unsigned millisecond);
|
||||
virtual bool sleep(unsigned millisecond);
|
||||
virtual bool print_window(const std::string& dir);
|
||||
|
||||
std::shared_ptr<WinMacro> m_window_ptr = nullptr;
|
||||
@@ -236,6 +256,33 @@ namespace asst {
|
||||
bool m_set_time = false;
|
||||
};
|
||||
|
||||
// 基建进驻任务
|
||||
class InfrastStationTask : public OcrAbstractTask
|
||||
{
|
||||
public:
|
||||
InfrastStationTask(AsstCallback callback, void* callback_arg);
|
||||
virtual ~InfrastStationTask() = default;
|
||||
|
||||
virtual bool run() override;
|
||||
void set_swipe_param(int delay, const Rect& begin_rect, const Rect& end_rect, int max_times = 20)
|
||||
{
|
||||
m_swipe_delay = delay;
|
||||
m_swipe_begin = begin_rect;
|
||||
m_swipe_end = end_rect;
|
||||
m_swipe_max_times = max_times;
|
||||
}
|
||||
void set_facility(FacilityType facility)
|
||||
{
|
||||
m_facility = facility;
|
||||
}
|
||||
private:
|
||||
FacilityType m_facility = FacilityType::Invalid;
|
||||
int m_swipe_delay = 0;
|
||||
Rect m_swipe_begin;
|
||||
Rect m_swipe_end;
|
||||
int m_swipe_max_times = 0;
|
||||
};
|
||||
|
||||
// for debug
|
||||
class TestOcrTask : public OcrAbstractTask
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace asst {
|
||||
bool hideWindow();
|
||||
bool click(const Point& p);
|
||||
bool click(const Rect& rect);
|
||||
bool swipe(const Point& p1, const Point& p2);
|
||||
bool swipe(const Rect& r1, const Rect& r2);
|
||||
void setControlScale(double scale);
|
||||
cv::Mat getImage(const Rect& rect);
|
||||
Rect getWindowRect();
|
||||
@@ -35,12 +37,14 @@ namespace asst {
|
||||
private:
|
||||
bool findHandle();
|
||||
std::optional<std::string> callCmd(const std::string& cmd, bool use_pipe = true);
|
||||
Point randPointInRect(const Rect& rect);
|
||||
|
||||
const EmulatorInfo m_emulator_info;
|
||||
const HandleType m_handle_type;
|
||||
HWND m_handle = NULL;
|
||||
bool m_is_adb = false;
|
||||
std::string m_click_cmd; // adb点击命令,不是adb的句柄用不到这个
|
||||
std::string m_swipe_cmd; // adb滑动命令,不是adb的句柄用不到这个
|
||||
std::minstd_rand m_rand_engine;
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#include "Logger.hpp"
|
||||
#include "AsstAux.h"
|
||||
#include "Task.h"
|
||||
#include "OpenRecruitConfiger.h"
|
||||
#include "RecruitConfiger.h"
|
||||
#include "InfrastConfiger.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
@@ -33,7 +34,12 @@ Assistance::Assistance(AsstCallback callback, void* callback_arg)
|
||||
callback_error();
|
||||
return;
|
||||
}
|
||||
ret = OpenRecruitConfiger::get_instance().load(GetResourceDir() + "operInfo.json");
|
||||
ret = RecruitConfiger::get_instance().load(GetResourceDir() + "recruit.json");
|
||||
if (!ret) {
|
||||
callback_error();
|
||||
return;
|
||||
}
|
||||
ret = InfrastConfiger::get_instance().load(GetResourceDir() + "infrast.json");
|
||||
if (!ret) {
|
||||
callback_error();
|
||||
return;
|
||||
@@ -62,6 +68,9 @@ Assistance::Assistance(AsstCallback callback, void* callback_arg)
|
||||
return;
|
||||
}
|
||||
|
||||
// for debug
|
||||
m_identify_ptr->add_text_image("森蚺", GetResourceDir() + "operators\\森蚺.png");
|
||||
|
||||
m_working_thread = std::thread(working_proc, this);
|
||||
m_msg_thread = std::thread(msg_proc, this);
|
||||
}
|
||||
@@ -214,6 +223,29 @@ bool Assistance::start_open_recruit(const std::vector<int>& required_level, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
bool asst::Assistance::start_infrast()
|
||||
{
|
||||
DebugTraceFunction;
|
||||
if (!m_thread_idle || !m_inited)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto task_ptr = std::make_shared<InfrastStationTask>(task_callback, (void*)this);
|
||||
// TODO 这个参数写到配置文件里
|
||||
task_ptr->set_swipe_param(2000, Rect(600, 300, 0, 0), Rect(450, 300, 0, 0), 20);
|
||||
task_ptr->set_facility(FacilityType::Manufacturing);
|
||||
task_ptr->set_task_chain("Infrast");
|
||||
m_tasks_queue.emplace(task_ptr);
|
||||
|
||||
m_thread_idle = false;
|
||||
m_condvar.notify_one();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Assistance::stop(bool block)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
@@ -240,6 +272,11 @@ bool Assistance::set_param(const std::string& type, const std::string& param, co
|
||||
return Configer::get_instance().set_param(type, param, value);
|
||||
}
|
||||
|
||||
bool asst::Assistance::swipe(const Point& p1, const Point& p2)
|
||||
{
|
||||
return m_control_ptr->swipe(p1, p2);
|
||||
}
|
||||
|
||||
void Assistance::working_proc(Assistance* p_this)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
|
||||
@@ -112,6 +112,15 @@ bool AsstRunOpenRecruit(asst::Assistance* p_asst, const int required_level[], bo
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AsstStartInfrast(asst::Assistance* p_asst)
|
||||
{
|
||||
if (p_asst == NULL) {
|
||||
return false;
|
||||
}
|
||||
p_asst->start_infrast();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AsstTestOcr(asst::Assistance* p_asst, const char** text_array, int array_size, bool need_click)
|
||||
{
|
||||
if (p_asst == NULL || text_array == nullptr) {
|
||||
@@ -140,4 +149,12 @@ bool CheckVersionUpdate(char* tag_buffer, int tag_bufsize, char* html_url_buffer
|
||||
strcpy_s(html_url_buffer, html_bufsize, info.html_url.c_str());
|
||||
strcpy_s(body_buffer, body_bufsize, info.body.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool AsstTestSwipe(asst::Assistance* p_asst, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
if (p_asst == NULL) {
|
||||
return false;
|
||||
}
|
||||
return p_asst->swipe({ x1, y1 }, { x2, y2 });
|
||||
}
|
||||
|
||||
@@ -250,10 +250,10 @@ bool asst::Configer::_load(const std::string& filename)
|
||||
}
|
||||
if (emulator_json.exist("adb")) {
|
||||
emulator_info.is_adb = true;
|
||||
std::cout << emulator_json.to_string() << std::endl;
|
||||
emulator_info.adb.path = emulator_json["adb"]["path"].as_string();
|
||||
emulator_info.adb.connect = emulator_json["adb"]["connect"].as_string();
|
||||
emulator_info.adb.click = emulator_json["adb"]["click"].as_string();
|
||||
emulator_info.adb.swipe = emulator_json["adb"]["swipe"].as_string();
|
||||
emulator_info.adb.display = emulator_json["adb"]["display"].as_string();
|
||||
emulator_info.adb.display_regex = emulator_json["adb"]["displayRegex"].as_string();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Logger.hpp"
|
||||
#include "AsstAux.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace asst;
|
||||
using namespace cv;
|
||||
using namespace cv::xfeatures2d;
|
||||
@@ -80,7 +82,7 @@ std::pair<std::vector<cv::KeyPoint>, cv::Mat> asst::Identify::surf_detect(const
|
||||
cv::Mat mat_gray;
|
||||
cv::cvtColor(mat, mat_gray, cv::COLOR_RGB2GRAY);
|
||||
|
||||
constexpr int min_hessian = 800;
|
||||
constexpr int min_hessian = 1000;
|
||||
// SURF特征点检测
|
||||
cv::Ptr<SURF> detector = SURF::create(min_hessian);
|
||||
std::vector<KeyPoint> keypoints;
|
||||
@@ -156,17 +158,64 @@ std::tuple<AlgorithmType, double, asst::Rect> Identify::find_image(const Mat& cu
|
||||
}
|
||||
}
|
||||
|
||||
void asst::Identify::feature_matching(const cv::Mat& mat)
|
||||
std::vector<TextArea> asst::Identify::feature_matching(const cv::Mat& mat)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
auto && [income_keypoints, income_mat_vector] = surf_detect(mat);
|
||||
|
||||
static FlannBasedMatcher matcher;
|
||||
|
||||
std::vector<TextArea> matched_text_area;
|
||||
for (auto&& [key, feature] : m_feature_map) {
|
||||
auto&& [keypoints, mat_vector] = feature;
|
||||
std::vector<cv::DMatch> matches;
|
||||
matcher.match(mat_vector, income_mat_vector, matches);
|
||||
|
||||
// 最大的距离
|
||||
auto max_iter = std::max_element(matches.cbegin(), matches.cend(),
|
||||
[](const cv::DMatch& lhs, const cv::DMatch& rhs) ->bool{
|
||||
return lhs.distance < rhs.distance;
|
||||
}); // 描述符欧式距离(knn)
|
||||
if (max_iter == matches.cend()) {
|
||||
continue;
|
||||
}
|
||||
float maxdist = max_iter->distance;
|
||||
|
||||
// 最小的距离
|
||||
auto min_iter = std::min_element(matches.cbegin(), matches.cend(),
|
||||
[](const cv::DMatch& lhs, const cv::DMatch& rhs) ->bool {
|
||||
return lhs.distance < rhs.distance;
|
||||
}); // 描述符欧式距离(knn)
|
||||
if (min_iter == matches.cend()) {
|
||||
continue;
|
||||
}
|
||||
float mindist = min_iter->distance;
|
||||
|
||||
std::vector<cv::DMatch> good_matches;
|
||||
constexpr static const double MatchRatio = 0.6;
|
||||
for (const cv::DMatch dmatch : matches) {
|
||||
if (dmatch.distance < maxdist * MatchRatio) {
|
||||
good_matches.emplace_back(dmatch);
|
||||
}
|
||||
}
|
||||
// TODO,把这个阈值写到配置文件里
|
||||
constexpr static const int MatchSizeThreshold = 10;
|
||||
if (good_matches.size() >= MatchSizeThreshold) {
|
||||
TextArea textarea;
|
||||
textarea.text = key;
|
||||
// TODO
|
||||
//textarea.rect = ;
|
||||
matched_text_area.emplace_back(std::move(textarea));
|
||||
}
|
||||
|
||||
// for debug
|
||||
cv::Mat text_mat = cv::imread(GetResourceDir() + "operators\\森蚺.png");
|
||||
cv::Mat draw_mat;
|
||||
cv::drawMatches(text_mat, keypoints, mat, income_keypoints, good_matches, draw_mat);
|
||||
cv::imshow("output", draw_mat);
|
||||
cv::waitKey(0);
|
||||
}
|
||||
return matched_text_area;
|
||||
}
|
||||
|
||||
void Identify::clear_cache()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "OpenRecruitConfiger.h"
|
||||
#include "RecruitConfiger.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@@ -9,12 +9,12 @@
|
||||
|
||||
using namespace asst;
|
||||
|
||||
bool OpenRecruitConfiger::load(const std::string& filename)
|
||||
bool RecruitConfiger::load(const std::string& filename)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
DebugTrace("OpenRecruitConfiger::load | ", filename);
|
||||
DebugTrace("RecruitConfiger::load | ", filename);
|
||||
|
||||
OpenRecruitConfiger temp;
|
||||
RecruitConfiger temp;
|
||||
if (temp._load(filename)) {
|
||||
// 按干员等级排个序
|
||||
std::sort(temp.m_all_opers.begin(), temp.m_all_opers.end(), [](
|
||||
@@ -31,7 +31,7 @@ bool OpenRecruitConfiger::load(const std::string& filename)
|
||||
}
|
||||
}
|
||||
|
||||
bool asst::OpenRecruitConfiger::_load(const std::string& filename)
|
||||
bool asst::RecruitConfiger::_load(const std::string& filename)
|
||||
{
|
||||
std::ifstream ifs(filename, std::ios::in);
|
||||
if (!ifs.is_open()) {
|
||||
@@ -3,7 +3,8 @@
|
||||
#include "WinMacro.h"
|
||||
#include "Identify.h"
|
||||
#include "Configer.h"
|
||||
#include "OpenRecruitConfiger.h"
|
||||
#include "RecruitConfiger.h"
|
||||
#include "InfrastConfiger.h"
|
||||
#include <json.h>
|
||||
#include "AsstAux.h"
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <filesystem>
|
||||
#include <future>
|
||||
|
||||
using namespace asst;
|
||||
|
||||
@@ -80,10 +82,10 @@ bool AbstractTask::set_control_scale(int cur_width, int cur_height)
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbstractTask::sleep(unsigned millisecond)
|
||||
bool AbstractTask::sleep(unsigned millisecond)
|
||||
{
|
||||
if (millisecond == 0) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
auto start = std::chrono::system_clock::now();
|
||||
unsigned duration = 0;
|
||||
@@ -99,6 +101,8 @@ void AbstractTask::sleep(unsigned millisecond)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
m_callback(AsstMsg::EndOfSleep, callback_json, m_callback_arg);
|
||||
|
||||
return (m_exit_flag == NULL || *m_exit_flag == false);
|
||||
}
|
||||
|
||||
bool AbstractTask::print_window(const std::string& dir)
|
||||
@@ -180,7 +184,10 @@ bool ProcessTask::run()
|
||||
}
|
||||
|
||||
// 前置固定延时
|
||||
sleep(task_info_ptr->pre_delay);
|
||||
if (!sleep(task_info_ptr->pre_delay))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool need_stop = false;
|
||||
switch (task_info_ptr->type) {
|
||||
@@ -198,7 +205,10 @@ bool ProcessTask::run()
|
||||
break;
|
||||
case ProcessTaskType::PrintWindow:
|
||||
{
|
||||
sleep(Configer::get_instance().m_options.print_window_delay);
|
||||
if (!sleep(Configer::get_instance().m_options.print_window_delay))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static const std::string dirname = GetCurrentDir() + "screenshot\\";
|
||||
print_window(dirname);
|
||||
}
|
||||
@@ -224,7 +234,9 @@ bool ProcessTask::run()
|
||||
m_callback(AsstMsg::TaskCompleted, callback_json, m_callback_arg);
|
||||
|
||||
// 后置固定延时
|
||||
sleep(task_info_ptr->rear_delay);
|
||||
if (!sleep(task_info_ptr->rear_delay)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
json::value next_json = callback_json;
|
||||
next_json["task_chain"] = m_task_chain;
|
||||
@@ -367,7 +379,9 @@ void ProcessTask::exec_click_task(const Rect& matched_rect)
|
||||
Configer::get_instance().m_options.control_delay_upper);
|
||||
|
||||
unsigned rand_delay = rand_uni(rand_engine);
|
||||
sleep(rand_delay);
|
||||
if (!sleep(rand_delay)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_control_ptr->click(matched_rect);
|
||||
@@ -428,7 +442,7 @@ bool OpenRecruitTask::run()
|
||||
|
||||
/* Filter out all tags from all text */
|
||||
std::vector<TextArea> all_tags = text_match(
|
||||
all_text_area, OpenRecruitConfiger::get_instance().m_all_tags, Configer::get_instance().m_recruit_ocr_replace);
|
||||
all_text_area, RecruitConfiger::get_instance().m_all_tags, Configer::get_instance().m_recruit_ocr_replace);
|
||||
|
||||
std::unordered_set<std::string> all_tags_name;
|
||||
std::vector<json::value> all_tags_json_vector;
|
||||
@@ -441,7 +455,7 @@ bool OpenRecruitTask::run()
|
||||
m_callback(AsstMsg::RecruitTagsDetected, all_tags_json, m_callback_arg);
|
||||
|
||||
/* 过滤tags数量不足的情况(可能是识别漏了) */
|
||||
if (all_tags.size() != OpenRecruitConfiger::CorrectNumberOfTags) {
|
||||
if (all_tags.size() != RecruitConfiger::CorrectNumberOfTags) {
|
||||
all_tags_json["type"] = "OpenRecruit";
|
||||
m_callback(AsstMsg::OcrResultError, all_tags_json, m_callback_arg);
|
||||
return false;
|
||||
@@ -488,7 +502,7 @@ bool OpenRecruitTask::run()
|
||||
// 例如 key: { "狙击"、"群攻" },value: OperCombs.opers{ "陨星", "白雪", "空爆" }
|
||||
std::map<std::vector<std::string>, OperCombs> result_map;
|
||||
for (const std::vector<std::string>& comb : all_combs) {
|
||||
for (const OperInfo& cur_oper : OpenRecruitConfiger::get_instance().m_all_opers) {
|
||||
for (const OperInfo& cur_oper : RecruitConfiger::get_instance().m_all_opers) {
|
||||
int matched_count = 0;
|
||||
for (const std::string& tag : comb) {
|
||||
if (cur_oper.tags.find(tag) != cur_oper.tags.cend()) {
|
||||
@@ -659,39 +673,268 @@ bool TestOcrTask::run()
|
||||
};
|
||||
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
|
||||
|
||||
/* Find all text */
|
||||
std::vector<TextArea> all_text_area = ocr_detect();
|
||||
auto swipe_foo = [&](bool reverse = false) -> bool {
|
||||
const Point p1(600, 300);
|
||||
const Point p2(450, 300);
|
||||
bool ret = false;
|
||||
if (!reverse) {
|
||||
ret = m_control_ptr->swipe(p1, p2);
|
||||
}
|
||||
else {
|
||||
ret = m_control_ptr->swipe(p2, p1);
|
||||
}
|
||||
ret &= sleep(3000);
|
||||
return ret;
|
||||
};
|
||||
|
||||
std::vector<json::value> all_text_json_vector;
|
||||
for (const TextArea& text_area : all_text_area) {
|
||||
all_text_json_vector.emplace_back(Utf8ToGbk(text_area.text));
|
||||
}
|
||||
json::value all_text_json;
|
||||
all_text_json["text"] = json::array(all_text_json_vector);
|
||||
m_callback(AsstMsg::TextDetected, all_text_json, m_callback_arg);
|
||||
// 识别到的干员名
|
||||
std::unordered_set<std::string> all_names;
|
||||
|
||||
/* Filter out all text from all text */
|
||||
std::vector<TextArea> all_text = text_search(
|
||||
all_text_area, m_text_vec, Configer::get_instance().m_infrast_ocr_replace);
|
||||
std::vector<json::value> all_tags_json_vector;
|
||||
for (const TextArea& text_area : all_text) {
|
||||
all_tags_json_vector.emplace_back(Utf8ToGbk(text_area.text));
|
||||
}
|
||||
json::value all_tags_json;
|
||||
all_tags_json["tags"] = json::array(all_tags_json_vector);
|
||||
m_callback(AsstMsg::RecruitTagsDetected, all_tags_json, m_callback_arg);
|
||||
// 一边识别一边滑动,把所有制造站干员名字抓出来
|
||||
for (int i = 0; i != 20; ++i) {
|
||||
const cv::Mat& image = get_format_image();
|
||||
// 异步进行滑动操作
|
||||
std::future<bool> swipe_future = std::async(std::launch::async, swipe_foo);
|
||||
|
||||
// 点击识别到的文字,直接回调扔出去,交给外层做
|
||||
if (m_need_click) {
|
||||
for (const TextArea& text_area : all_text) {
|
||||
json::value task_json;
|
||||
task_json["type"] = "ClickTask";
|
||||
task_json["rect"] = json::array({ text_area.rect.x, text_area.rect.y, text_area.rect.width, text_area.rect.height });
|
||||
task_json["retry_times"] = m_retry_times;
|
||||
task_json["task_chain"] = m_task_chain;
|
||||
m_callback(AsstMsg::AppendTask, task_json, m_callback_arg);
|
||||
std::vector<TextArea> all_text_area = ocr_detect(image);
|
||||
/* 过滤出所有制造站中的干员名 */
|
||||
std::vector<TextArea> cur_names = text_search(
|
||||
all_text_area,
|
||||
InfrastConfiger::get_instance().m_mfg_opers,
|
||||
Configer::get_instance().m_infrast_ocr_replace);
|
||||
|
||||
for (TextArea& text_area : cur_names) {
|
||||
all_names.emplace(std::move(text_area.text));
|
||||
}
|
||||
bool break_flag = false;
|
||||
// 识别到了结束标记,就直接退出循环
|
||||
if (all_names.find(InfrastConfiger::get_instance().m_mfg_end) != all_names.cend()) {
|
||||
break_flag = true;
|
||||
}
|
||||
// 阻塞等待滑动结束
|
||||
if (!swipe_future.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (break_flag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "识别到制造站干员:" << std::endl;
|
||||
for (const std::string& name : all_names) {
|
||||
std::cout << Utf8ToGbk(name) << std::endl;
|
||||
}
|
||||
|
||||
// 配置文件中的干员组合,和抓出来的干员名比对,如果组合中的干员都有,那就用这个组合
|
||||
// Todo 时间复杂度起飞了,需要优化下
|
||||
std::vector<std::string> optimal_comb;
|
||||
for (auto&& name_vec : InfrastConfiger::get_instance().m_mfg_combs) {
|
||||
int count = 0;
|
||||
for (std::string& name : name_vec) {
|
||||
if (all_names.find(name) != all_names.cend()) {
|
||||
++count;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count == name_vec.size()) {
|
||||
optimal_comb = name_vec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "最优组合:" << std::endl;
|
||||
for (const std::string& name : optimal_comb) {
|
||||
std::cout << Utf8ToGbk(name) << std::endl;
|
||||
}
|
||||
|
||||
// 一边滑动一边点击最优解中的干员
|
||||
for (int i = 0; i != 20; ++i) {
|
||||
const cv::Mat& image = get_format_image();
|
||||
std::vector<TextArea> all_text_area = ocr_detect(image);
|
||||
/* 过滤出所有制造站中的干员名 */
|
||||
std::vector<TextArea> cur_names = text_search(
|
||||
all_text_area,
|
||||
optimal_comb,
|
||||
Configer::get_instance().m_infrast_ocr_replace);
|
||||
|
||||
for (TextArea& text_area : cur_names) {
|
||||
m_control_ptr->click(text_area.rect);
|
||||
// 点过了就不会再点了,直接从最优解vector里面删了
|
||||
auto iter = std::find(optimal_comb.begin(), optimal_comb.end(), text_area.text);
|
||||
if (iter != optimal_comb.end()) {
|
||||
optimal_comb.erase(iter);
|
||||
}
|
||||
}
|
||||
if (optimal_comb.empty()) {
|
||||
break;
|
||||
}
|
||||
// 因为滑动和点击是矛盾的,这里没法异步做
|
||||
if (!swipe_foo(true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// 点击识别到的文字,直接回调扔出去,交给外层做
|
||||
//if (m_need_click) {
|
||||
// for (const TextArea& text_area : all_text) {
|
||||
// json::value task_json;
|
||||
// task_json["type"] = "ClickTask";
|
||||
// task_json["rect"] = json::array({ text_area.rect.x, text_area.rect.y, text_area.rect.width, text_area.rect.height });
|
||||
// task_json["retry_times"] = m_retry_times;
|
||||
// task_json["task_chain"] = m_task_chain;
|
||||
// m_callback(AsstMsg::AppendTask, task_json, m_callback_arg);
|
||||
// }
|
||||
//}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
asst::InfrastStationTask::InfrastStationTask(AsstCallback callback, void* callback_arg)
|
||||
: OcrAbstractTask(callback, callback_arg)
|
||||
{
|
||||
}
|
||||
|
||||
bool asst::InfrastStationTask::run()
|
||||
{
|
||||
if (m_view_ptr == NULL
|
||||
|| m_identify_ptr == NULL)
|
||||
{
|
||||
m_callback(AsstMsg::PtrIsNull, json::value(), m_callback_arg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// for debug
|
||||
const cv::Mat& debug_image = get_format_image();
|
||||
m_identify_ptr->feature_matching(debug_image);
|
||||
|
||||
std::vector<std::vector<std::string>> all_oper_combs; // 所有的干员组合
|
||||
std::unordered_set<std::string> all_oper_name; // 所有干员名
|
||||
std::string oper_end_flag; // 干员名结束标记,识别到这个string就认为识别完成了
|
||||
|
||||
switch (m_facility) {
|
||||
case FacilityType::Manufacturing:
|
||||
all_oper_combs = InfrastConfiger::get_instance().m_mfg_combs;
|
||||
all_oper_name = InfrastConfiger::get_instance().m_mfg_opers;
|
||||
oper_end_flag = InfrastConfiger::get_instance().m_mfg_end;
|
||||
break;
|
||||
// TODO 贸易站和其他啥的,有空再做
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
json::value task_start_json = json::object{
|
||||
{ "task_type", "InfrastStationTask" },
|
||||
{ "task_chain", m_task_chain},
|
||||
};
|
||||
m_callback(AsstMsg::TaskStart, task_start_json, m_callback_arg);
|
||||
|
||||
auto swipe_foo = [&](bool reverse = false) -> bool {
|
||||
bool ret = false;
|
||||
if (!reverse) {
|
||||
ret = m_control_ptr->swipe(m_swipe_begin, m_swipe_end);
|
||||
}
|
||||
else {
|
||||
ret = m_control_ptr->swipe(m_swipe_end, m_swipe_begin);
|
||||
}
|
||||
ret &= sleep(m_swipe_delay);
|
||||
return ret;
|
||||
};
|
||||
|
||||
// 识别到的干员名
|
||||
std::unordered_set<std::string> detected_names;
|
||||
|
||||
// 一边识别一边滑动,把所有制造站干员名字抓出来
|
||||
for (int i = 0; i != m_swipe_max_times; ++i) {
|
||||
const cv::Mat& image = get_format_image();
|
||||
// 异步进行滑动操作
|
||||
std::future<bool> swipe_future = std::async(std::launch::async, swipe_foo);
|
||||
|
||||
std::vector<TextArea> all_text_area = ocr_detect(image);
|
||||
/* 过滤出所有制造站中的干员名 */
|
||||
std::vector<TextArea> cur_names = text_search(
|
||||
all_text_area,
|
||||
all_oper_name,
|
||||
Configer::get_instance().m_infrast_ocr_replace);
|
||||
|
||||
for (TextArea& text_area : cur_names) {
|
||||
detected_names.emplace(std::move(text_area.text));
|
||||
}
|
||||
bool break_flag = false;
|
||||
// 识别到了结束标记,就直接退出循环
|
||||
if (detected_names.find(oper_end_flag) != detected_names.cend()) {
|
||||
break_flag = true;
|
||||
}
|
||||
// 阻塞等待滑动结束
|
||||
if (!swipe_future.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (break_flag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
json::value opers_json;
|
||||
std::vector<json::value> all_names_vector;
|
||||
for (const std::string& name : detected_names) {
|
||||
all_names_vector.emplace_back(Utf8ToGbk(name));
|
||||
}
|
||||
opers_json["names"] = json::array(all_names_vector);
|
||||
|
||||
m_callback(AsstMsg::InfrastOpers, opers_json, m_callback_arg);
|
||||
|
||||
// 配置文件中的干员组合,和抓出来的干员名比对,如果组合中的干员都有,那就用这个组合
|
||||
// Todo 时间复杂度起飞了,需要优化下
|
||||
std::vector<std::string> optimal_comb;
|
||||
for (auto&& name_vec :all_oper_combs) {
|
||||
int count = 0;
|
||||
for (std::string& name : name_vec) {
|
||||
if (detected_names.find(name) != detected_names.cend()) {
|
||||
++count;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count == name_vec.size()) {
|
||||
optimal_comb = name_vec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
opers_json["comb"] = json::array(optimal_comb);
|
||||
m_callback(AsstMsg::InfrastComb, opers_json, m_callback_arg);
|
||||
|
||||
|
||||
// 一边滑动一边点击最优解中的干员
|
||||
for (int i = 0; i != m_swipe_max_times; ++i) {
|
||||
const cv::Mat& image = get_format_image();
|
||||
std::vector<TextArea> all_text_area = ocr_detect(image);
|
||||
/* 过滤出所有制造站中的干员名 */
|
||||
std::vector<TextArea> cur_names = text_search(
|
||||
all_text_area,
|
||||
optimal_comb,
|
||||
Configer::get_instance().m_infrast_ocr_replace);
|
||||
|
||||
for (TextArea& text_area : cur_names) {
|
||||
m_control_ptr->click(text_area.rect);
|
||||
// 点过了就不会再点了,直接从最优解vector里面删了
|
||||
auto iter = std::find(optimal_comb.begin(), optimal_comb.end(), text_area.text);
|
||||
if (iter != optimal_comb.end()) {
|
||||
optimal_comb.erase(iter);
|
||||
}
|
||||
}
|
||||
if (optimal_comb.empty()) {
|
||||
break;
|
||||
}
|
||||
// 因为滑动和点击是矛盾的,这里没法异步做
|
||||
if (!swipe_foo(true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ bool WinMacro::findHandle()
|
||||
}
|
||||
|
||||
m_click_cmd = adb_dir + m_emulator_info.adb.click;
|
||||
m_swipe_cmd = adb_dir + m_emulator_info.adb.swipe;
|
||||
}
|
||||
DebugTrace("Handle:", m_handle, "Name:", m_emulator_info.name, "Type:", m_handle_type);
|
||||
|
||||
@@ -190,6 +191,29 @@ std::optional<std::string> asst::WinMacro::callCmd(const std::string& cmd, bool
|
||||
return pipe_str;
|
||||
}
|
||||
|
||||
Point asst::WinMacro::randPointInRect(const Rect& rect)
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
if (rect.width == 0) {
|
||||
x = rect.x;
|
||||
}
|
||||
else {
|
||||
int x_rand = std::poisson_distribution<int>(rect.width / 2)(m_rand_engine);
|
||||
|
||||
x = x_rand + rect.x;
|
||||
}
|
||||
|
||||
if (rect.height == 0) {
|
||||
y = rect.y;
|
||||
}
|
||||
else {
|
||||
int y_rand = std::poisson_distribution<int>(rect.height / 2)(m_rand_engine);
|
||||
y = y_rand + rect.y;
|
||||
}
|
||||
|
||||
return Point(x, y);
|
||||
}
|
||||
|
||||
bool WinMacro::resizeWindow(int width, int height)
|
||||
{
|
||||
if (m_handle_type != HandleType::Window || !::IsWindow(m_handle)) {
|
||||
@@ -289,25 +313,41 @@ bool WinMacro::click(const Rect& rect)
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = 0, y = 0;
|
||||
if (rect.width == 0) {
|
||||
x = rect.x;
|
||||
}
|
||||
else {
|
||||
int x_rand = std::poisson_distribution<int>(rect.width / 2)(m_rand_engine);
|
||||
return click(randPointInRect(rect));
|
||||
}
|
||||
|
||||
x = x_rand + rect.x;
|
||||
bool asst::WinMacro::swipe(const Point& p1, const Point& p2)
|
||||
{
|
||||
if (m_handle_type != HandleType::Control || !::IsWindow(m_handle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rect.height == 0) {
|
||||
y = rect.y;
|
||||
int x1 = p1.x * m_control_scale;
|
||||
int y1 = p1.y * m_control_scale;
|
||||
int x2 = p2.x * m_control_scale;
|
||||
int y2 = p2.y * m_control_scale;
|
||||
DebugTrace("Swipe, raw:", p1.x, p1.y, p2.x, p2.y, "corr:", x1, y1, x2, y2);
|
||||
|
||||
if (m_is_adb) {
|
||||
std::string cur_cmd = StringReplaceAll(m_swipe_cmd, "[x1]", std::to_string(x1));
|
||||
cur_cmd = StringReplaceAll(cur_cmd, "[y1]", std::to_string(y1));
|
||||
cur_cmd = StringReplaceAll(cur_cmd, "[x2]", std::to_string(x2));
|
||||
cur_cmd = StringReplaceAll(cur_cmd, "[y2]", std::to_string(y2));
|
||||
return callCmd(cur_cmd, false).has_value();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
int y_rand = std::poisson_distribution<int>(rect.height / 2)(m_rand_engine);
|
||||
y = y_rand + rect.y;
|
||||
else { // TODO
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool asst::WinMacro::swipe(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
if (m_handle_type != HandleType::Control || !::IsWindow(m_handle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return click({ x, y });
|
||||
return swipe(randPointInRect(r1), randPointInRect(r2));
|
||||
}
|
||||
|
||||
void asst::WinMacro::setControlScale(double scale)
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir)meojson\include;$(SolutionDir)MeoAssistance\include;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(SolutionDir)MeoAssistance\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(TargetDir);$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#include "AsstCaller.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace asst;
|
||||
|
||||
void test_dorm(Assistance* ptr);
|
||||
void test_swipe(Assistance* ptr);
|
||||
void test_infrast(Assistance* ptr);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using namespace asst;
|
||||
|
||||
Assistance* ptr = AsstCreate();
|
||||
auto ret = AsstCatchEmulator(ptr);
|
||||
@@ -15,11 +20,13 @@ int main(int argc, char** argv)
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
const char* text_array[] = { "×¢ÒâÁ¦" };
|
||||
|
||||
char ch = 0;
|
||||
while (ch != 'q') {
|
||||
AsstTestOcr(ptr, text_array, sizeof(text_array) / sizeof(char*), true);
|
||||
|
||||
test_infrast(ptr);
|
||||
//test_swipe(ptr);
|
||||
|
||||
ch = getchar();
|
||||
}
|
||||
|
||||
@@ -29,4 +36,21 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_swipe(Assistance* ptr)
|
||||
{
|
||||
AsstTestSwipe(ptr, 1000, 300, 500, 300);
|
||||
}
|
||||
|
||||
void test_dorm(Assistance* ptr)
|
||||
{
|
||||
const char* text_array[] = { "×¢ÒâÁ¦" };
|
||||
|
||||
AsstTestOcr(ptr, text_array, sizeof(text_array) / sizeof(char*), true);
|
||||
}
|
||||
|
||||
void test_infrast(Assistance* ptr)
|
||||
{
|
||||
AsstStartInfrast(ptr);
|
||||
}
|
||||
@@ -30,6 +30,9 @@
|
||||
[ "都任", "输出" ]
|
||||
],
|
||||
"infrastOcrReplace": [
|
||||
[ "森蛐", "森蚺" ],
|
||||
[ "森蛾", "森蚺" ],
|
||||
[ "森躺", "森蚺" ]
|
||||
],
|
||||
"handle_Doc": "下面的和模拟器窗口捕获逻辑有关,不需要修改",
|
||||
"handle": {
|
||||
@@ -60,115 +63,19 @@
|
||||
"window": "BlueStacks Android PluginAndroid"
|
||||
}
|
||||
],
|
||||
"adb": {
|
||||
"path": "[EmulatorPath]HD-Adb.exe",
|
||||
"connect": " connect 127.0.0.1:5555",
|
||||
"click": " -s 127.0.0.1:5555 shell input tap [x] [y]",
|
||||
"swipe": " -s 127.0.0.1:5555 shell input swipe [x1] [y1] [x2] [y2]",
|
||||
"display": " -s 127.0.0.1:5555 shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"displayRegex": "cur=%dx%d"
|
||||
},
|
||||
"xOffset": 11,
|
||||
"yOffset": 46,
|
||||
"rightOffset": 11,
|
||||
"bottomOffset": 10
|
||||
},
|
||||
"Nox": {
|
||||
"window": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
}
|
||||
],
|
||||
"view": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
}
|
||||
],
|
||||
"control": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
}
|
||||
],
|
||||
"xOffset": 2,
|
||||
"yOffset": 39,
|
||||
"rightOffset": 39,
|
||||
"bottomOffset": 9
|
||||
},
|
||||
"LDPlayer": {
|
||||
"window": [
|
||||
{
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
}
|
||||
],
|
||||
"view": [
|
||||
{
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
}
|
||||
],
|
||||
"control": [
|
||||
{
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
},
|
||||
{
|
||||
"class": "RenderWindow",
|
||||
"window": "TheRender"
|
||||
}
|
||||
],
|
||||
"xOffset": 0,
|
||||
"yOffset": 35
|
||||
},
|
||||
"XYAZ": {
|
||||
"window": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "逍遥模拟器"
|
||||
}
|
||||
],
|
||||
"view": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "逍遥模拟器"
|
||||
}
|
||||
],
|
||||
"control": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "逍遥模拟器"
|
||||
},
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "MainWindowWindow"
|
||||
}
|
||||
],
|
||||
"xOffset": 1,
|
||||
"yOffset": 48,
|
||||
"rightOffset": 1,
|
||||
"bottomOffset": 1
|
||||
},
|
||||
"Tencent": {
|
||||
"window": [
|
||||
{
|
||||
"class": "TXGuiFoundation",
|
||||
"window": "腾讯手游助手"
|
||||
}
|
||||
],
|
||||
"view": [
|
||||
{
|
||||
"class": "TXGuiFoundation",
|
||||
"window": "腾讯手游助手"
|
||||
}
|
||||
],
|
||||
"control": [
|
||||
{
|
||||
"class": "TXGuiFoundation",
|
||||
"window": "腾讯手游助手"
|
||||
},
|
||||
{
|
||||
"class": "AEngineRenderWindowClass",
|
||||
"window": "AEngineRenderWindow"
|
||||
}
|
||||
],
|
||||
"xOffset": 1,
|
||||
"yOffset": 42
|
||||
},
|
||||
"MuMuEmulator": {
|
||||
"window": [
|
||||
{
|
||||
@@ -191,8 +98,9 @@
|
||||
"adb": {
|
||||
"path": "[EmulatorPath]..\\\\vmonitor\\\\bin\\\\adb_server.exe",
|
||||
"connect": " connect 127.0.0.1:7555",
|
||||
"click": " shell input tap [x] [y]",
|
||||
"display": " shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"click": " -s 127.0.0.1:7555 shell input tap [x] [y]",
|
||||
"swipe": " -s 127.0.0.1:7555 shell input swipe [x1] [y1] [x2] [y2]",
|
||||
"display": " -s 127.0.0.1:7555 shell dumpsys window displays | grep init= | awk ' { print $3 } '",
|
||||
"displayRegex": "cur=%dx%d"
|
||||
},
|
||||
"xOffset": 0,
|
||||
|
||||
34
resource/infrast.json
Normal file
34
resource/infrast.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"Manufacturing": {
|
||||
"Doc": "制造站",
|
||||
"combs": [
|
||||
{
|
||||
"comb": [
|
||||
"刻俄柏",
|
||||
"稀音",
|
||||
"红云"
|
||||
],
|
||||
"efficiency": 105
|
||||
},
|
||||
{
|
||||
"comb": [
|
||||
"温蒂",
|
||||
"异客",
|
||||
"森蚺"
|
||||
],
|
||||
"efficiency": 90
|
||||
},
|
||||
{
|
||||
"comb": [
|
||||
"月见夜"
|
||||
],
|
||||
"efficiency": 10
|
||||
}
|
||||
],
|
||||
"end": "月见夜",
|
||||
"end_Doc": "识别到这个词,就认为干员遍历结束,一般用排序里最后的那个干员(?)"
|
||||
},
|
||||
"Trade": {
|
||||
"Doc": "贸易站"
|
||||
}
|
||||
}
|
||||
3
resource/operators/screen.bat
Normal file
3
resource/operators/screen.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
adb connect 127.0.0.1:5555
|
||||
adb -s 127.0.0.1:5555 shell screencap /sdcard/screen.png
|
||||
adb -s 127.0.0.1:5555 pull /sdcard/screen.png .
|
||||
Reference in New Issue
Block a user