Compare commits

...

8 Commits

Author SHA1 Message Date
MistEO
20e5d32d1a update algorithm and configer 2021-07-13 01:02:37 +08:00
MistEO
0169e2c68d rename namespace asst 2021-07-12 20:32:35 +08:00
MistEO
dba404f33b optimze thread 2021-07-12 20:11:10 +08:00
MistEO
839c97c6cd rename Test to Sanity 2021-07-12 19:56:29 +08:00
MistEO
d31b42fd93 update debugprint 2021-07-12 19:35:38 +08:00
MistEO
c52069d59f Merge branch 'develop' 2021-07-12 19:17:37 +08:00
MistEO
8dd30d406a add *.filters 2021-07-12 19:15:49 +08:00
MistEO
af5fcf53ad update tasks queue. add DebugTrace function 2021-07-12 17:44:15 +08:00
27 changed files with 435 additions and 306 deletions

1
.gitignore vendored
View File

@@ -34,6 +34,5 @@
Debug
Release
.vs
*.vcxproj.filters
*.vcxproj.user
*.swp

View File

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

View File

@@ -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" />

View 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>

View File

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

View File

@@ -6,9 +6,9 @@
#include <memory>
#include <queue>
#include "AssDef.h"
#include "AsstDef.h"
namespace MeoAssistance {
namespace asst {
class WinMacro;
class Identify;
@@ -24,25 +24,18 @@ namespace MeoAssistance {
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<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;
};
}

View File

@@ -0,0 +1,96 @@
#pragma once
#include "json_value.h"
#include "json_array.h"
#include <mutex>
#include <process.h>
#include <Windows.h>
namespace asst {
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() = 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)...);
}
}

View File

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

View File

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

View File

@@ -5,9 +5,9 @@
#include <Windows.h>
#include <opencv2/opencv.hpp>
#include "AssDef.h"
#include "AsstDef.h"
namespace MeoAssistance {
namespace asst {
class WinMacro
{
public:
@@ -16,6 +16,7 @@ namespace MeoAssistance {
bool findHandle();
bool resizeWindow(int Width, int Height);
bool resizeWindow(); // by configer
bool click(const Point & p);
bool clickRange(const Rect & rect);
cv::Mat getImage(const Rect& rect);
@@ -26,5 +27,9 @@ namespace MeoAssistance {
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;
};
}

View File

@@ -4,7 +4,7 @@
#include "Configer.h"
#include "Identify.h"
using namespace MeoAssistance;
using namespace asst;
Assistance::Assistance()
{
@@ -16,26 +16,18 @@ 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_thread_exit = true;
m_thread_running = false;
m_condvar.notify_one();
m_identify_exit = true;
m_identify_running = false;
m_identify_cv.notify_all();
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();
}
}
@@ -43,105 +35,104 @@ bool Assistance::setSimulatorType(SimulatorType type)
{
stop();
std::unique_lock<std::mutex> lock(m_tasks_mutex);
std::queue<Rect> empty;
m_tasks.swap(empty);
std::unique_lock<std::mutex> lock(m_mutex);
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);
ret = m_pWindow->resizeWindow();
}
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);
}
}
}

View File

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

View File

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

View File

@@ -9,11 +9,10 @@
#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),
@@ -26,13 +25,17 @@ bool WinMacro::findHandle()
json::array handle_arr;
switch (m_handle_type) {
case HandleType::BlueStacksControl:
handle_arr = Configer::handleObj["BlueStacksControl"].as_array();
m_xOffset = Configer::handleObj["BlueStacks"]["xOffset"].as_integer();
m_yOffset = Configer::handleObj["BlueStacks"]["yOffset"].as_integer();
handle_arr = Configer::handleObj["BlueStacks"]["Control"].as_array();
break;
case HandleType::BlueStacksView:
handle_arr = Configer::handleObj["BlueStacksView"].as_array();
handle_arr = Configer::handleObj["BlueStacks"]["View"].as_array();
break;
case HandleType::BlueStacksWindow:
handle_arr = Configer::handleObj["BlueStacksWindow"].as_array();
m_width = Configer::handleObj["BlueStacks"]["Width"].as_integer();
m_height = Configer::handleObj["BlueStacks"]["Height"].as_integer();
handle_arr = Configer::handleObj["BlueStacks"]["Window"].as_array();
break;
default:
std::cerr << "handle type error! " << static_cast<int>(m_handle_type) << std::endl;
@@ -45,9 +48,7 @@ bool WinMacro::findHandle()
m_handle = ::FindWindowExA(m_handle, NULL, obj["class"].as_string().c_str(), obj["window"].as_string().c_str());
}
#ifdef _DEBUG
std::cout << "type: " << static_cast<int>(m_handle_type) << ", handle: " << m_handle << std::endl;
#endif
DebugTrace("type: 0x%x, handle: 0x%x", m_handle_type, m_handle);
if (m_handle != NULL) {
return true;
@@ -66,6 +67,11 @@ bool WinMacro::resizeWindow(int width, int height)
return ::MoveWindow(m_handle, 0, 0, width / getScreenScale(), height / getScreenScale(), true);
}
bool WinMacro::resizeWindow()
{
return resizeWindow(m_width, m_height);
}
double WinMacro::getScreenScale()
{
static double scale = 0;
@@ -106,11 +112,10 @@ bool WinMacro::click(const Point& p)
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);
@@ -131,16 +136,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,9 +157,11 @@ 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)

View File

@@ -16,10 +16,10 @@ A game assistance for Arknights
## 使用说明
### alpha_2 版本
### alpha_3 版本
1. 使用蓝叠模拟器打开明日方舟,进入有**蓝色的开始行动按钮**的界面,勾上代理指挥
2. 解压压缩包,**使用管理员权限**,打开"Test.exe"
2. 解压压缩包,**使用管理员权限**,打开"Sanity.exe"
3. 目前只有最基本的功能,刷完体力+体力药就会自动停了……
## Todo
@@ -28,19 +28,20 @@ A game assistance for Arknights
- [ ] 图形化界面
- [ ] 功能
- [ ] 支持剿灭
- [x] 支持剿灭
- [ ] 支持刷指定次数
- [ ] 支持使模拟器窗口不可见
- [x] 自动吃体力药
- [ ] 自动吃石头(根据设置,指定数量)
- [ ] 代理失败的情况
- [ ] 支持更多模拟器
- [ ] 支持等级提升
- [x] 支持等级提升
- [ ] 支持凌晨4点更新数据
- [ ] 信用访问
- [ ] 基建收菜
- [ ] 算法
- [ ] 更换算法为找图,而不是当前的区域相似度对比
- [x] 算法
- [x] 更换算法为找图,而不是当前的区域相似度对比
- [ ] 优化算法效率
## 致谢

View File

@@ -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">

View 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>

23
Tools/Sanity/main.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include "Assistance.h"
int main(int argc, char** argv)
{
using namespace asst;
Assistance asst;
if (!asst.setSimulatorType(SimulatorType::BlueStacks)) {
DebugTraceError("Can't Find Simulator or Permission denied.");
getchar();
return -1;
}
DebugTraceInfo("Start");
asst.start();
getchar();
DebugTraceInfo("Stop");
asst.stop();
return 0;
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 KiB

After

Width:  |  Height:  |  Size: 188 KiB

View File

@@ -1,112 +1,78 @@
{
"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
}
},
"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.99,
"type": "doNothing"
},
"UseStone": {
"viewRect": [
571,
118,
621,
504
],
"filename": "UseStone.png",
"similarity": 0.999,
"threshold": 0.999,
"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"
}
}
}