mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 09:20:24 +08:00
Compare commits
19 Commits
release.al
...
release.al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38bff9a43a | ||
|
|
f2e73a586d | ||
|
|
694dbcc02b | ||
|
|
bbdb1ce349 | ||
|
|
e684a1339a | ||
|
|
d17078e7b8 | ||
|
|
db65d51e37 | ||
|
|
43848c1e89 | ||
|
|
ae9b6a1265 | ||
|
|
b69e7c76e6 | ||
|
|
e81421579d | ||
|
|
1d3c3874ce | ||
|
|
bfd21e4631 | ||
|
|
27dd02f4f4 | ||
|
|
30d714b814 | ||
|
|
96793ff73a | ||
|
|
e591283dea | ||
|
|
c7ac3f0886 | ||
|
|
f6a451b3bf |
@@ -31,6 +31,9 @@
|
||||
<ClCompile Include="src\Identify.cpp" />
|
||||
<ClCompile Include="src\WinMacro.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\resource\config.json" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
@@ -97,7 +100,7 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(ProjectDir)include;$(SolutionDir)meojson\include;$(OPENCV_PATH)\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(TargetDir);$(OPENCV_PATH)\x64\vc15\lib;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>$(TargetDir);$(OPENCV_NEW_BUILD)lib\Release;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -172,7 +175,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>opencv_world452.lib;libmeojson.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>opencv_core452.lib;opencv_imgcodecs452.lib;opencv_imgproc452.lib;libmeojson.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
|
||||
<AdditionalLibraryDirectories>$(TargetDir)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
|
||||
@@ -45,4 +45,9 @@
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\resource\config.json">
|
||||
<Filter>资源文件</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -36,6 +36,7 @@ namespace asst {
|
||||
std::condition_variable m_condvar;
|
||||
bool m_thread_exit = false;
|
||||
bool m_thread_running = false;
|
||||
json::array m_next_tasks;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -71,9 +71,9 @@ namespace asst {
|
||||
template <typename... Args>
|
||||
inline void DebugTrace(Args &&... args)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
//#ifdef _DEBUG
|
||||
DebugPrint("TRC", std::forward<Args>(args)...);
|
||||
#endif
|
||||
//#endif
|
||||
}
|
||||
template <typename... Args>
|
||||
inline void DebugTraceInfo(Args &&... args)
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace asst {
|
||||
static bool reload();
|
||||
static std::string getCurDir();
|
||||
static std::string getResDir();
|
||||
static json::object dataObj;
|
||||
static json::object handleObj;
|
||||
static json::object optionsObj;
|
||||
static json::object tasksJson;
|
||||
static json::object handleJson;
|
||||
static json::object optionsJson;
|
||||
private:
|
||||
Configer() = default;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
|
||||
namespace asst {
|
||||
|
||||
@@ -16,15 +17,25 @@ namespace asst {
|
||||
Identify() = default;
|
||||
~Identify() = default;
|
||||
|
||||
void setUseCache(bool b) noexcept;
|
||||
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);
|
||||
// return tuple< algorithmType, suitability, scaled asst::rect>
|
||||
std::tuple<int, double, asst::Rect> findImage(const cv::Mat& image, const std::string& templ, double threshold = 0.99);
|
||||
|
||||
private:
|
||||
cv::Mat image2Hist(const cv::Mat& src);
|
||||
double imageHistComp(const cv::Mat& src, const cv::MatND& hist);
|
||||
asst::Rect cvRect2Rect(const cv::Rect& cvRect) {
|
||||
return asst::Rect(cvRect.x, cvRect.y, cvRect.width, cvRect.height);
|
||||
}
|
||||
|
||||
// return pair< suitability, raw opencv::point>
|
||||
std::pair<double, cv::Point> findImage(const cv::Mat& cur, const cv::Mat& templ);
|
||||
|
||||
std::unordered_map<std::string, cv::Mat> m_matMap;
|
||||
bool m_use_cache = true;
|
||||
std::unordered_map<std::string, std::pair<cv::Rect, cv::Mat>> m_cacheMap;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -11,10 +11,11 @@ Assistance::Assistance()
|
||||
Configer::reload();
|
||||
|
||||
m_Ider = std::make_shared<Identify>();
|
||||
for (auto&& pair : Configer::dataObj)
|
||||
for (auto&& pair : Configer::tasksJson)
|
||||
{
|
||||
m_Ider->addImage(pair.first, Configer::getResDir() + pair.second["filename"].as_string());
|
||||
}
|
||||
m_Ider->setUseCache(Configer::optionsJson["cache"].as_boolean());
|
||||
|
||||
m_working_thread = std::thread(working_proc, this);
|
||||
|
||||
@@ -50,7 +51,7 @@ std::optional<std::string> Assistance::setSimulator(const std::string& simulator
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
if (simulator_name.empty()) {
|
||||
for (auto&& [name, value] : Configer::handleObj)
|
||||
for (auto&& [name, value] : Configer::handleJson)
|
||||
{
|
||||
ret = create_handles(name);
|
||||
if (ret) {
|
||||
@@ -72,8 +73,13 @@ std::optional<std::string> Assistance::setSimulator(const std::string& simulator
|
||||
|
||||
void Assistance::start()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_thread_running) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_next_tasks.clear();
|
||||
m_next_tasks.emplace_back("Begin");
|
||||
m_thread_running = true;
|
||||
m_condvar.notify_one();
|
||||
}
|
||||
@@ -83,6 +89,7 @@ void Assistance::stop()
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
m_thread_running = false;
|
||||
m_next_tasks.clear();
|
||||
}
|
||||
|
||||
void Assistance::working_proc(Assistance* pThis)
|
||||
@@ -91,68 +98,51 @@ void Assistance::working_proc(Assistance* pThis)
|
||||
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;
|
||||
for (auto&& pair : Configer::dataObj) {
|
||||
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;
|
||||
}
|
||||
|
||||
std::string matched_task;
|
||||
Rect matched_rect;
|
||||
for (auto&& task_jstr : pThis->m_next_tasks) {
|
||||
std::string task_name = task_jstr.as_string();
|
||||
double threshold = Configer::tasksJson[task_name]["threshold"].as_double();
|
||||
auto&& [algorithm, value, rect] = pThis->m_Ider->findImage(curImg, task_name, threshold);
|
||||
DebugTrace("%-20s %f", task_name.c_str(), value);
|
||||
if ( algorithm == 0 ||
|
||||
(algorithm == 1 && value >= threshold)
|
||||
|| (algorithm == 2 && value >= 0.9999)) {
|
||||
matched_task = task_name;
|
||||
matched_rect = rect;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (max_value >= 0) {
|
||||
auto task = Configer::dataObj[matched.first].as_object();
|
||||
|
||||
if (!matched_task.empty()) {
|
||||
auto task = Configer::tasksJson[matched_task].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);
|
||||
DebugTraceInfo("Matched: %s, type: %s", matched_task.c_str(), opType.c_str());
|
||||
|
||||
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;
|
||||
if (opType == "clickSelf") {
|
||||
pThis->m_pCtrl->clickRange(matched_rect);
|
||||
}
|
||||
else if (opType == "clickRand") {
|
||||
pThis->m_pCtrl->clickRange(pThis->m_pCtrl->getWindowRect());
|
||||
}
|
||||
else if (opType == "doNothing") {
|
||||
// do nothing
|
||||
}
|
||||
else if (opType == "stop") {
|
||||
DebugTrace("opType == stop");
|
||||
pThis->m_thread_running = false;
|
||||
pThis->m_next_tasks.clear();
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
DebugTraceError("Unknow option type: %s", opType.c_str());
|
||||
}
|
||||
|
||||
pThis->m_next_tasks = Configer::tasksJson[matched_task]["next"].as_array();
|
||||
DebugTrace("Next: %s", pThis->m_next_tasks.to_string().c_str());
|
||||
}
|
||||
pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(Configer::optionsObj["delay"].as_integer()));
|
||||
pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(Configer::optionsJson["delay"]["fixedTime"].as_integer()));
|
||||
}
|
||||
else {
|
||||
pThis->m_condvar.wait(lock);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
using namespace asst;
|
||||
|
||||
json::object Configer::dataObj;
|
||||
json::object Configer::handleObj;
|
||||
json::object Configer::optionsObj;
|
||||
json::object Configer::tasksJson;
|
||||
json::object Configer::handleJson;
|
||||
json::object Configer::optionsJson;
|
||||
|
||||
std::string Configer::m_curDir;
|
||||
|
||||
@@ -32,9 +32,9 @@ bool Configer::reload()
|
||||
}
|
||||
|
||||
auto root = std::move(ret).value();
|
||||
dataObj = root["data"].as_object();
|
||||
handleObj = root["handle"].as_object();
|
||||
optionsObj = root["options"].as_object();
|
||||
tasksJson = root["tasks"].as_object();
|
||||
handleJson = root["handle"].as_object();
|
||||
optionsJson = root["options"].as_object();
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "Identify.h"
|
||||
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/imgproc/types_c.h>
|
||||
|
||||
@@ -17,12 +16,21 @@ bool Identify::addImage(const std::string& name, const std::string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
double Identify::imgHistComp(const cv::Mat& lhs, const cv::Mat& rhs)
|
||||
void Identify::setUseCache(bool b) noexcept
|
||||
{
|
||||
cv::Mat lhs_hsv;
|
||||
cv::Mat rhs_hsv;
|
||||
cvtColor(lhs, lhs_hsv, COLOR_BGR2HSV);
|
||||
cvtColor(rhs, rhs_hsv, COLOR_BGR2HSV);
|
||||
if (b) {
|
||||
m_use_cache = true;
|
||||
}
|
||||
else {
|
||||
m_cacheMap.clear();
|
||||
m_use_cache = false;
|
||||
}
|
||||
}
|
||||
|
||||
Mat Identify::image2Hist(const cv::Mat& src)
|
||||
{
|
||||
Mat src_hsv;
|
||||
cvtColor(src, src_hsv, COLOR_BGR2HSV);
|
||||
|
||||
int histSize[] = { 50, 60 };
|
||||
float h_ranges[] = { 0, 180 };
|
||||
@@ -30,31 +38,23 @@ double Identify::imgHistComp(const cv::Mat& lhs, const cv::Mat& rhs)
|
||||
const float* ranges[] = { h_ranges, s_ranges };
|
||||
int channels[] = { 0, 1 };
|
||||
|
||||
MatND lhs_hist;
|
||||
MatND rhs_hist;
|
||||
MatND src_hist;
|
||||
|
||||
calcHist(&lhs_hsv, 1, channels, Mat(), lhs_hist, 2, histSize, ranges);
|
||||
normalize(lhs_hist, lhs_hist, 0, 1, NORM_MINMAX);
|
||||
calcHist(&src_hsv, 1, channels, Mat(), src_hist, 2, histSize, ranges);
|
||||
normalize(src_hist, src_hist, 0, 1, NORM_MINMAX);
|
||||
|
||||
calcHist(&rhs_hsv, 1, channels, Mat(), rhs_hist, 2, histSize, ranges);
|
||||
normalize(rhs_hist, rhs_hist, 0, 1, NORM_MINMAX);
|
||||
|
||||
return compareHist(lhs_hist, rhs_hist, CV_COMP_CORREL);
|
||||
return src_hist;
|
||||
}
|
||||
|
||||
double Identify::imgHistComp(const cv::Mat& cur, const std::string& src, asst::Rect compRect)
|
||||
double Identify::imageHistComp(const cv::Mat& src, const cv::MatND& hist)
|
||||
{
|
||||
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));
|
||||
return compareHist(image2Hist(src), hist, CV_COMP_CORREL);
|
||||
}
|
||||
|
||||
std::pair<double, asst::Rect> Identify::findImage(const cv::Mat& image, const cv::Mat& templ)
|
||||
std::pair<double, cv::Point> Identify::findImage(const cv::Mat& image, const cv::Mat& templ)
|
||||
{
|
||||
cv::Mat image_hsv;
|
||||
cv::Mat templ_hsv;
|
||||
Mat image_hsv;
|
||||
Mat templ_hsv;
|
||||
cvtColor(image, image_hsv, COLOR_BGR2HSV);
|
||||
cvtColor(templ, templ_hsv, COLOR_BGR2HSV);
|
||||
|
||||
@@ -64,18 +64,36 @@ std::pair<double, asst::Rect> Identify::findImage(const cv::Mat& image, const cv
|
||||
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) };
|
||||
return { maxVal, maxLoc };
|
||||
}
|
||||
|
||||
std::pair<double, asst::Rect> Identify::findImage(const cv::Mat& cur, const std::string& templ)
|
||||
std::tuple<int, double, asst::Rect> Identify::findImage(const Mat& cur, const std::string& templ, double threshold)
|
||||
{
|
||||
if (m_matMap.find(templ) == m_matMap.end()) {
|
||||
return { 0, asst::Rect() };
|
||||
if (m_matMap.find(templ) == m_matMap.cend()) {
|
||||
return { 0, 0, asst::Rect() };
|
||||
}
|
||||
|
||||
if (m_use_cache && m_cacheMap.find(templ) != m_cacheMap.cend()) {
|
||||
DebugTrace("Identify | %s get cache", templ.c_str());
|
||||
auto&& [rect, hist] = m_cacheMap.at(templ);
|
||||
double value = imageHistComp(cur(rect), hist);
|
||||
return { 2, value, cvRect2Rect(rect).center_zoom(0.8) };
|
||||
}
|
||||
else {
|
||||
auto&& templ_mat = m_matMap.at(templ);
|
||||
auto&& [value, point] = findImage(cur, templ_mat);
|
||||
cv::Rect raw_rect(point.x, point.y, templ_mat.cols, templ_mat.rows);
|
||||
|
||||
if (m_use_cache && value >= threshold) {
|
||||
DebugTrace("Identify | %s add to cache", templ.c_str());
|
||||
m_cacheMap.emplace(templ, std::make_pair(raw_rect, image2Hist(cur(raw_rect))));
|
||||
}
|
||||
|
||||
return { 1, value, cvRect2Rect(raw_rect).center_zoom(0.8) };
|
||||
}
|
||||
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);
|
||||
@@ -84,3 +102,4 @@ std::pair<double, asst::Rect> Identify::findImageWithFile(const cv::Mat& cur, co
|
||||
}
|
||||
return findImage(cur, mat);
|
||||
}
|
||||
*/
|
||||
@@ -29,7 +29,7 @@ bool WinMacro::captured() const noexcept
|
||||
bool WinMacro::findHandle()
|
||||
{
|
||||
json::array handle_arr;
|
||||
json::value simulator_json = Configer::handleObj[m_simulator_name];
|
||||
json::value simulator_json = Configer::handleJson[m_simulator_name];
|
||||
switch (m_handle_type) {
|
||||
case HandleType::Window:
|
||||
m_width = simulator_json["Width"].as_integer();
|
||||
@@ -52,21 +52,32 @@ bool WinMacro::findHandle()
|
||||
m_handle = NULL;
|
||||
for (auto&& obj : handle_arr)
|
||||
{
|
||||
wchar_t* class_wbuff = NULL;
|
||||
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);
|
||||
|
||||
if (!class_str.empty()) {
|
||||
size_t class_len = (class_str.size() + 1) * 2;
|
||||
class_wbuff = new wchar_t[class_len];
|
||||
::MultiByteToWideChar(CP_UTF8, 0, class_str.c_str(), -1, class_wbuff, class_len);
|
||||
}
|
||||
wchar_t* window_wbuff = NULL;
|
||||
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);
|
||||
if (!window_str.empty()) {
|
||||
size_t window_len = (window_str.size() + 1) * 2;
|
||||
window_wbuff = new wchar_t[window_len];
|
||||
memset(window_wbuff, 0, window_len);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, window_str.c_str(), -1, window_wbuff, window_len);
|
||||
}
|
||||
|
||||
m_handle = ::FindWindowExW(m_handle, NULL, class_wbuff, window_wbuff);
|
||||
|
||||
delete[] class_wbuff;
|
||||
delete[] window_wbuff;
|
||||
if (class_wbuff != NULL) {
|
||||
delete[] class_wbuff;
|
||||
class_wbuff = NULL;
|
||||
}
|
||||
if (window_wbuff != NULL) {
|
||||
delete[] window_wbuff;
|
||||
window_wbuff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DebugTrace("Handle: 0x%x, Name: %s, Type: %d", m_handle, m_simulator_name.c_str(), m_handle_type);
|
||||
@@ -85,7 +96,10 @@ bool WinMacro::resizeWindow(int width, int height)
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::MoveWindow(m_handle, 0, 0, width / getScreenScale(), height / getScreenScale(), true);
|
||||
RECT rect;
|
||||
bool ret = ::GetWindowRect(m_handle, &rect);
|
||||
|
||||
return ret && ::MoveWindow(m_handle, rect.left, rect.top, width / getScreenScale(), height / getScreenScale(), true);
|
||||
}
|
||||
|
||||
bool WinMacro::resizeWindow()
|
||||
|
||||
44
README.md
44
README.md
@@ -2,16 +2,20 @@
|
||||
|
||||
A game assistance for Arknights
|
||||
|
||||
一款明日方舟的游戏辅助,龟速开发中……
|
||||
一款明日方舟的游戏辅助,供PC端安卓模拟器使用,龟速开发中……
|
||||
|
||||
## 功能介绍
|
||||
|
||||
- 目前版本支持自动刷完所有体力+自动吃完体力药
|
||||
- 刷完后程序会自动停止
|
||||
- 代理失败会自动放弃本次行动
|
||||
- 所有操作,都是点击按钮内随机位置,且模拟泊松分布,不会像鼠标宏一样一直是同一个点,没有封号风险
|
||||
~~(虽然好像也没听说过谁用鼠标宏被封号的)~~
|
||||
- 模拟器窗口可以被遮挡,即使全屏看视频、玩游戏,也完全不影响辅助运行
|
||||
~~(但是模拟器还是不能最小化)~~
|
||||
- 使用C++ WinAPI开发,效率高,对系统性能占用小
|
||||
- 目前版本支持自动刷完所有体力+自动吃完体力药
|
||||
- 支持多款主流模拟器
|
||||
- 自适应分辨率及屏幕缩放
|
||||
- 未来更多功能见[Todo](#Todo)
|
||||
|
||||
### 模拟器支持
|
||||
|
||||
@@ -37,11 +41,11 @@ A game assistance for Arknights
|
||||
|
||||
#### MuMu手游助手 && MuMu模拟器
|
||||
|
||||
不兼容,MuMu所有的句柄均不响应SendMessage鼠标消息,但官方提供了adb的方式进行控制,有时间再做
|
||||
不兼容,MuMu所有的窗口句柄均不响应SendMessage鼠标消息,但官方提供了adb的方式进行控制,有时间再做
|
||||
|
||||
## 使用说明
|
||||
|
||||
1. 使用蓝叠模拟器打开明日方舟,进入有**蓝色的开始行动按钮**的界面,勾上代理指挥
|
||||
1. 使用支持的模拟器打开明日方舟,进入有**蓝色的开始行动按钮**的界面
|
||||
2. 解压压缩包,**使用管理员权限**,打开"Sanity.exe"
|
||||
3. 目前只有最基本的功能,刷完体力+体力药就会自动停了……
|
||||
|
||||
@@ -49,22 +53,30 @@ A game assistance for Arknights
|
||||
|
||||
~~在做了在做了.jpg~~
|
||||
|
||||
- [ ] 图形化界面
|
||||
- [ ] 功能
|
||||
- [x] 支持剿灭
|
||||
- [ ] 支持刷指定次数
|
||||
- [x] 支持使模拟器窗口不可见
|
||||
- [x] 自动吃体力药
|
||||
- [ ] 自动吃石头(根据设置,指定数量)
|
||||
- [ ] 代理失败的情况
|
||||
- [ ] 图形化界面
|
||||
- [ ] 刷理智
|
||||
- [x] 支持剿灭
|
||||
- [x] 支持使模拟器窗口不可见
|
||||
- [x] 自动吃体力药
|
||||
- [x] 代理失败的情况
|
||||
- [x] 支持等级提升
|
||||
- [x] 支持自动勾选代理指挥
|
||||
- [ ] 支持刷指定次数
|
||||
- [ ] 自动吃石头(根据设置,指定数量)
|
||||
- [ ] 支持凌晨4点更新数据
|
||||
- [ ] 结束界面自动截图,可用于上传企鹅物流
|
||||
- [ ] 持续监视理智,一有就自动刷掉
|
||||
- [x] 支持更多模拟器
|
||||
- [x] 支持等级提升
|
||||
- [ ] 支持凌晨4点更新数据
|
||||
- [ ] 信用访问
|
||||
- [ ] 基建收菜
|
||||
- [ ] 当前公招可能干员一览
|
||||
- [x] 算法
|
||||
- [x] 更换算法为找图,而不是当前的区域相似度对比
|
||||
- [ ] 优化算法效率
|
||||
- [x] 更换算法为模板匹配找图,而不是当前的区域相似度对比
|
||||
- [x] 优化算法效率,添加缓存功能
|
||||
- [x] 优化任务队列,减少不必要的计算
|
||||
- [x] 其他
|
||||
- [x] 尝试减小程序体积
|
||||
|
||||
|
||||
## 致谢
|
||||
|
||||
2
meojson
2
meojson
Submodule meojson updated: 6b854ac42b...b530ddcffa
BIN
resource/AbandonAction.png
Normal file
BIN
resource/AbandonAction.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
resource/PrtsErrorConfirm.png
Normal file
BIN
resource/PrtsErrorConfirm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 383 KiB |
BIN
resource/UsePrts.png
Normal file
BIN
resource/UsePrts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"version": 0.1,
|
||||
"version": 0.2,
|
||||
"options": {
|
||||
"delay": 2000
|
||||
"delay": {
|
||||
"type": "fixedTime",
|
||||
"fixedTime": 2000
|
||||
},
|
||||
"cache": true
|
||||
},
|
||||
"handle": {
|
||||
"BlueStacks": {
|
||||
@@ -15,7 +19,7 @@
|
||||
"window": "HOSTWND"
|
||||
},
|
||||
{
|
||||
"class": "WindowsForms10.Window.8.app.0.34f5582_r6_ad1",
|
||||
"class": "",
|
||||
"window": "BlueStacks Android PluginAndroid"
|
||||
}
|
||||
],
|
||||
@@ -145,42 +149,115 @@
|
||||
"yOffset": -42
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"Random": {
|
||||
"tasks": {
|
||||
"Begin": {
|
||||
"filename": "",
|
||||
"threshold": 0,
|
||||
"type": "clickRand"
|
||||
"type": "doNothing",
|
||||
"next": [
|
||||
"UsePrts",
|
||||
"StartButton1",
|
||||
"StartButton2",
|
||||
"PRTS",
|
||||
"UseMedicine",
|
||||
"UseStone",
|
||||
"PrtsErrorConfirm",
|
||||
"Random"
|
||||
]
|
||||
},
|
||||
"UseMedicine": {
|
||||
"filename": "UseMedicine.png",
|
||||
"UsePrts": {
|
||||
"filename": "UsePrts.png",
|
||||
"threshold": 0.97,
|
||||
"type": "clickSelf",
|
||||
"next": [
|
||||
"StartButton1"
|
||||
]
|
||||
},
|
||||
"StartButton1": {
|
||||
"filename": "StartButton1.png",
|
||||
"threshold": 0.94,
|
||||
"type": "clickSelf",
|
||||
"next": [
|
||||
"StartButton2",
|
||||
"UseMedicine",
|
||||
"UseStone"
|
||||
]
|
||||
},
|
||||
"StartButton2": {
|
||||
"id": 2,
|
||||
"filename": "StartButton2.png",
|
||||
"threshold": 0.99,
|
||||
"type": "next",
|
||||
"next": {
|
||||
"name": "MedicineConfirm",
|
||||
"filename": "MedicineConfirm.png",
|
||||
"threshold": 0.99,
|
||||
"type": "clickSelf"
|
||||
}
|
||||
"type": "clickSelf",
|
||||
"next": [
|
||||
"PRTS"
|
||||
]
|
||||
},
|
||||
"PRTS": {
|
||||
"filename": "PRTS.png",
|
||||
"threshold": 0.98,
|
||||
"type": "doNothing"
|
||||
"type": "doNothing",
|
||||
"next": [
|
||||
"PRTS",
|
||||
"PrtsErrorConfirm",
|
||||
"Random"
|
||||
]
|
||||
},
|
||||
"Random": {
|
||||
"filename": "",
|
||||
"threshold": 0,
|
||||
"type": "clickRand",
|
||||
"next": [
|
||||
"StartButton1",
|
||||
"Random"
|
||||
]
|
||||
},
|
||||
"UseMedicine": {
|
||||
"filename": "UseMedicine.png",
|
||||
"threshold": 0.99,
|
||||
"type": "doNothing",
|
||||
"next": [
|
||||
"MedicineConfirm"
|
||||
]
|
||||
},
|
||||
"MedicineConfirm": {
|
||||
"filename": "MedicineConfirm.png",
|
||||
"threshold": 0.98,
|
||||
"type": "clickSelf",
|
||||
"next": [
|
||||
"StartButton1"
|
||||
]
|
||||
},
|
||||
"UseStone": {
|
||||
"filename": "UseStone.png",
|
||||
"threshold": 0.99,
|
||||
"type": "stop"
|
||||
"type": "stop",
|
||||
"next": [
|
||||
"StoneConfirm"
|
||||
]
|
||||
},
|
||||
"StartButton1": {
|
||||
"filename": "StartButton1.png",
|
||||
"threshold": 0.99,
|
||||
"type": "clickSelf"
|
||||
"StoneConfirm": {
|
||||
"filename": "MedicineConfirm.png",
|
||||
"threshold": 0.98,
|
||||
"type": "clickSelf",
|
||||
"next": [
|
||||
"StartButton1"
|
||||
]
|
||||
},
|
||||
"StartButton2": {
|
||||
"filename": "StartButton2.png",
|
||||
"threshold": 0.99,
|
||||
"type": "clickSelf"
|
||||
"PrtsErrorConfirm": {
|
||||
"filename": "PrtsErrorConfirm.png",
|
||||
"threshold": 0.98,
|
||||
"type": "doNothing",
|
||||
"next": [
|
||||
"AbandonAction"
|
||||
]
|
||||
},
|
||||
"AbandonAction": {
|
||||
"filename": "AbandonAction.png",
|
||||
"threshold": 0.98,
|
||||
"type": "clickSelf",
|
||||
"next": [
|
||||
"Random"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user