Compare commits
14 Commits
release.al
...
release.al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92a531b43a | ||
|
|
3a4d2e430d | ||
|
|
6a6302cb93 | ||
|
|
2454844735 | ||
|
|
fba51db8c8 | ||
|
|
06e8a5e6b8 | ||
|
|
20e5d32d1a | ||
|
|
0169e2c68d | ||
|
|
dba404f33b | ||
|
|
839c97c6cd | ||
|
|
d31b42fd93 | ||
|
|
c52069d59f | ||
|
|
8dd30d406a | ||
|
|
af5fcf53ad |
1
.gitignore
vendored
@@ -34,6 +34,5 @@
|
||||
Debug
|
||||
Release
|
||||
.vs
|
||||
*.vcxproj.filters
|
||||
*.vcxproj.user
|
||||
*.swp
|
||||
|
||||
@@ -10,7 +10,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeoAssistance", "MeoAssista
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmeojson", "meojson\test\vsproj\meojson\libmeojson\libmeojson.vcxproj", "{9CC7838E-D5FB-4771-848D-5F83D638C5AD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Tools\Test\Test.vcxproj", "{36BC08F3-71CF-429A-AE69-291BE8962CB2}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sanity", "Tools\Sanity\Sanity.vcxproj", "{36BC08F3-71CF-429A-AE69-291BE8962CB2}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
|
||||
{9CC7838E-D5FB-4771-848D-5F83D638C5AD} = {9CC7838E-D5FB-4771-848D-5F83D638C5AD}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\AssDef.h" />
|
||||
<ClInclude Include="include\AsstDef.h" />
|
||||
<ClInclude Include="include\Assistance.h" />
|
||||
<ClInclude Include="include\Configer.h" />
|
||||
<ClInclude Include="include\Identify.h" />
|
||||
|
||||
48
MeoAssistance/MeoAssistance.vcxproj.filters
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\Assistance.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Assistance.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Configer.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Identify.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\WinMacro.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_value.h"
|
||||
#include "json_array.h"
|
||||
|
||||
namespace MeoAssistance {
|
||||
enum class SimulatorType
|
||||
{
|
||||
BlueStacks = 0x100
|
||||
};
|
||||
enum class HandleType
|
||||
{
|
||||
View = 1,
|
||||
Control = 2,
|
||||
Window = 4,
|
||||
|
||||
BlueStacksView = 0x100 | 1,
|
||||
BlueStacksControl = 0x100 | 2,
|
||||
BlueStacksWindow = 0x100 | 4
|
||||
};
|
||||
|
||||
struct Point
|
||||
{
|
||||
Point(int x, int y) : x(x), y(y) {}
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
Rect(int x, int y, int width, int height)
|
||||
: x(x), y(y), width(width), height(height) {}
|
||||
Rect operator*(double rhs) const { return { x, y, static_cast<int>(width * rhs), static_cast<int>(height * rhs) }; }
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
};
|
||||
|
||||
static Rect jsonToRect(const json::array& arr)
|
||||
{
|
||||
if (arr.size() != 4) {
|
||||
return { 0, 0, 0, 0 };
|
||||
}
|
||||
return Rect(arr[0].as_integer(), arr[1].as_integer(), arr[2].as_integer(), arr[3].as_integer());
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,11 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <optional>
|
||||
|
||||
#include "AssDef.h"
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace MeoAssistance {
|
||||
namespace asst {
|
||||
class WinMacro;
|
||||
class Identify;
|
||||
|
||||
@@ -18,31 +18,24 @@ namespace MeoAssistance {
|
||||
Assistance();
|
||||
~Assistance();
|
||||
|
||||
bool setSimulatorType(SimulatorType type);
|
||||
std::optional<std::string> setSimulator(const std::string & simulator_name = std::string());
|
||||
void start();
|
||||
// void pause();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
static void identify_function(Assistance* pThis); // 识别线程,生产者
|
||||
static void control_function(Assistance* pThis); // 控制线程,消费者
|
||||
static void working_proc(Assistance* pThis);
|
||||
|
||||
std::shared_ptr<WinMacro> m_pCtrl = nullptr;
|
||||
std::shared_ptr<WinMacro> m_pWindow = nullptr;
|
||||
std::shared_ptr<WinMacro> m_pView = nullptr;
|
||||
std::shared_ptr<WinMacro> m_pCtrl = nullptr;
|
||||
std::shared_ptr<Identify> m_Ider = nullptr;
|
||||
|
||||
std::queue<Rect> m_tasks;
|
||||
std::mutex m_tasks_mutex;
|
||||
|
||||
std::thread m_control_thread;
|
||||
std::thread m_identify_thread;
|
||||
bool m_control_exit = false;
|
||||
bool m_identify_exit = false;
|
||||
bool m_control_running = false;
|
||||
bool m_identify_running = false;
|
||||
std::condition_variable m_control_cv;
|
||||
std::condition_variable m_identify_cv;
|
||||
std::thread m_working_thread;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_condvar;
|
||||
bool m_thread_exit = false;
|
||||
bool m_thread_running = false;
|
||||
};
|
||||
|
||||
}
|
||||
88
MeoAssistance/include/AsstDef.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_value.h"
|
||||
#include "json_array.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <process.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace asst {
|
||||
enum class HandleType
|
||||
{
|
||||
Window = 1,
|
||||
View = 2,
|
||||
Control = 4
|
||||
};
|
||||
|
||||
struct Point
|
||||
{
|
||||
Point() = default;
|
||||
Point(int x, int y) : x(x), y(y) {}
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
Rect() = default;
|
||||
Rect(int x, int y, int width, int height)
|
||||
: x(x), y(y), width(width), height(height) {}
|
||||
Rect operator*(double rhs) const
|
||||
{
|
||||
return { x, y, static_cast<int>(width * rhs), static_cast<int>(height * rhs) };
|
||||
}
|
||||
Rect center_zoom(double scale)
|
||||
{
|
||||
int half_width_scale = static_cast<int>(width * (1- scale) / 2) ;
|
||||
int half_hight_scale = static_cast<int>(height * (1 - scale) / 2) ;
|
||||
return { x + half_width_scale, y + half_hight_scale, width - half_width_scale, height - half_hight_scale };
|
||||
}
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
};
|
||||
|
||||
static Rect jsonToRect(const json::array& arr)
|
||||
{
|
||||
if (arr.size() != 4) {
|
||||
return { 0, 0, 0, 0 };
|
||||
}
|
||||
return Rect(arr[0].as_integer(), arr[1].as_integer(), arr[2].as_integer(), arr[3].as_integer());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void DebugPrint(const std::string& level, Args &&... args)
|
||||
{
|
||||
static std::mutex trace_mutex;
|
||||
std::unique_lock<std::mutex> trace_lock(trace_mutex);
|
||||
|
||||
SYSTEMTIME curtime;
|
||||
GetLocalTime(&curtime);
|
||||
printf("[%04d-%02d-%02d %02d:%02d:%02d.%03d][%s][Px%x][Tx%x] ",
|
||||
curtime.wYear, curtime.wMonth, curtime.wDay,
|
||||
curtime.wHour, curtime.wMinute, curtime.wSecond, curtime.wMilliseconds,
|
||||
level.c_str(), _getpid(), GetCurrentThreadId());
|
||||
printf(std::forward<Args>(args)...);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline void DebugTrace(Args &&... args)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
DebugPrint("TRC", std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void DebugTraceInfo(Args &&... args)
|
||||
{
|
||||
DebugPrint("INF", std::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void DebugTraceError(Args &&... args)
|
||||
{
|
||||
DebugPrint("ERR", std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
#include "json_object.h"
|
||||
|
||||
namespace MeoAssistance {
|
||||
namespace asst {
|
||||
class Configer
|
||||
{
|
||||
public:
|
||||
@@ -14,7 +14,7 @@ namespace MeoAssistance {
|
||||
static std::string getResDir();
|
||||
static json::object dataObj;
|
||||
static json::object handleObj;
|
||||
|
||||
static json::object optionsObj;
|
||||
private:
|
||||
Configer() = default;
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "AssDef.h"
|
||||
#include "AsstDef.h"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace MeoAssistance {
|
||||
namespace asst {
|
||||
|
||||
class WinMacro;
|
||||
|
||||
@@ -14,9 +15,15 @@ namespace MeoAssistance {
|
||||
public:
|
||||
Identify() = default;
|
||||
~Identify() = default;
|
||||
double imgHistComp(const cv::Mat& lhs, const cv::Mat& rhs);
|
||||
double imgHistComp(const cv::Mat& cur, const std::string& src, MeoAssistance::Rect compRect);
|
||||
|
||||
bool addImage(const std::string& name, const std::string& path);
|
||||
|
||||
double imgHistComp(const cv::Mat& lhs, const cv::Mat& rhs);
|
||||
double imgHistComp(const cv::Mat& cur, const std::string& src, asst::Rect compRect);
|
||||
std::pair<double, asst::Rect> findImage(const cv::Mat& image, const cv::Mat& templ);
|
||||
std::pair<double, asst::Rect> findImage(const cv::Mat& cur, const std::string& templ);
|
||||
std::pair<double, asst::Rect> findImageWithFile(const cv::Mat& cur, const std::string& filename);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, cv::Mat> m_matMap;
|
||||
};
|
||||
|
||||
@@ -5,26 +5,35 @@
|
||||
#include <Windows.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "AssDef.h"
|
||||
#include "AsstDef.h"
|
||||
|
||||
namespace MeoAssistance {
|
||||
namespace asst {
|
||||
class WinMacro
|
||||
{
|
||||
public:
|
||||
WinMacro(HandleType type);
|
||||
WinMacro(const std::string & simulator_name, HandleType type);
|
||||
~WinMacro() = default;
|
||||
|
||||
bool findHandle();
|
||||
bool captured() const noexcept;
|
||||
bool resizeWindow(int Width, int Height);
|
||||
bool resizeWindow(); // by configer
|
||||
bool showWindow();
|
||||
bool hideWindow();
|
||||
bool click(const Point & p);
|
||||
bool clickRange(const Rect & rect);
|
||||
cv::Mat getImage(const Rect& rect);
|
||||
Rect getWindowRect();
|
||||
static double getScreenScale();
|
||||
private:
|
||||
bool findHandle();
|
||||
|
||||
HandleType m_handle_type;
|
||||
const std::string m_simulator_name;
|
||||
const HandleType m_handle_type;
|
||||
HWND m_handle = NULL;
|
||||
std::minstd_rand m_rand_engine;
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
int m_xOffset = 0;
|
||||
int m_yOffset = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Configer.h"
|
||||
#include "Identify.h"
|
||||
|
||||
using namespace MeoAssistance;
|
||||
using namespace asst;
|
||||
|
||||
Assistance::Assistance()
|
||||
{
|
||||
@@ -16,132 +16,146 @@ Assistance::Assistance()
|
||||
m_Ider->addImage(pair.first, Configer::getResDir() + pair.second["filename"].as_string());
|
||||
}
|
||||
|
||||
m_control_thread = std::thread(control_function, this);
|
||||
m_identify_thread = std::thread(identify_function, this);
|
||||
m_working_thread = std::thread(working_proc, this);
|
||||
|
||||
}
|
||||
|
||||
Assistance::~Assistance()
|
||||
{
|
||||
m_control_exit = true;
|
||||
m_control_running = false;
|
||||
m_control_cv.notify_all();
|
||||
m_pWindow->showWindow();
|
||||
|
||||
m_identify_exit = true;
|
||||
m_identify_running = false;
|
||||
m_identify_cv.notify_all();
|
||||
m_thread_exit = true;
|
||||
m_thread_running = false;
|
||||
m_condvar.notify_one();
|
||||
|
||||
if (m_control_thread.joinable()) {
|
||||
m_control_thread.join();
|
||||
}
|
||||
if (m_identify_thread.joinable()) {
|
||||
m_identify_thread.join();
|
||||
if (m_working_thread.joinable()) {
|
||||
m_working_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
bool Assistance::setSimulatorType(SimulatorType type)
|
||||
std::optional<std::string> Assistance::setSimulator(const std::string& simulator_name)
|
||||
{
|
||||
stop();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_tasks_mutex);
|
||||
std::queue<Rect> empty;
|
||||
m_tasks.swap(empty);
|
||||
int int_type = static_cast<int>(type);
|
||||
m_pCtrl = std::make_shared<WinMacro>(static_cast<HandleType>(int_type | static_cast<int>(HandleType::Control)));
|
||||
m_pWindow = std::make_shared<WinMacro>(static_cast<HandleType>(int_type | static_cast<int>(HandleType::Window)));
|
||||
m_pView = std::make_shared<WinMacro>(static_cast<HandleType>(int_type | static_cast<int>(HandleType::View)));
|
||||
bool ret = m_pCtrl->findHandle() && m_pWindow->findHandle() && m_pView->findHandle();
|
||||
if (ret) {
|
||||
m_pWindow->resizeWindow(1200, 720);
|
||||
auto create_handles = [&](const std::string name) -> bool {
|
||||
m_pWindow = std::make_shared<WinMacro>(name, HandleType::Window);
|
||||
m_pView = std::make_shared<WinMacro>(name, HandleType::View);
|
||||
m_pCtrl = std::make_shared<WinMacro>(name, HandleType::Control);
|
||||
return m_pWindow->captured() && m_pView->captured() && m_pCtrl->captured();
|
||||
};
|
||||
|
||||
bool ret = false;
|
||||
std::string cor_name = simulator_name;
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
if (simulator_name.empty()) {
|
||||
for (auto&& [name, value] : Configer::handleObj)
|
||||
{
|
||||
ret = create_handles(name);
|
||||
if (ret) {
|
||||
cor_name = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = create_handles(simulator_name);
|
||||
}
|
||||
if (ret && m_pWindow->resizeWindow()) {
|
||||
return cor_name;
|
||||
}
|
||||
else {
|
||||
return std::nullopt;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Assistance::start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_tasks_mutex);
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
m_control_running = true;
|
||||
m_identify_running = true;
|
||||
m_control_cv.notify_all();
|
||||
m_identify_cv.notify_all();
|
||||
m_thread_running = true;
|
||||
m_condvar.notify_one();
|
||||
}
|
||||
|
||||
void Assistance::stop()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_tasks_mutex);
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
m_control_running = false;
|
||||
m_identify_running = false;
|
||||
m_thread_running = false;
|
||||
}
|
||||
|
||||
void Assistance::identify_function(Assistance* pThis)
|
||||
void Assistance::working_proc(Assistance* pThis)
|
||||
{
|
||||
while (!pThis->m_identify_exit) {
|
||||
std::unique_lock<std::mutex> lock(pThis->m_tasks_mutex);
|
||||
if (pThis->m_identify_running) {
|
||||
while (!pThis->m_thread_exit) {
|
||||
std::unique_lock<std::mutex> lock(pThis->m_mutex);
|
||||
if (pThis->m_thread_running) {
|
||||
auto curImg = pThis->m_pView->getImage(pThis->m_pView->getWindowRect());
|
||||
|
||||
double max_value = -1;
|
||||
Rect cor_rect;
|
||||
std::pair<std::string, json::value> matched;
|
||||
double max_similarity = 0;
|
||||
for (auto&& pair : Configer::dataObj) {
|
||||
double similarity = pThis->m_Ider->imgHistComp(curImg, pair.first, jsonToRect(pair.second["viewRect"].as_array()));
|
||||
#ifdef _DEBUG
|
||||
std::cout << pair.first << " Similarity: " << similarity << std::endl;
|
||||
#endif
|
||||
if (similarity >= pair.second["similarity"].as_double()) {
|
||||
if (similarity > max_similarity) {
|
||||
max_similarity = similarity;
|
||||
auto&& [value, rect] = pThis->m_Ider->findImage(curImg, pair.first);
|
||||
DebugTrace("%-20s %f", pair.first.c_str(), value);
|
||||
if (value >= pair.second["threshold"].as_double()) {
|
||||
if (value >= max_value) {
|
||||
max_value = value;
|
||||
cor_rect = rect;
|
||||
matched = pair;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (max_similarity != 0) {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "Max: " << matched.first << " , Similarity: " << max_similarity << std::endl;
|
||||
#endif
|
||||
std::string opType = matched.second["type"].as_string();
|
||||
if (opType == "click") {
|
||||
pThis->m_tasks.emplace(jsonToRect(matched.second["ctrlRect"].as_array()));
|
||||
if (max_value >= 0) {
|
||||
auto task = Configer::dataObj[matched.first].as_object();
|
||||
std::string opType = task["type"].as_string();
|
||||
DebugTraceInfo("Matched: %s, type: %s", matched.first.c_str(), opType.c_str());
|
||||
bool next_loop = true;
|
||||
while (next_loop) {
|
||||
if (opType == "clickSelf") {
|
||||
pThis->m_pCtrl->clickRange(cor_rect);
|
||||
}
|
||||
else if (opType == "clickRand") {
|
||||
pThis->m_pCtrl->clickRange(pThis->m_pCtrl->getWindowRect());
|
||||
}
|
||||
else if (opType == "next") {
|
||||
json::value nextObj = task["next"];
|
||||
std::string name = nextObj["name"].as_string();
|
||||
std::string filepath = Configer::getResDir() + nextObj["filename"].as_string();
|
||||
auto&& [value, rect] = pThis->m_Ider->findImageWithFile(curImg, filepath);
|
||||
DebugTrace("Next: %-20s %f", name.c_str(), value);
|
||||
|
||||
if (value >= nextObj["threshold"].as_double()) {
|
||||
DebugTraceInfo("Next matched: %s", name.c_str());
|
||||
task = nextObj.as_object();
|
||||
opType = nextObj["type"].as_string();
|
||||
cor_rect = rect;
|
||||
max_value = value;
|
||||
next_loop = true;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
DebugTraceInfo("Next not matched: %s", name.c_str());
|
||||
}
|
||||
}
|
||||
else if (opType == "stop") {
|
||||
DebugTrace("opType == stop");
|
||||
pThis->m_thread_running = false;
|
||||
break;
|
||||
}
|
||||
else if (opType == "doNothing") {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
DebugTraceError("Unknow option type: %s", opType.c_str());
|
||||
}
|
||||
next_loop = false;
|
||||
}
|
||||
else if (opType == "stop") {
|
||||
#ifdef _DEBUG
|
||||
std::cout << "opType == stop " << std::endl;
|
||||
#endif
|
||||
pThis->m_control_running = false;
|
||||
pThis->m_identify_running = false;
|
||||
continue;
|
||||
}
|
||||
else if (opType == "donothing") {
|
||||
pThis->m_identify_cv.wait_for(lock, std::chrono::milliseconds(1000));
|
||||
continue;
|
||||
}
|
||||
pThis->m_control_cv.notify_all();
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
pThis->m_identify_cv.wait_for(lock, std::chrono::milliseconds(1000));
|
||||
pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(Configer::optionsObj["delay"].as_integer()));
|
||||
}
|
||||
else {
|
||||
pThis->m_identify_cv.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Assistance::control_function(Assistance* pThis)
|
||||
{
|
||||
while (!pThis->m_control_exit) {
|
||||
std::unique_lock<std::mutex> lock(pThis->m_tasks_mutex);
|
||||
if (pThis->m_control_running && !pThis->m_tasks.empty()) {
|
||||
const Rect rect = pThis->m_tasks.front();
|
||||
pThis->m_tasks.pop();
|
||||
lock.unlock();
|
||||
|
||||
pThis->m_pCtrl->clickRange(rect);
|
||||
}
|
||||
else {
|
||||
pThis->m_control_cv.wait(lock);
|
||||
pThis->m_condvar.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,11 @@
|
||||
|
||||
#include "json.h"
|
||||
|
||||
using namespace MeoAssistance;
|
||||
using namespace asst;
|
||||
|
||||
json::object Configer::dataObj;
|
||||
json::object Configer::handleObj;
|
||||
json::object Configer::optionsObj;
|
||||
|
||||
std::string Configer::m_curDir;
|
||||
|
||||
@@ -33,6 +34,8 @@ bool Configer::reload()
|
||||
auto root = std::move(ret).value();
|
||||
dataObj = root["data"].as_object();
|
||||
handleObj = root["handle"].as_object();
|
||||
optionsObj = root["options"].as_object();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,19 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/imgproc/types_c.h>
|
||||
|
||||
using namespace MeoAssistance;
|
||||
using namespace asst;
|
||||
using namespace cv;
|
||||
|
||||
bool Identify::addImage(const std::string& name, const std::string& path)
|
||||
{
|
||||
Mat mat = imread(path);
|
||||
if (mat.empty()) {
|
||||
return false;
|
||||
}
|
||||
m_matMap.emplace(name, mat);
|
||||
return true;
|
||||
}
|
||||
|
||||
double Identify::imgHistComp(const cv::Mat& lhs, const cv::Mat& rhs)
|
||||
{
|
||||
cv::Mat lhs_hsv;
|
||||
@@ -32,18 +42,45 @@ double Identify::imgHistComp(const cv::Mat& lhs, const cv::Mat& rhs)
|
||||
return compareHist(lhs_hist, rhs_hist, CV_COMP_CORREL);
|
||||
}
|
||||
|
||||
double Identify::imgHistComp(const cv::Mat& cur, const std::string& src, MeoAssistance::Rect compRect)
|
||||
double Identify::imgHistComp(const cv::Mat& cur, const std::string& src, asst::Rect compRect)
|
||||
{
|
||||
if (m_matMap.find(src) == m_matMap.end()) {
|
||||
return 0;
|
||||
}
|
||||
cv::Rect cvRect(compRect.x, compRect.y, compRect.width, compRect.height);
|
||||
return imgHistComp(cur(cvRect), m_matMap.at(src)(cvRect));
|
||||
}
|
||||
|
||||
bool Identify::addImage(const std::string& name, const std::string& path)
|
||||
std::pair<double, asst::Rect> Identify::findImage(const cv::Mat& image, const cv::Mat& templ)
|
||||
{
|
||||
Mat mat = imread(path);
|
||||
if (mat.empty()) {
|
||||
return false;
|
||||
cv::Mat image_hsv;
|
||||
cv::Mat templ_hsv;
|
||||
cvtColor(image, image_hsv, COLOR_BGR2HSV);
|
||||
cvtColor(templ, templ_hsv, COLOR_BGR2HSV);
|
||||
|
||||
Mat matched;
|
||||
matchTemplate(image_hsv, templ_hsv, matched, cv::TM_CCORR_NORMED);
|
||||
|
||||
double minVal = 0, maxVal = 0;
|
||||
cv::Point minLoc, maxLoc;
|
||||
minMaxLoc(matched, &minVal, &maxVal, &minLoc, &maxLoc);
|
||||
|
||||
return { maxVal, asst::Rect(maxLoc.x, maxLoc.y, templ.cols, templ.rows).center_zoom(0.8) };
|
||||
}
|
||||
|
||||
std::pair<double, asst::Rect> Identify::findImage(const cv::Mat& cur, const std::string& templ)
|
||||
{
|
||||
if (m_matMap.find(templ) == m_matMap.end()) {
|
||||
return { 0, asst::Rect() };
|
||||
}
|
||||
m_matMap.emplace(name, mat);
|
||||
return true;
|
||||
}
|
||||
return findImage(cur, m_matMap.at(templ));
|
||||
}
|
||||
|
||||
std::pair<double, asst::Rect> Identify::findImageWithFile(const cv::Mat& cur, const std::string& filename)
|
||||
{
|
||||
Mat mat = imread(filename);
|
||||
if (mat.empty()) {
|
||||
return { 0, asst::Rect() };
|
||||
}
|
||||
return findImage(cur, mat);
|
||||
}
|
||||
|
||||
@@ -3,51 +3,73 @@
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <WinUser.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Configer.h"
|
||||
#include "AsstDef.h"
|
||||
|
||||
using namespace MeoAssistance;
|
||||
using namespace asst;
|
||||
|
||||
WinMacro::WinMacro(HandleType type)
|
||||
: m_handle_type(type),
|
||||
WinMacro::WinMacro(const std::string& simulator_name, HandleType type)
|
||||
: m_simulator_name(simulator_name),
|
||||
m_handle_type(type),
|
||||
m_rand_engine(time(NULL))
|
||||
{
|
||||
findHandle();
|
||||
}
|
||||
|
||||
bool WinMacro::captured() const noexcept
|
||||
{
|
||||
return m_handle != NULL;
|
||||
}
|
||||
|
||||
bool WinMacro::findHandle()
|
||||
{
|
||||
json::array handle_arr;
|
||||
json::value simulator_json = Configer::handleObj[m_simulator_name];
|
||||
switch (m_handle_type) {
|
||||
case HandleType::BlueStacksControl:
|
||||
handle_arr = Configer::handleObj["BlueStacksControl"].as_array();
|
||||
case HandleType::Window:
|
||||
m_width = simulator_json["Width"].as_integer();
|
||||
m_height = simulator_json["Height"].as_integer();
|
||||
handle_arr = simulator_json["Window"].as_array();
|
||||
break;
|
||||
case HandleType::BlueStacksView:
|
||||
handle_arr = Configer::handleObj["BlueStacksView"].as_array();
|
||||
case HandleType::View:
|
||||
handle_arr = simulator_json["View"].as_array();
|
||||
break;
|
||||
case HandleType::BlueStacksWindow:
|
||||
handle_arr = Configer::handleObj["BlueStacksWindow"].as_array();
|
||||
case HandleType::Control:
|
||||
m_xOffset = simulator_json["xOffset"].as_integer();
|
||||
m_yOffset = simulator_json["yOffset"].as_integer();
|
||||
handle_arr = simulator_json["Control"].as_array();
|
||||
break;
|
||||
default:
|
||||
std::cerr << "handle type error! " << static_cast<int>(m_handle_type) << std::endl;
|
||||
DebugTraceError("Handle type error!: %d", m_handle_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_handle = NULL;
|
||||
for (auto&& obj : handle_arr)
|
||||
{
|
||||
m_handle = ::FindWindowExA(m_handle, NULL, obj["class"].as_string().c_str(), obj["window"].as_string().c_str());
|
||||
std::string class_str = obj["class"].as_string();
|
||||
size_t class_len = (class_str.size() + 1) * 2;
|
||||
wchar_t* class_wbuff = new wchar_t[class_len];
|
||||
::MultiByteToWideChar(CP_UTF8, 0, obj["class"].as_string().c_str(), -1, class_wbuff, class_len);
|
||||
|
||||
std::string window_str = obj["window"].as_string();
|
||||
size_t window_len = (window_str.size() + 1) * 2;
|
||||
wchar_t* window_wbuff = new wchar_t[window_len];
|
||||
memset(window_wbuff, 0, window_len);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, obj["window"].as_string().c_str(), -1, window_wbuff, window_len);
|
||||
|
||||
m_handle = ::FindWindowExW(m_handle, NULL, class_wbuff, window_wbuff);
|
||||
|
||||
delete[] class_wbuff;
|
||||
delete[] window_wbuff;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
std::cout << "type: " << static_cast<int>(m_handle_type) << ", handle: " << m_handle << std::endl;
|
||||
#endif
|
||||
DebugTrace("Handle: 0x%x, Name: %s, Type: %d", m_handle, m_simulator_name.c_str(), m_handle_type);
|
||||
|
||||
if (m_handle != NULL) {
|
||||
return true;
|
||||
@@ -59,13 +81,36 @@ bool WinMacro::findHandle()
|
||||
|
||||
bool WinMacro::resizeWindow(int width, int height)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Window))) {
|
||||
if (m_handle_type != HandleType::Window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::MoveWindow(m_handle, 0, 0, width / getScreenScale(), height / getScreenScale(), true);
|
||||
}
|
||||
|
||||
bool WinMacro::resizeWindow()
|
||||
{
|
||||
return resizeWindow(m_width, m_height);
|
||||
}
|
||||
|
||||
bool WinMacro::showWindow()
|
||||
{
|
||||
if (m_handle_type != HandleType::Window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::ShowWindow(m_handle, SW_SHOW);
|
||||
}
|
||||
|
||||
bool WinMacro::hideWindow()
|
||||
{
|
||||
if (m_handle_type != HandleType::Window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::ShowWindow(m_handle, SW_HIDE);
|
||||
}
|
||||
|
||||
double WinMacro::getScreenScale()
|
||||
{
|
||||
static double scale = 0;
|
||||
@@ -102,15 +147,14 @@ double WinMacro::getScreenScale()
|
||||
|
||||
bool WinMacro::click(const Point& p)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Control))) {
|
||||
if (m_handle_type != HandleType::Control) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = p.x / getScreenScale();
|
||||
int y = p.y / getScreenScale();
|
||||
#ifdef _DEBUG
|
||||
std::cout << "click: " << x << ", " << y << std::endl;
|
||||
#endif
|
||||
int x = (p.x + m_xOffset) / getScreenScale();
|
||||
int y = (p.y + m_yOffset) / getScreenScale();
|
||||
|
||||
DebugTrace("click, raw: %d, %d, cor: %d, %d", p.x, p.y, x, y);
|
||||
|
||||
LPARAM lparam = MAKELPARAM(x, y);
|
||||
|
||||
@@ -122,7 +166,7 @@ bool WinMacro::click(const Point& p)
|
||||
|
||||
bool WinMacro::clickRange(const Rect& rect)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::Control))) {
|
||||
if (m_handle_type != HandleType::Control) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -131,16 +175,17 @@ bool WinMacro::clickRange(const Rect& rect)
|
||||
x = rect.x;
|
||||
}
|
||||
else {
|
||||
std::poisson_distribution<int> x_rand(rect.width);
|
||||
x = x_rand(m_rand_engine) + rect.x;
|
||||
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 {
|
||||
std::poisson_distribution<int> y_rand(rect.height);
|
||||
y = y_rand(m_rand_engine) + rect.y;
|
||||
int y_rand = std::poisson_distribution<int>(rect.height / 2)(m_rand_engine);
|
||||
y = y_rand + rect.y;
|
||||
}
|
||||
|
||||
return click({ x, y });
|
||||
@@ -151,14 +196,16 @@ Rect WinMacro::getWindowRect()
|
||||
RECT rect;
|
||||
bool ret = ::GetWindowRect(m_handle, &rect);
|
||||
if (!ret) {
|
||||
return { 0, 0, 0 ,0 };
|
||||
return Rect();
|
||||
}
|
||||
return Rect{ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top } *getScreenScale();
|
||||
return Rect{ rect.left, rect.top,
|
||||
static_cast<int>((rect.right - rect.left) * getScreenScale()),
|
||||
static_cast<int>((rect.bottom - rect.top) * getScreenScale()) };
|
||||
}
|
||||
|
||||
cv::Mat WinMacro::getImage(const Rect& rect)
|
||||
{
|
||||
if (!(static_cast<int>(m_handle_type) & static_cast<int>(HandleType::View))) {
|
||||
if (m_handle_type != HandleType::View) {
|
||||
return cv::Mat();
|
||||
}
|
||||
|
||||
|
||||
50
README.md
@@ -2,24 +2,47 @@
|
||||
|
||||
A game assistance for Arknights
|
||||
|
||||
一款明日方舟的游戏辅助,目前仅支持蓝叠模拟器
|
||||
一款明日方舟的游戏辅助,龟速开发中……
|
||||
|
||||
龟速开发中……
|
||||
|
||||
## 优缺点
|
||||
## 功能介绍
|
||||
|
||||
- 所有操作,都是点击按钮内随机位置,且模拟泊松分布,不会像鼠标宏一样一直是同一个点,没有封号风险
|
||||
~~(虽然好像也没听说过谁用鼠标宏被封号的)~~
|
||||
- 模拟器窗口可以被遮挡,即使全屏看视频、玩游戏,也完全不影响辅助运行
|
||||
~~(但是模拟器还是不能最小化)~~
|
||||
- 使用C++ WinAPI开发,效率高,对系统性能占用小
|
||||
- 目前版本支持自动刷完所有体力+自动吃完体力药
|
||||
|
||||
### 模拟器支持
|
||||
|
||||
#### 蓝叠模拟器
|
||||
|
||||
完美兼容,作者绝大部分测试均在蓝叠上进行,稳定性最能保障
|
||||
|
||||
#### 逍遥模拟器
|
||||
|
||||
完美兼容
|
||||
|
||||
#### 雷电模拟器
|
||||
|
||||
完美兼容,需要收起右侧侧边栏后使用
|
||||
|
||||
#### 夜神模拟器
|
||||
|
||||
兼容,但辅助开始后不可操作模拟器窗口
|
||||
|
||||
#### 腾讯手游助手
|
||||
|
||||
兼容,但需要手动设置分辨率:设置中心——引擎设置——分辨率设置——1280x720——保存后重启模拟器
|
||||
|
||||
#### MuMu手游助手 && MuMu模拟器
|
||||
|
||||
不兼容,MuMu所有的句柄均不响应SendMessage鼠标消息,但官方提供了adb的方式进行控制,有时间再做
|
||||
|
||||
## 使用说明
|
||||
|
||||
### alpha_2 版本
|
||||
|
||||
1. 使用蓝叠模拟器打开明日方舟,进入有**蓝色的开始行动按钮**的界面,勾上代理指挥
|
||||
2. 解压压缩包,**使用管理员权限**,打开"Test.exe"
|
||||
2. 解压压缩包,**使用管理员权限**,打开"Sanity.exe"
|
||||
3. 目前只有最基本的功能,刷完体力+体力药就会自动停了……
|
||||
|
||||
## Todo
|
||||
@@ -28,19 +51,20 @@ A game assistance for Arknights
|
||||
|
||||
- [ ] 图形化界面
|
||||
- [ ] 功能
|
||||
- [ ] 支持剿灭
|
||||
- [x] 支持剿灭
|
||||
- [ ] 支持刷指定次数
|
||||
- [ ] 支持使模拟器窗口不可见
|
||||
- [x] 支持使模拟器窗口不可见
|
||||
- [x] 自动吃体力药
|
||||
- [ ] 自动吃石头(根据设置,指定数量)
|
||||
- [ ] 代理失败的情况
|
||||
- [ ] 支持更多模拟器
|
||||
- [ ] 支持等级提升
|
||||
- [x] 支持更多模拟器
|
||||
- [x] 支持等级提升
|
||||
- [ ] 支持凌晨4点更新数据
|
||||
- [ ] 信用访问
|
||||
- [ ] 基建收菜
|
||||
- [ ] 算法
|
||||
- [ ] 更换算法为找图,而不是当前的区域相似度对比
|
||||
- [x] 算法
|
||||
- [x] 更换算法为找图,而不是当前的区域相似度对比
|
||||
- [ ] 优化算法效率
|
||||
|
||||
|
||||
## 致谢
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<ProjectGuid>{36bc08f3-71cf-429a-ae69-291be8962cb2}</ProjectGuid>
|
||||
<RootNamespace>Test</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>Sanity</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
22
Tools/Sanity/Sanity.vcxproj.filters
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="源文件">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="头文件">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="资源文件">
|
||||
<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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
28
Tools/Sanity/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "Assistance.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using namespace asst;
|
||||
|
||||
Assistance asst;
|
||||
|
||||
auto ret = asst.setSimulator();
|
||||
if (!ret) {
|
||||
DebugTraceError("Can't Find Simulator or Permission denied.");
|
||||
getchar();
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
DebugTraceInfo("Find Simulator: %s", ret->c_str());
|
||||
}
|
||||
|
||||
DebugTraceInfo("Start");
|
||||
asst.start();
|
||||
|
||||
getchar();
|
||||
|
||||
DebugTraceInfo("Stop");
|
||||
asst.stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#include "Assistance.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
using namespace MeoAssistance;
|
||||
|
||||
Assistance ass;
|
||||
if (!ass.setSimulatorType(SimulatorType::BlueStacks)) {
|
||||
std::cerr << "failed" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "start" << std::endl;
|
||||
ass.start();
|
||||
|
||||
getchar();
|
||||
|
||||
std::cout << "stop" << std::endl;
|
||||
ass.stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
resource/MedicineConfirm.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 842 KiB |
|
Before Width: | Height: | Size: 811 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 952 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 988 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 667 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 717 KiB After Width: | Height: | Size: 188 KiB |
@@ -1,112 +1,186 @@
|
||||
{
|
||||
"version": 0.1,
|
||||
"options": {
|
||||
"delay": 2000
|
||||
},
|
||||
"handle": {
|
||||
"BlueStacksControl": [
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "BlueStacks App Player"
|
||||
},
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "HOSTWND"
|
||||
},
|
||||
{
|
||||
"class": "WindowsForms10.Window.8.app.0.34f5582_r6_ad1",
|
||||
"window": "BlueStacks Android PluginAndroid"
|
||||
}
|
||||
],
|
||||
"BlueStacksView": [
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "BlueStacks App Player"
|
||||
}
|
||||
],
|
||||
"BlueStacksWindow": [
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "BlueStacks App Player"
|
||||
}
|
||||
]
|
||||
"BlueStacks": {
|
||||
"Control": [
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "BlueStacks App Player"
|
||||
},
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "HOSTWND"
|
||||
},
|
||||
{
|
||||
"class": "WindowsForms10.Window.8.app.0.34f5582_r6_ad1",
|
||||
"window": "BlueStacks Android PluginAndroid"
|
||||
}
|
||||
],
|
||||
"View": [
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "BlueStacks App Player"
|
||||
}
|
||||
],
|
||||
"Window": [
|
||||
{
|
||||
"class": "BS2CHINAUI",
|
||||
"window": "BlueStacks App Player"
|
||||
}
|
||||
],
|
||||
"Width": 1294,
|
||||
"Height": 773,
|
||||
"xOffset": -7,
|
||||
"yOffset": -47
|
||||
},
|
||||
"Nox": {
|
||||
"Control": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
}
|
||||
],
|
||||
"View": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
}
|
||||
],
|
||||
"Window": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "夜神模拟器"
|
||||
}
|
||||
],
|
||||
"Width": 1298,
|
||||
"Height": 754,
|
||||
"xOffset": 0,
|
||||
"yOffset": -32
|
||||
},
|
||||
"LDPlayer": {
|
||||
"Control": [
|
||||
{
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
},
|
||||
{
|
||||
"class": "RenderWindow",
|
||||
"window": "TheRender"
|
||||
}
|
||||
],
|
||||
"View": [
|
||||
{
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
}
|
||||
],
|
||||
"Window": [
|
||||
{
|
||||
"class": "LDPlayerMainFrame",
|
||||
"window": "雷电模拟器"
|
||||
}
|
||||
],
|
||||
"Width": 1304,
|
||||
"Height": 756,
|
||||
"xOffset": 0,
|
||||
"yOffset": -35
|
||||
},
|
||||
"XYAZ": {
|
||||
"Control": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "逍遥模拟器"
|
||||
},
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "MainWindowWindow"
|
||||
}
|
||||
],
|
||||
"View": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "逍遥模拟器"
|
||||
}
|
||||
],
|
||||
"Window": [
|
||||
{
|
||||
"class": "Qt5QWindowIcon",
|
||||
"window": "逍遥模拟器"
|
||||
}
|
||||
],
|
||||
"Width": 1282,
|
||||
"Height": 769,
|
||||
"xOffset": 0,
|
||||
"yOffset": -47
|
||||
},
|
||||
"Tencent": {
|
||||
"Control": [
|
||||
{
|
||||
"class": "TXGuiFoundation",
|
||||
"window": "腾讯手游助手"
|
||||
},
|
||||
{
|
||||
"class": "AEngineRenderWindowClass",
|
||||
"window": "AEngineRenderWindow"
|
||||
}
|
||||
],
|
||||
"View": [
|
||||
{
|
||||
"class": "TXGuiFoundation",
|
||||
"window": "腾讯手游助手"
|
||||
}
|
||||
],
|
||||
"Window": [
|
||||
{
|
||||
"class": "TXGuiFoundation",
|
||||
"window": "腾讯手游助手"
|
||||
}
|
||||
],
|
||||
"Width": 1282,
|
||||
"Height": 769,
|
||||
"xOffset": 0,
|
||||
"yOffset": -42
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Random": {
|
||||
"filename": "",
|
||||
"threshold": 0,
|
||||
"type": "clickRand"
|
||||
},
|
||||
"UseMedicine": {
|
||||
"viewRect": [
|
||||
571,
|
||||
118,
|
||||
621,
|
||||
504
|
||||
],
|
||||
"filename": "UseMedicine.png",
|
||||
"similarity": 0.999,
|
||||
"type": "click",
|
||||
"ctrlRect": [
|
||||
994,
|
||||
523,
|
||||
30,
|
||||
17
|
||||
]
|
||||
"threshold": 0.99,
|
||||
"type": "next",
|
||||
"next": {
|
||||
"name": "MedicineConfirm",
|
||||
"filename": "MedicineConfirm.png",
|
||||
"threshold": 0.99,
|
||||
"type": "clickSelf"
|
||||
}
|
||||
},
|
||||
"PRTS": {
|
||||
"filename": "PRTS.png",
|
||||
"threshold": 0.98,
|
||||
"type": "doNothing"
|
||||
},
|
||||
"UseStone": {
|
||||
"viewRect": [
|
||||
571,
|
||||
118,
|
||||
621,
|
||||
504
|
||||
],
|
||||
"filename": "UseStone.png",
|
||||
"similarity": 0.999,
|
||||
"threshold": 0.99,
|
||||
"type": "stop"
|
||||
},
|
||||
"MissionSucceed": {
|
||||
"viewRect": [
|
||||
186,
|
||||
521,
|
||||
47,
|
||||
26
|
||||
],
|
||||
"filename": "MissionSucceed.png",
|
||||
"similarity": 0.4,
|
||||
"type": "click",
|
||||
"ctrlRect": [
|
||||
977,
|
||||
596,
|
||||
163,
|
||||
29
|
||||
]
|
||||
},
|
||||
"StartButton1": {
|
||||
"viewRect": [
|
||||
968,
|
||||
627,
|
||||
193,
|
||||
70
|
||||
],
|
||||
"filename": "StartButton1.png",
|
||||
"similarity": 0.99,
|
||||
"type": "click",
|
||||
"ctrlRect": [
|
||||
977,
|
||||
596,
|
||||
163,
|
||||
29
|
||||
]
|
||||
"threshold": 0.99,
|
||||
"type": "clickSelf"
|
||||
},
|
||||
"StartButton2": {
|
||||
"viewRect": [
|
||||
966,
|
||||
386,
|
||||
126,
|
||||
259
|
||||
],
|
||||
"filename": "StartButton2.png",
|
||||
"similarity": 0.99,
|
||||
"type": "click",
|
||||
"ctrlRect": [
|
||||
975,
|
||||
353,
|
||||
97,
|
||||
230
|
||||
]
|
||||
"threshold": 0.99,
|
||||
"type": "clickSelf"
|
||||
}
|
||||
}
|
||||
}
|
||||