Compare commits

...

62 Commits

Author SHA1 Message Date
MistEO
b885d722b1 更新版本号beta 04 2021-07-28 01:05:36 +08:00
MistEO
4801cdf17d 修复一处图片尺寸及点击位置不正确的问题 2021-07-28 00:55:35 +08:00
MistEO
a496bb1fc8 update config 2021-07-27 00:56:47 +08:00
MistEO
ab5b4dd072 update resource 2021-07-26 19:14:26 +08:00
MistEO
0908d0e381 update log 2021-07-25 22:32:16 +08:00
MistEO
2e16d76569 Update README.md 2021-07-25 22:16:41 +08:00
MistEO
0b622e1313 更新GUI,完成自动关机功能 2021-07-25 22:03:15 +08:00
MistEO
ba104a0705 优化截图裁剪,再额外多裁剪一圈 2021-07-25 21:37:49 +08:00
MistEO
3c9f41ae4b 更新界面布局 2021-07-25 16:56:49 +08:00
MistEO
8a08223ab9 新增关机按钮的GUI,功能还没做 2021-07-25 16:52:50 +08:00
MistEO
47299fec45 更新版本号beat.03 2021-07-25 16:23:17 +08:00
MistEO
b683ca52d5 update 2021-07-25 16:21:02 +08:00
MistEO
b95f1f2dc9 更新资源图片,和VS工程文件 2021-07-25 16:11:20 +08:00
MistEO
423d538a80 更新模拟器适配 2021-07-25 14:48:27 +08:00
MistEO
eb6eb55161 兼容MuMu模拟器 2021-07-25 03:02:14 +08:00
MistEO
a195f559b8 优化分辨率自适应,现在不强制调整窗口大小了 2021-07-25 00:17:53 +08:00
MistEO
b5776d33b0 添加注释 2021-07-24 19:37:14 +08:00
MistEO
63aa3575c6 update readme 2021-07-24 18:05:23 +08:00
MistEO
41f56a6e6b update readme 2021-07-24 17:51:47 +08:00
MistEO
8e0430f773 update adb control 2021-07-24 17:41:46 +08:00
MistEO
94c81eb60f update screenshot 2021-07-24 16:52:08 +08:00
MistEO
3eb0328630 rename some function and variable 2021-07-24 16:23:36 +08:00
MistEO
78187cb9c7 update readme 2021-07-24 01:28:26 +08:00
MistEO
d1826e8664 support to print window, and fixed crash when window closed or miniized 2021-07-24 01:25:12 +08:00
MistEO
40b4751616 restructure configer, improve thread safety 2021-07-23 23:48:00 +08:00
MistEO
a01e50571b Update README.md 2021-07-23 16:32:24 +08:00
MistEO
4b244b3aef fixed readme 2021-07-23 00:03:26 +08:00
MistEO
e05430ec0e update version id 2021-07-22 23:48:32 +08:00
MistEO
0a081d4fa2 update readme 2021-07-22 23:45:20 +08:00
MistEO
a6488f0ea6 rename config json key 2021-07-22 22:56:06 +08:00
MistEO
8844d35c2e support control random delay 2021-07-22 22:54:58 +08:00
MistEO
0534e35871 update threshold 2021-07-22 21:47:20 +08:00
MistEO
107d3af5c5 header file unlooping 2021-07-22 21:46:32 +08:00
MistEO
1e170e6c1a fixed some warning, update logger 2021-07-22 19:40:25 +08:00
MistEO
f3773d22c6 update log and config 2021-07-22 10:07:40 +08:00
MistEO
7928a21051 update updater gui 2021-07-22 02:16:53 +08:00
MistEO
2a89b01c1b fixed gui 2021-07-22 02:00:51 +08:00
MistEO
d735404766 add log 2021-07-22 01:07:12 +08:00
MistEO
a8173eb82c fixed count error when use stone or medicine 2021-07-22 00:39:13 +08:00
MistEO
67f52b321c update log 2021-07-21 23:43:47 +08:00
MistEO
6c3540b692 move readme.png to resource 2021-07-21 20:40:54 +08:00
MistEO
dd556817ea update version id 2021-07-21 20:36:29 +08:00
MistEO
c393da2046 Merge pull request #3 from MistEO/feature/new_algorithm
Feature/new algorithm
2021-07-21 20:17:11 +08:00
MistEO
5657af6d94 update config and something 2021-07-21 20:16:33 +08:00
MistEO
f35ef18bd2 add log 2021-07-21 20:16:02 +08:00
MistEO
0fef8e2174 merge "Updater interface modified" 2021-07-21 02:05:23 +08:00
MistEO
ee3afb440e modified the interface of Updater, because VS2019 's O2 optimzation is not friendly to std::optional 2021-07-21 01:43:58 +08:00
MistEO
952861c1e5 update icon and window title 2021-07-20 23:51:47 +08:00
MistEO
dab705a3de fixed bug: process cannot exit 2021-07-20 23:37:27 +08:00
MistEO
17f8353a97 fixed bug: process cannot exit 2021-07-20 23:36:57 +08:00
MistEO
53a1297842 update task sleep logic 2021-07-20 23:29:01 +08:00
MistEO
e589a7498c update identify algorithm 2021-07-20 23:17:10 +08:00
MistEO
ca412965ca add icon for GUI 2021-07-20 21:50:26 +08:00
MistEO
adfed6d276 update release body 2021-07-20 00:50:34 +08:00
MistEO
6fddf69e67 add function of check version update 2021-07-20 00:12:00 +08:00
MistEO
fb3cbb0b7a add set max times function 2021-07-19 21:22:35 +08:00
MistEO
a348139df5 update configer 2021-07-18 23:22:47 +08:00
MistEO
08db7f008d Merge branch 'master' of https://github.com/MistEO/MeoAssistance 2021-07-18 17:43:25 +08:00
MistEO
d66f178aec update gui, add use stone label 2021-07-18 17:43:16 +08:00
MistEO
d51882fd1c Update README.md 2021-07-18 17:29:09 +08:00
MistEO
c7b80b4603 support to MuMu (not MuMuAsst) 2021-07-18 15:19:15 +08:00
MistEO
1a0add784d try to supoort MuMu 2021-07-18 02:40:57 +08:00
52 changed files with 1808 additions and 451 deletions

View File

@@ -13,71 +13,57 @@ EndProject
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}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeoAsstGui", "MeoAsstGui\MeoAsstGui.csproj", "{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
{9CC7838E-D5FB-4771-848D-5F83D638C5AD} = {9CC7838E-D5FB-4771-848D-5F83D638C5AD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Screenshot", "Tools\Screenshot\Screenshot.vcxproj", "{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B}"
ProjectSection(ProjectDependencies) = postProject
{362D1E30-F5AE-4279-9985-65C27B3BA300} = {362D1E30-F5AE-4279-9985-65C27B3BA300}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{6C4B8D52-51D1-45F8-AAEC-808035443FD6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdPart", "3rdPart", "{402D9F27-234E-41A9-BEB1-1FC1FA3C8825}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|Any CPU.ActiveCfg = Debug|Win32
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|x64.ActiveCfg = Debug|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|x64.Build.0 = Debug|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|x86.ActiveCfg = Debug|Win32
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Debug|x86.Build.0 = Debug|Win32
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|Any CPU.ActiveCfg = Release|Win32
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.ActiveCfg = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x64.Build.0 = Release|x64
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x86.ActiveCfg = Release|Win32
{362D1E30-F5AE-4279-9985-65C27B3BA300}.Release|x86.Build.0 = Release|Win32
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Debug|Any CPU.ActiveCfg = Debug|Win32
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Debug|x64.ActiveCfg = Debug|x64
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Debug|x64.Build.0 = Debug|x64
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Debug|x86.ActiveCfg = Debug|Win32
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Debug|x86.Build.0 = Debug|Win32
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Release|Any CPU.ActiveCfg = Release|Win32
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Release|x64.ActiveCfg = Release|x64
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Release|x64.Build.0 = Release|x64
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Release|x86.ActiveCfg = Release|Win32
{9CC7838E-D5FB-4771-848D-5F83D638C5AD}.Release|x86.Build.0 = Release|Win32
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Debug|Any CPU.ActiveCfg = Debug|Win32
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Debug|x64.ActiveCfg = Debug|x64
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Debug|x64.Build.0 = Debug|x64
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Debug|x86.ActiveCfg = Debug|Win32
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Debug|x86.Build.0 = Debug|Win32
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Release|Any CPU.ActiveCfg = Release|Win32
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Release|x64.ActiveCfg = Release|x64
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Release|x64.Build.0 = Release|x64
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Release|x86.ActiveCfg = Release|Win32
{36BC08F3-71CF-429A-AE69-291BE8962CB2}.Release|x86.Build.0 = Release|Win32
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|x64.ActiveCfg = Debug|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|x64.Build.0 = Debug|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|x86.ActiveCfg = Debug|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Debug|x86.Build.0 = Debug|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|Any CPU.Build.0 = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x64.Build.0 = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x86.ActiveCfg = Release|Any CPU
{FFDC8F49-8EAF-45BE-B0A8-7EF0DB9875A2}.Release|x86.Build.0 = Release|Any CPU
{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B}.Debug|x64.ActiveCfg = Debug|x64
{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B}.Debug|x64.Build.0 = Debug|x64
{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B}.Release|x64.ActiveCfg = Release|x64
{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9CC7838E-D5FB-4771-848D-5F83D638C5AD} = {402D9F27-234E-41A9-BEB1-1FC1FA3C8825}
{36BC08F3-71CF-429A-AE69-291BE8962CB2} = {6C4B8D52-51D1-45F8-AAEC-808035443FD6}
{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B} = {6C4B8D52-51D1-45F8-AAEC-808035443FD6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4F2C0E4B-4FE9-47C6-A878-6BD2FAD8B9B2}
EndGlobalSection

View File

@@ -20,10 +20,13 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\Assistance.h" />
<ClInclude Include="include\AsstAux.h" />
<ClInclude Include="include\AsstCaller.h" />
<ClInclude Include="include\AsstDef.h" />
<ClInclude Include="include\Configer.h" />
<ClInclude Include="include\Identify.h" />
<ClInclude Include="include\Logger.hpp" />
<ClInclude Include="include\Updater.h" />
<ClInclude Include="include\WinMacro.h" />
</ItemGroup>
<ItemGroup>
@@ -31,6 +34,7 @@
<ClCompile Include="src\AsstCaller.cpp" />
<ClCompile Include="src\Configer.cpp" />
<ClCompile Include="src\Identify.cpp" />
<ClCompile Include="src\Updater.cpp" />
<ClCompile Include="src\WinMacro.cpp" />
</ItemGroup>
<ItemGroup>
@@ -145,7 +149,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>opencv_world452d.lib;libmeojson.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>opencv_world452d.lib;libmeojson.lib;WinInet.Lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<AdditionalLibraryDirectories>$(TargetDir)</AdditionalLibraryDirectories>
</Link>
@@ -177,7 +181,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>opencv_core452.lib;opencv_imgcodecs452.lib;opencv_imgproc452.lib;libmeojson.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>opencv_core452.lib;opencv_imgcodecs452.lib;opencv_imgproc452.lib;WinInet.Lib;libmeojson.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<AdditionalLibraryDirectories>$(TargetDir)</AdditionalLibraryDirectories>
</Link>
@@ -197,7 +201,7 @@
</ImportGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties _1_1_4resource_4config_1json__JsonSchema="https://beaujs.com/schema.json" />
<UserProperties _1_1_4resource_4config_1json__JsonSchema="" />
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@@ -33,6 +33,15 @@
<ClInclude Include="include\AsstCaller.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\Updater.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\Logger.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\AsstAux.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Configer.cpp">
@@ -50,6 +59,9 @@
<ClCompile Include="src\AsstCaller.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\Updater.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\resource\config.json">

View File

@@ -8,6 +8,11 @@
#include <unordered_map>
#include "AsstDef.h"
#include "Configer.h"
namespace cv {
class Mat;
}
namespace asst {
class WinMacro;
@@ -19,15 +24,20 @@ namespace asst {
Assistance();
~Assistance();
std::optional<std::string> setSimulator(const std::string & simulator_name = std::string());
void start(const std::string & task);
void stop();
std::optional<std::string> set_emulator(const std::string& emulator_name = std::string());
bool setParam(const std::string& type, const std::string& param, const std::string& value);
void start(const std::string& task);
void stop(bool block = true);
bool set_param(const std::string& type, const std::string& param, const std::string& value);
std::optional<std::string> get_param(const std::string& type, const std::string& param);
bool print_window(const std::string& filename, bool block = true);
private:
static void workingProc(Assistance* pThis);
static void working_proc(Assistance* pThis);
// pair<scale, image>
cv::Mat get_format_image(bool need_set_scale = true);
std::shared_ptr<WinMacro> m_pWindow = nullptr;
std::shared_ptr<WinMacro> m_pView = nullptr;
@@ -41,6 +51,8 @@ namespace asst {
bool m_thread_exit = false;
bool m_thread_running = false;
std::vector<std::string> m_next_tasks;
Configer m_configer;
};
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <string>
#include <Windows.h>
namespace asst {
static std::string GetCurrentDir()
{
static std::string cur_dir;
if (cur_dir.empty()) {
char exepath_buff[_MAX_PATH] = { 0 };
::GetModuleFileNameA(NULL, exepath_buff, _MAX_PATH);
std::string exepath(exepath_buff);
cur_dir = exepath.substr(0, exepath.find_last_of('\\') + 1);
}
return cur_dir;
}
static std::string GetResourceDir()
{
static std::string res_dir = GetCurrentDir() + "resource\\";
return res_dir;
}
static std::string StringReplaceAll(const std::string& src, const std::string& old_value, const std::string& new_value)
{
std::string str = src;
for (std::string::size_type pos(0); pos != std::string::npos; pos += new_value.length()) {
if ((pos = str.find(old_value, pos)) != std::string::npos)
str.replace(pos, old_value.length(), new_value);
else
break;
}
return str;
}
static std::string GetFormatTimeString()
{
SYSTEMTIME curtime;
GetLocalTime(&curtime);
char buff[64] = { 0 };
sprintf_s(buff, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
curtime.wYear, curtime.wMonth, curtime.wDay,
curtime.wHour, curtime.wMinute, curtime.wSecond, curtime.wMilliseconds);
return buff;
}
}

View File

@@ -8,10 +8,12 @@ extern "C" {
extern __declspec(dllexport) asst::Assistance* CreateAsst();
extern __declspec(dllexport) void DestoryAsst(asst::Assistance* p_asst);
extern __declspec(dllexport) bool AsstCatchSimulator(asst::Assistance* p_asst);
extern __declspec(dllexport) bool AsstCatchEmulator(asst::Assistance* p_asst);
extern __declspec(dllexport) void AsstStart(asst::Assistance* p_asst, const char* task);
extern __declspec(dllexport) void AsstStop(asst::Assistance* p_asst);
extern __declspec(dllexport) bool AsstSetParam(asst::Assistance* p_asst, const char* type, const char* param, const char* value);
extern __declspec(dllexport) bool AsstGetParam(asst::Assistance* p_asst, const char* type, const char* param, char * buffer, int buffer_size);
extern __declspec(dllexport) bool CheckVersionUpdate(char * tag_buffer, int tag_bufsize, char * html_url_buffer, int html_bufsize, char * body_buffer, int body_bufsize);
#ifdef __cplusplus
}

View File

@@ -1,13 +1,14 @@
#pragma once
#include <mutex>
#include <iostream>
#include <fstream>
#include <sstream>
#include <process.h>
#include <Windows.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <ostream>
namespace asst {
const static std::string Version = "release.beta.04";
enum class HandleType
{
Window = 1,
@@ -15,6 +16,60 @@ namespace asst {
Control = 4
};
static std::ostream& operator<<(std::ostream& os, const HandleType& type)
{
static std::unordered_map<HandleType, std::string> _type_name = {
{HandleType::Window, "Window"},
{HandleType::View, "View"},
{HandleType::Control, "Control"}
};
return os << _type_name.at(type);
}
enum class TaskType {
Invalid = 0,
BasicClick = 1,
DoNothing = 2,
Stop = 4,
PrintWindow,
ClickSelf = 8 | BasicClick,
ClickRect = 16 | BasicClick,
ClickRand = 32 | BasicClick
};
static bool operator&(const TaskType& lhs, const TaskType& rhs)
{
return static_cast<std::underlying_type<TaskType>::type>(lhs) & static_cast<std::underlying_type<TaskType>::type>(rhs);
}
static std::ostream& operator<<(std::ostream& os, const TaskType& task)
{
static std::unordered_map<TaskType, std::string> _type_name = {
{TaskType::Invalid, "Invalid"},
{TaskType::BasicClick, "BasicClick"},
{TaskType::ClickSelf, "ClickSelf"},
{TaskType::ClickRect, "ClickRect"},
{TaskType::ClickRand, "ClickRand"},
{TaskType::DoNothing, "DoNothing"},
{TaskType::Stop, "Stop"},
{TaskType::PrintWindow, "PrintWindow"}
};
return os << _type_name.at(task);
}
enum class AlgorithmType {
JustReturn,
MatchTemplate,
CompareHist
};
static std::ostream& operator<<(std::ostream& os, const AlgorithmType& type)
{
static std::unordered_map<AlgorithmType, std::string> _type_name = {
{AlgorithmType::JustReturn, "JustReturn"},
{AlgorithmType::MatchTemplate, "MatchTemplate"},
{AlgorithmType::CompareHist, "CompareHist"}
};
return os << _type_name.at(type);
}
struct Point
{
Point() = default;
@@ -32,7 +87,7 @@ namespace asst {
{
return { x, y, static_cast<int>(width * rhs), static_cast<int>(height * rhs) };
}
Rect center_zoom(double scale)
Rect center_zoom(double scale) const
{
int half_width_scale = static_cast<int>(width * (1 - scale) / 2);
int half_hight_scale = static_cast<int>(height * (1 - scale) / 2);
@@ -44,70 +99,58 @@ namespace asst {
int height = 0;
};
static std::string GetCurrentDir()
{
static std::string cur_dir;
if (cur_dir.empty()) {
char exepath_buff[_MAX_PATH] = { 0 };
::GetModuleFileNameA(NULL, exepath_buff, _MAX_PATH);
std::string exepath(exepath_buff);
cur_dir = exepath.substr(0, exepath.find_last_of('\\') + 1);
}
return cur_dir;
}
static std::string GetResourceDir()
{
static std::string res_dir = GetCurrentDir() + "resource\\";
return res_dir;
}
struct HandleInfo {
std::string class_name;
std::string window_name;
};
inline void StreamArgs(std::ostream& os)
{
os << std::endl;
}
template <typename T, typename... Args>
inline void StreamArgs(std::ostream& os, T&& first, Args && ...rest)
{
os << first << " ";
StreamArgs(os, std::forward<Args>(rest)...);
}
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);
#ifdef _DEBUG
auto & out_stream = std::cout;
#else
std::ofstream out_stream(GetCurrentDir() + "asst.log", std::ios::out | std::ios::app);
#endif
struct AdbCmd {
std::string path;
std::string connect;
std::string click;
std::string display;
std::string display_regex;
int display_width = 0;
int display_height = 0;
};
SYSTEMTIME curtime;
GetLocalTime(&curtime);
char buff[64] = { 0 };
sprintf_s(buff, "[%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());
struct EmulatorInfo {
std::string name;
std::vector<HandleInfo> window;
std::vector<HandleInfo> view;
std::vector<HandleInfo> control;
bool is_adb = false;
AdbCmd adb;
int width = 0;
int height = 0;
int x_offset = 0;
int y_offset = 0;
int right_offset = 0;
int bottom_offset = 0;
};
StreamArgs(out_stream, buff, std::forward<Args>(args)...);
}
struct TaskInfo {
std::string filename; // 图片文件名
double threshold = 0; // 模板匹配阈值
double cache_threshold = 0; // 直方图比较阈值
TaskType type = TaskType::Invalid; // 任务类型
std::vector<std::string> next; // 下一个可能的任务(列表)
int exec_times = 0; // 任务已执行了多少次
int max_times = INT_MAX; // 任务最多执行多少次
std::vector<std::string> exceeded_next; // 达到最多次数了之后,下一个可能的任务(列表)
std::vector<std::string> reduce_other_times; // 执行了该任务后,需要减少别的任务的执行次数。例如执行了吃理智药,则说明上一次点击蓝色开始行动按钮没生效,所以蓝色开始行动要-1
asst::Rect specific_area; // 指定区域目前仅针对ClickRect任务有用会点这个区域
int pre_delay = 0; // 执行该任务前的延时
int rear_delay = 0; // 执行该任务后的延时
};
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)...);
}
struct Options {
bool identify_cache = false; // 图像识别缓存功能开启后可以大幅降低CPU消耗但需要保证要识别的按钮每次的位置不会改变
int identify_delay = 0; // 图像识别延时越快操作越快但会增加CPU消耗
int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时
int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时
bool print_window = false; // 截图功能开启后每次结算界面会截图到screenshot目录下
int print_window_delay = 0; // 截图延时:每次到结算界面,掉落物品不是一次性出来的,有个动画,所以需要等一会再截图
int print_window_crop_offset = 0; // 截图额外裁剪:再额外把边框裁减掉一圈,不然企鹅物流有可能识别不出来
};
}

View File

@@ -2,65 +2,42 @@
#include <string>
#include <unordered_map>
#include <vector>
#include <optional>
#include "AsstDef.h"
namespace asst {
struct HandleInfo {
std::string className;
std::string windowName;
};
struct SimulatorInfo {
std::vector<HandleInfo> window;
std::vector<HandleInfo> view;
std::vector<HandleInfo> control;
int width = 0;
int height = 0;
int xOffset = 0;
int yOffset = 0;
};
enum class TaskType {
ClickSelf,
ClickRand,
DoNothing,
Stop,
ClickRect
};
struct TaskInfo {
std::string filename;
double threshold = 0;
TaskType type;
std::vector<std::string> next;
int exec_times = 0;
int max_times = INT_MAX;
asst::Rect specific_area;
int pre_delay = 0;
int rear_delay = 0;
};
struct Options {
std::string delayType;
int delayFixedTime = 0;
bool cache = false;
};
class Configer
{
public:
Configer() = default;
~Configer() = default;
static bool reload();
Configer(const Configer& rhs);
Configer(Configer&& rhs) noexcept;
static std::string m_version;
static Options m_options;
static std::unordered_map<std::string, TaskInfo> m_tasks;
static std::unordered_map<std::string, SimulatorInfo> m_handles;
bool reload(const std::string& filename);
bool set_param(const std::string& type, const std::string& param, const std::string& value);
std::optional<std::string> get_param(const std::string& type, const std::string& param);
void clear_exec_times();
Configer& operator=(const Configer& rhs);
Configer& operator=(Configer&& rhs) noexcept;
constexpr static int DefaultWindowWidth = 1280;
constexpr static int DefaultWindowHeight = 720;
constexpr static double DefaultThreshold = 0.9;
constexpr static double DefaultCacheThreshold = 0.9;
std::string m_version;
Options m_options;
std::unordered_map<std::string, TaskInfo> m_tasks;
std::unordered_map<std::string, EmulatorInfo> m_handles;
static bool setParam(const std::string& type, const std::string& param, const std::string& value);
private:
Configer() = default;
static std::string m_curDir;
};
}

View File

@@ -1,11 +1,12 @@
#pragma once
#include "AsstDef.h"
#include <opencv2/opencv.hpp>
#include <unordered_map>
#include <utility>
#include <tuple>
#include <opencv2/opencv.hpp>
#include "AsstDef.h"
namespace asst {
@@ -17,26 +18,26 @@ namespace asst {
Identify() = default;
~Identify() = default;
void setUseCache(bool b) noexcept;
bool addImage(const std::string& name, const std::string& path);
void set_use_cache(bool b) noexcept;
bool add_image(const std::string& name, const std::string& path);
// 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);
std::tuple<AlgorithmType, double, asst::Rect> find_image(const cv::Mat& image, const std::string& templ, double threshold = 0.99);
void clear_cache();
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) {
cv::Mat image_2_hist(const cv::Mat& src);
double image_hist_comp(const cv::Mat& src, const cv::MatND& hist);
static asst::Rect cvrect_2_rect(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::pair<double, cv::Point> find_image(const cv::Mat& cur, const cv::Mat& templ);
std::unordered_map<std::string, cv::Mat> m_mat_map;
bool m_use_cache = true;
std::unordered_map<std::string, std::pair<cv::Rect, cv::Mat>> m_cache_map;
std::unordered_map<std::string, std::pair<cv::Rect, cv::Mat>> m_cache_map; // λÖá¢Ö±·½Í¼»º´æ
};
}

View File

@@ -0,0 +1,110 @@
#pragma once
#include <fstream>
#include <mutex>
#include <iostream>
#include "AsstAux.h"
#include "AsstDef.h"
namespace asst {
class Logger {
public:
~Logger() = default;
Logger(const Logger&) = delete;
Logger(Logger&&) = delete;
static Logger& get_instance()
{
static Logger _unique_instance;
return _unique_instance;
}
template <typename... Args>
inline void log_trace(Args &&... args)
{
log("TRC", std::forward<Args>(args)...);
}
template <typename... Args>
inline void log_info(Args &&... args)
{
log("INF", std::forward<Args>(args)...);
}
template <typename... Args>
inline void log_error(Args &&... args)
{
log("ERR", std::forward<Args>(args)...);
}
private:
Logger() {
log_trace("-----------------------------");
log_trace("MeoAssistance Process Start");
log_trace("Version", Version);
log_trace("Build DataTime", __DATE__, __TIME__);
log_trace("Working Path", GetCurrentDir());
log_trace("Resource Path", GetResourceDir());
log_trace("-----------------------------");
}
template <typename... Args>
void log(const std::string& level, Args &&... args)
{
std::unique_lock<std::mutex> trace_lock(m_trace_mutex);
char buff[128] = { 0 };
sprintf_s(buff, "[%s][%s][Px%x][Tx%x]",
asst::GetFormatTimeString().c_str(),
level.c_str(), _getpid(), ::GetCurrentThreadId());
if (level == "ERR" || level == "INF"
#ifdef _DEBUG
|| level == "TRC"
#endif
) {
stream_args(std::cout, buff, std::forward<Args>(args)...);
}
std::ofstream out_stream(asst::GetCurrentDir() + "asst.log", std::ios::out | std::ios::app);
stream_args(out_stream, buff, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
inline void stream_args(std::ostream& os, T&& first, Args && ...rest)
{
os << first << " ";
stream_args(os, std::forward<Args>(rest)...);
}
inline void stream_args(std::ostream& os)
{
os << std::endl;
}
std::mutex m_trace_mutex;
};
class LoggerAux {
public:
LoggerAux(const std::string& func_name)
: m_func_name(func_name),
m_start_time(std::chrono::system_clock::now())
{
Logger::get_instance().log_trace(m_func_name, " | enter");
}
~LoggerAux()
{
auto duration = std::chrono::system_clock::now() - m_start_time;
Logger::get_instance().log_trace(m_func_name, " | leave,",
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(), "ms");
}
private:
std::string m_func_name;
std::chrono::time_point<std::chrono::system_clock> m_start_time;
};
}
#define DebugTrace Logger::get_instance().log_trace
#define DebugTraceInfo Logger::get_instance().log_info
#define DebugTraceError Logger::get_instance().log_error
#define DebugTraceFunction LoggerAux _func_aux(__FUNCTION__)

View File

@@ -0,0 +1,39 @@
#pragma once
#include <string>
#include <optional>
#include <mutex>
namespace asst {
struct __declspec(dllexport) VersionInfo {
std::string tag_name;
std::string html_url;
std::string down_url;
std::string author_name;
std::string created_time;
std::string body;
};
class __declspec(dllexport) Updater
{
static const std::string GithubReleaseLastestApiUrl;
static const std::string GithubReleaseApiUrl;
public:
~Updater() = default;
Updater(const Updater&) = delete;
Updater(Updater&&) = delete;
static Updater& get_instance();
bool has_new_version();
const VersionInfo & get_version_info() const noexcept;
private:
Updater() = default;
std::optional<std::string> request_github_api();
bool m_has_new_version = false;
VersionInfo m_lastest_version;
std::mutex m_mutex;
};
}

View File

@@ -2,16 +2,20 @@
#include <string>
#include <random>
#include <optional>
#include <Windows.h>
#include <opencv2/opencv.hpp>
#include "AsstDef.h"
namespace cv {
class Mat;
}
namespace asst {
class WinMacro
{
public:
WinMacro(const std::string & simulator_name, HandleType type);
WinMacro(const EmulatorInfo & info, HandleType type);
~WinMacro() = default;
bool captured() const noexcept;
@@ -20,20 +24,28 @@ namespace asst {
bool showWindow();
bool hideWindow();
bool click(const Point & p);
bool clickRange(const Rect & rect);
bool click(const Rect & rect);
void setControlScale(double scale);
cv::Mat getImage(const Rect& rect);
Rect getWindowRect();
const EmulatorInfo& getEmulatorInfo() const noexcept { return m_emulator_info; }
const HandleType& getHandleType() const noexcept { return m_handle_type; }
static double getScreenScale();
private:
bool findHandle();
std::optional<std::string> callCmd(const std::string& cmd, bool use_pipe = true);
const std::string m_simulator_name;
const EmulatorInfo m_emulator_info;
const HandleType m_handle_type;
HWND m_handle = NULL;
bool m_is_adb = false;
std::string m_click_cmd; // adb点击命令不是adb的句柄用不到这个
std::minstd_rand m_rand_engine;
int m_width = 0;
int m_height = 0;
int m_xOffset = 0;
int m_yOffset = 0;
//int m_x_offset = 0;
//int m_y_offset = 0;
double m_control_scale = 1;
};
}

View File

@@ -3,69 +3,82 @@
#include "WinMacro.h"
#include "Configer.h"
#include "Identify.h"
#include "Logger.hpp"
#include "AsstAux.h"
#include <opencv2/opencv.hpp>
#include <time.h>
#include <filesystem>
using namespace asst;
Assistance::Assistance()
{
Configer::reload();
DebugTraceFunction;
m_configer.reload(GetResourceDir() + "config.json");
m_pIder = std::make_shared<Identify>();
for (auto&& [name, info] : Configer::m_tasks)
for (auto&& [name, info] : m_configer.m_tasks)
{
m_pIder->addImage(name, GetResourceDir() + info.filename);
m_pIder->add_image(name, GetResourceDir() + info.filename);
}
m_pIder->setUseCache(Configer::m_options.cache);
m_working_thread = std::thread(workingProc, this);
m_pIder->set_use_cache(m_configer.m_options.identify_cache);
m_working_thread = std::thread(working_proc, this);
}
Assistance::~Assistance()
{
if (m_pWindow != nullptr) {
m_pWindow->showWindow();
}
DebugTraceFunction;
//if (m_pWindow != nullptr) {
// m_pWindow->showWindow();
//}
m_thread_exit = true;
m_thread_running = false;
m_condvar.notify_one();
m_condvar.notify_all();
if (m_working_thread.joinable()) {
m_working_thread.join();
}
}
std::optional<std::string> Assistance::setSimulator(const std::string& simulator_name)
std::optional<std::string> Assistance::set_emulator(const std::string& emulator_name)
{
DebugTraceFunction;
stop();
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);
auto create_handles = [&](const EmulatorInfo& info) -> bool {
m_pWindow = std::make_shared<WinMacro>(info, HandleType::Window);
m_pView = std::make_shared<WinMacro>(info, HandleType::View);
m_pCtrl = std::make_shared<WinMacro>(info, HandleType::Control);
return m_pWindow->captured() && m_pView->captured() && m_pCtrl->captured();
};
bool ret = false;
std::string cor_name = simulator_name;
std::string cor_name = emulator_name;
std::unique_lock<std::mutex> lock(m_mutex);
if (simulator_name.empty()) {
for (auto&& [name, value] : Configer::m_handles)
// 自动匹配模拟器,逐个找
if (emulator_name.empty()) {
for (auto&& [name, info] : m_configer.m_handles)
{
ret = create_handles(name);
ret = create_handles(info);
if (ret) {
cor_name = name;
break;
}
}
}
else {
ret = create_handles(simulator_name);
else { // 指定的模拟器
ret = create_handles(m_configer.m_handles[emulator_name]);
}
if (ret && m_pWindow->resizeWindow()) {
if (ret && m_pWindow->showWindow() && m_pWindow->resizeWindow()) {
m_inited = true;
return cor_name;
}
@@ -77,11 +90,17 @@ std::optional<std::string> Assistance::setSimulator(const std::string& simulator
void Assistance::start(const std::string& task)
{
DebugTraceFunction;
DebugTrace("Start |", task);
if (m_thread_running || !m_inited) {
return;
}
std::unique_lock<std::mutex> lock(m_mutex);
m_configer.clear_exec_times();
m_pIder->clear_cache();
m_next_tasks.clear();
m_next_tasks.emplace_back(task);
@@ -89,99 +108,256 @@ void Assistance::start(const std::string& task)
m_condvar.notify_one();
}
void Assistance::stop()
void Assistance::stop(bool block)
{
std::unique_lock<std::mutex> lock(m_mutex);
DebugTraceFunction;
DebugTrace("Stop |", block ? "block" : "non block");
std::unique_lock<std::mutex> lock;
if (block) { // 外部调用
lock = std::unique_lock<std::mutex>(m_mutex);
m_configer.clear_exec_times();
}
m_thread_running = false;
m_next_tasks.clear();
m_pIder->clear_cache();
}
bool Assistance::setParam(const std::string& type, const std::string& param, const std::string& value)
bool Assistance::set_param(const std::string& type, const std::string& param, const std::string& value)
{
return Configer::setParam(type, param, value);
DebugTraceFunction;
DebugTrace("SetParam |", type, param, value);
std::unique_lock<std::mutex> lock(m_mutex);
return m_configer.set_param(type, param, value);
}
void Assistance::workingProc(Assistance* pThis)
std::optional<std::string> Assistance::get_param(const std::string& type, const std::string& param)
{
// DebugTraceFunction;
if (type == "status") {
if (param == "running") {
return std::to_string(m_thread_running);
}
else {
return std::nullopt;
}
}
std::unique_lock<std::mutex> lock(m_mutex);
return m_configer.get_param(type, param);
}
bool asst::Assistance::print_window(const std::string& filename, bool block)
{
DebugTraceFunction;
DebugTrace("print_window |", block ? "block" : "non block");
std::unique_lock<std::mutex> lock;
if (block) { // 外部调用
lock = std::unique_lock<std::mutex>(m_mutex);
}
auto&& image = get_format_image();
// 保存的截图额外再裁剪掉一圈,不然企鹅物流识别不出来
int offset = m_configer.m_options.print_window_crop_offset;
cv::Rect rect(offset, offset, image.cols - offset * 2, image.rows - offset * 2);
bool ret = cv::imwrite(filename.c_str(), image(rect));
if (ret) {
DebugTraceInfo("PrintWindow to", filename);
}
else {
DebugTraceError("PrintWindow error", filename);
}
return ret;
}
void Assistance::working_proc(Assistance* pThis)
{
DebugTraceFunction;
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());
auto&& cur_image = pThis->get_format_image();
if (cur_image.empty()) {
DebugTraceError("Unable to capture window image!!!");
pThis->stop(false);
continue;
}
if (cur_image.rows < 100) {
DebugTraceInfo("Window Could not be minimized!!!");
pThis->m_pWindow->showWindow();
pThis->m_condvar.wait_for(lock,
std::chrono::milliseconds(pThis->m_configer.m_options.identify_delay),
[&]() -> bool { return !pThis->m_thread_running; });
continue;
}
std::string matched_task;
Rect matched_rect;
// 逐个匹配当前可能的图像
for (auto&& task_name : pThis->m_next_tasks) {
double threshold = Configer::m_tasks[task_name].threshold;
auto&& [algorithm, value, rect] = pThis->m_pIder->findImage(curImg, task_name, threshold);
double threshold = pThis->m_configer.m_tasks[task_name].threshold;
double cache_threshold = pThis->m_configer.m_tasks[task_name].cache_threshold;
auto&& [algorithm, value, rect] = pThis->m_pIder->find_image(cur_image, task_name, threshold);
DebugTrace(task_name, "Type:", algorithm, "Value:", value);
if (algorithm == 0 ||
(algorithm == 1 && value >= threshold)
|| (algorithm == 2 && value >= 0.9998)) {
if (algorithm == AlgorithmType::JustReturn ||
(algorithm == AlgorithmType::MatchTemplate && value >= threshold)
|| (algorithm == AlgorithmType::CompareHist && value >= cache_threshold)) {
matched_task = task_name;
matched_rect = rect;
break;
}
}
// 执行任务
if (!matched_task.empty()) {
auto && task = Configer::m_tasks[matched_task];
DebugTraceInfo("Matched:", matched_task, "Type:", static_cast<int>(task.type));
auto&& task = pThis->m_configer.m_tasks[matched_task];
DebugTraceInfo("***Matched***", matched_task, "Type:", task.type);
// 前置固定延时
if (task.pre_delay > 0) {
DebugTrace("PreDelay", task.pre_delay);
std::this_thread::sleep_for(std::chrono::milliseconds(task.pre_delay));
}
switch (task.type) {
case TaskType::ClickRect:
matched_rect = task.specific_area;
case TaskType::ClickSelf:
if (task.max_times != INT_MAX) {
DebugTrace("CurTimes:", task.exec_times, "MaxTimes:", task.max_times);
}
if (task.exec_times >= task.max_times) {
DebugTraceInfo("Reached limit, Stop.");
pThis->m_thread_running = false;
pThis->m_next_tasks.clear();
continue;
}
pThis->m_pCtrl->clickRange(matched_rect);
++task.exec_times;
break;
case TaskType::ClickRand:
pThis->m_pCtrl->clickRange(pThis->m_pCtrl->getWindowRect());
break;
case TaskType::DoNothing:
break;
case TaskType::Stop:
DebugTrace("TaskType is Stop");
pThis->m_thread_running = false;
pThis->m_next_tasks.clear();
continue;
break;
default:
DebugTraceError("Unknown option type:", static_cast<int>(task.type));
break;
}
if (task.rear_delay > 0) {
DebugTrace("RearDelay", task.rear_delay);
std::this_thread::sleep_for(std::chrono::milliseconds(task.rear_delay));
// std::this_thread::sleep_for(std::chrono::milliseconds(task.pre_delay));
bool cv_ret = pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(task.pre_delay),
[&]() -> bool { return !pThis->m_thread_running; });
if (cv_ret) { continue; }
}
pThis->m_next_tasks = Configer::m_tasks[matched_task].next;
if (task.max_times != INT_MAX) {
DebugTrace("CurTimes:", task.exec_times, "MaxTimes:", task.max_times);
}
if (task.exec_times < task.max_times) {
// 随机延时功能
if ((task.type & TaskType::BasicClick)
&& pThis->m_configer.m_options.control_delay_upper != 0) {
static std::default_random_engine rand_engine(std::chrono::system_clock::now().time_since_epoch().count());
static std::uniform_int_distribution<unsigned> rand_uni(pThis->m_configer.m_options.control_delay_lower, pThis->m_configer.m_options.control_delay_upper);
int delay = rand_uni(rand_engine);
DebugTraceInfo("Random Delay", delay, "ms");
bool cv_ret = pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(delay),
[&]() -> bool { return !pThis->m_thread_running; });
if (cv_ret) { continue; }
}
if (!pThis->m_thread_running) {
continue;
}
switch (task.type) {
case TaskType::ClickRect:
matched_rect = task.specific_area;
[[fallthrough]];
case TaskType::ClickSelf:
pThis->m_pCtrl->click(matched_rect);
break;
case TaskType::ClickRand:
pThis->m_pCtrl->click(pThis->m_pCtrl->getWindowRect());
break;
case TaskType::DoNothing:
break;
case TaskType::Stop:
DebugTrace("TaskType is Stop");
pThis->stop(false);
continue;
break;
case TaskType::PrintWindow:
if (pThis->m_configer.m_options.print_window) {
// 每次到结算界面,掉落物品不是一次性出来的,有个动画,所以需要等一会再截图
int print_delay = pThis->m_configer.m_options.print_window_delay;
DebugTraceInfo("Ready to print window, delay", print_delay);
pThis->m_condvar.wait_for(lock,
std::chrono::milliseconds(print_delay),
[&]() -> bool { return !pThis->m_thread_running; });
std::string dirname = GetCurrentDir() + "screenshot\\";
std::filesystem::create_directory(dirname);
auto time_str = StringReplaceAll(StringReplaceAll(GetFormatTimeString(), " ", "_"), ":", "-");
std::string filename = dirname + time_str + ".png";
pThis->print_window(filename, false);
}
break;
default:
DebugTraceError("Unknown option type:", task.type);
break;
}
++task.exec_times;
// 减少其他任务的执行次数
// 例如,进入吃理智药的界面了,相当于上一次点蓝色开始行动没生效
// 所以要给蓝色开始行动的次数减一
for (auto&& reduce : task.reduce_other_times) {
--pThis->m_configer.m_tasks[reduce].exec_times;
DebugTrace("Reduce exec times", reduce, pThis->m_configer.m_tasks[reduce].exec_times);
}
// 后置固定延时
if (task.rear_delay > 0) {
DebugTrace("RearDelay", task.rear_delay);
// std::this_thread::sleep_for(std::chrono::milliseconds(task.rear_delay));
auto cv_ret = pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(task.rear_delay),
[&]() -> bool { return !pThis->m_thread_running; });
if (cv_ret) { continue; }
}
pThis->m_next_tasks = pThis->m_configer.m_tasks[matched_task].next;
}
else {
DebugTraceInfo("Reached limit");
pThis->m_next_tasks = pThis->m_configer.m_tasks[matched_task].exceeded_next;
}
// 单纯为了打印日志。。感觉可以优化下
std::string nexts_str;
for (auto&& name : pThis->m_next_tasks) {
nexts_str += name + ",";
nexts_str += name + " ,";
}
if (nexts_str.back() == ',') {
nexts_str.pop_back();
}
DebugTrace("Next:", nexts_str);
}
pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(Configer::m_options.delayFixedTime));
pThis->m_condvar.wait_for(lock,
std::chrono::milliseconds(pThis->m_configer.m_options.identify_delay),
[&]() -> bool { return !pThis->m_thread_running; });
}
else {
pThis->m_condvar.wait(lock);
}
}
}
cv::Mat asst::Assistance::get_format_image(bool need_set_scale)
{
auto&& raw_image = m_pView->getImage(m_pView->getWindowRect());
if (raw_image.empty() || raw_image.rows < 100) {
DebugTraceError("Window image error");
return raw_image;
}
// 把模拟器边框的一圈裁剪掉
auto&& window_info = m_pView->getEmulatorInfo();
int x_offset = window_info.x_offset;
int y_offset = window_info.y_offset;
int width = raw_image.cols - x_offset - window_info.right_offset;
int height = raw_image.rows - y_offset - window_info.bottom_offset;
cv::Mat cropped(raw_image, cv::Rect(x_offset, y_offset, width, height));
if (need_set_scale) {
double scale_width = static_cast<double>(width) / m_configer.DefaultWindowWidth;
double scale_height = static_cast<double>(height) / m_configer.DefaultWindowHeight;
// 有些模拟器有可收缩的侧边,会增加宽度。
// config.json中设置的是侧边展开后的offset
// 如果用户把侧边收起来了,则有侧边的那头会额外裁剪掉一些,长度偏小
// 所以按这里面长、宽里大的那个算,大的那边没侧边
double scale = std::max(scale_width, scale_height);
m_pCtrl->setControlScale(scale);
}
//// 调整尺寸,与资源中截图的标准尺寸一致
//cv::Mat dst;
//cv::resize(cropped, dst, cv::Size(m_configer.DefaultWindowWidth, m_configer.DefaultWindowHeight));
return cropped;
}

View File

@@ -1,5 +1,7 @@
#include "AsstCaller.h"
#include "Updater.h"
#include <string.h>
asst::Assistance* CreateAsst()
{
@@ -16,13 +18,13 @@ void DestoryAsst(asst::Assistance* p_asst)
p_asst = NULL;
}
bool AsstCatchSimulator(asst::Assistance* p_asst)
bool AsstCatchEmulator(asst::Assistance* p_asst)
{
if (p_asst == NULL) {
return false;
}
auto ret = p_asst->setSimulator();
auto ret = p_asst->set_emulator();
if (ret) {
return true;
}
@@ -54,5 +56,31 @@ bool AsstSetParam(asst::Assistance* p_asst, const char* type, const char* param,
return false;
}
p_asst->setParam(type, param, value);
return p_asst->set_param(type, param, value);
}
bool AsstGetParam(asst::Assistance* p_asst, const char* type, const char* param, char * buffer, int buffer_size)
{
if (p_asst == NULL) {
return false;
}
auto ret = p_asst->get_param(type, param);
if (!ret) {
return false;
}
strcpy_s(buffer, buffer_size, ret.value().c_str());
return true;
}
bool CheckVersionUpdate(char* tag_buffer, int tag_bufsize, char* html_url_buffer, int html_bufsize, char* body_buffer, int body_bufsize)
{
bool ret = asst::Updater::get_instance().has_new_version();
if (!ret) {
return false;
}
auto && info = asst::Updater::get_instance().get_version_info();
strcpy_s(tag_buffer, tag_bufsize, info.tag_name.c_str());
strcpy_s(html_url_buffer, html_bufsize, info.html_url.c_str());
strcpy_s(body_buffer, body_bufsize, info.body.c_str());
return true;
}

View File

@@ -3,22 +3,33 @@
#include <fstream>
#include <sstream>
#include <algorithm>
#include <Windows.h>
#include "json.h"
#include "AsstDef.h"
#include "Logger.hpp"
using namespace asst;
std::string Configer::m_curDir;
std::string Configer::m_version;
Options Configer::m_options;
std::unordered_map<std::string, TaskInfo> Configer::m_tasks;
std::unordered_map<std::string, SimulatorInfo> Configer::m_handles;
bool Configer::reload()
Configer::Configer(const Configer& rhs)
: m_version(rhs.m_version),
m_options(rhs.m_options),
m_tasks(rhs.m_tasks),
m_handles(rhs.m_handles)
{
std::string filename = GetResourceDir() + "config.json";
}
Configer::Configer(Configer&& rhs) noexcept
: m_version(std::move(rhs.m_version)),
m_options(std::move(rhs.m_options)),
m_tasks(std::move(rhs.m_tasks)),
m_handles(std::move(rhs.m_handles))
{
}
bool Configer::reload(const std::string& filename)
{
DebugTraceFunction;
DebugTrace("Configer::reload | ", filename);
std::ifstream ifs(filename, std::ios::in);
if (!ifs.is_open()) {
return false;
@@ -30,24 +41,45 @@ bool Configer::reload()
auto ret = json::parser::parse(content);
if (!ret) {
DebugTrace("parse error", content);
return false;
}
auto root = std::move(ret).value();
Configer temp;
try {
m_version = root["version"].as_string();
temp.m_version = root["version"].as_string();
auto options_obj = root["options"].as_object();
m_options.delayType = options_obj["delay"]["type"].as_string();
m_options.delayFixedTime = options_obj["delay"]["fixedTime"].as_integer();
m_options.cache = options_obj["cache"].as_boolean();
{
temp.m_options.identify_delay = options_obj["identifyDelay"].as_integer();
temp.m_options.identify_cache = options_obj["identifyCache"].as_boolean();
temp.m_options.control_delay_lower = options_obj["controlDelayRange"][0].as_integer();
temp.m_options.control_delay_upper = options_obj["controlDelayRange"][1].as_integer();
temp.m_options.print_window = options_obj["printWindow"].as_boolean();
temp.m_options.print_window_delay = options_obj["printWindowDelay"].as_integer();
temp.m_options.print_window_crop_offset = options_obj["printWindowCropOffset"].as_integer();
}
DebugTrace("Options", options_obj.to_string());
auto tasks_obj = root["tasks"].as_object();
for (auto&& [name, task_json] : tasks_obj) {
TaskInfo task_info;
task_info.filename = task_json["filename"].as_string();
task_info.threshold = task_json["threshold"].as_double();
if (task_json.exist("threshold")) {
task_info.threshold = task_json["threshold"].as_double();
}
else {
task_info.threshold = DefaultThreshold;
}
if (task_json.exist("cacheThreshold")) {
task_info.cache_threshold = task_json["cacheThreshold"].as_double();
}
else {
task_info.cache_threshold = DefaultCacheThreshold;
}
std::string type = task_json["type"].as_string();
std::transform(type.begin(), type.end(), type.begin(), std::tolower);
if (type == "clickself") {
@@ -71,60 +103,94 @@ bool Configer::reload()
area_json[2].as_integer(),
area_json[3].as_integer());
}
else if (type == "printwindow") {
task_info.type = TaskType::PrintWindow;
}
else {
DebugTraceError("Task:", name, "error:", type);
return false;
}
if (task_json.as_object().exist("maxTimes")) {
if (task_json.exist("maxTimes")) {
task_info.max_times = task_json["maxTimes"].as_integer();
}
if (task_json.as_object().exist("preDelay")) {
if (task_json.exist("exceededNext")) {
auto next_arr = task_json["exceededNext"].as_array();
for (auto&& name : next_arr) {
task_info.exceeded_next.emplace_back(name.as_string());
}
}
else {
task_info.exceeded_next.emplace_back("Stop");
}
if (task_json.exist("preDelay")) {
task_info.pre_delay = task_json["preDelay"].as_integer();
}
if (task_json.as_object().exist("rearDelay")) {
if (task_json.exist("rearDelay")) {
task_info.rear_delay = task_json["rearDelay"].as_integer();
}
if (task_json.exist("reduceOtherTimes")) {
auto reduce_arr = task_json["reduceOtherTimes"].as_array();
for (auto&& reduce : reduce_arr) {
task_info.reduce_other_times.emplace_back(reduce.as_string());
}
}
auto next_arr = task_json["next"].as_array();
for (auto&& name : next_arr) {
task_info.next.emplace_back(name.as_string());
}
m_tasks.emplace(name, task_info);
temp.m_tasks.emplace(name, task_info);
}
auto handle_obj = root["handle"].as_object();
for (auto&& [name, simulator_json] : handle_obj) {
SimulatorInfo simulator_info;
for (auto&& [name, emulator_json] : handle_obj) {
EmulatorInfo emulator_info;
emulator_info.name = name;
auto window_arr = simulator_json["window"].as_array();
auto window_arr = emulator_json["window"].as_array();
for (auto&& info : window_arr) {
HandleInfo handle_info;
handle_info.className = info["class"].as_string();
handle_info.windowName = info["window"].as_string();
simulator_info.window.emplace_back(handle_info);
handle_info.class_name = info["class"].as_string();
handle_info.window_name = info["window"].as_string();
emulator_info.window.emplace_back(handle_info);
}
auto view_arr = simulator_json["view"].as_array();
auto view_arr = emulator_json["view"].as_array();
for (auto&& info : view_arr) {
HandleInfo handle_info;
handle_info.className = info["class"].as_string();
handle_info.windowName = info["window"].as_string();
simulator_info.view.emplace_back(handle_info);
handle_info.class_name = info["class"].as_string();
handle_info.window_name = info["window"].as_string();
emulator_info.view.emplace_back(handle_info);
}
auto ctrl_arr = simulator_json["control"].as_array();
auto ctrl_arr = emulator_json["control"].as_array();
for (auto&& info : ctrl_arr) {
HandleInfo handle_info;
handle_info.className = info["class"].as_string();
handle_info.windowName = info["window"].as_string();
simulator_info.control.emplace_back(handle_info);
handle_info.class_name = info["class"].as_string();
handle_info.window_name = info["window"].as_string();
emulator_info.control.emplace_back(handle_info);
}
simulator_info.width = simulator_json["width"].as_integer();
simulator_info.height = simulator_json["height"].as_integer();
simulator_info.xOffset = simulator_json["xOffset"].as_integer();
simulator_info.yOffset = simulator_json["yOffset"].as_integer();
if (emulator_json.exist("adb")) {
emulator_info.is_adb = true;
// meojson的bug暂时没空修先转个字符串
emulator_info.adb.path = StringReplaceAll(emulator_json["adb"]["path"].as_string(), "\\\\", "\\");
emulator_info.adb.connect = emulator_json["adb"]["connect"].as_string();
emulator_info.adb.click = emulator_json["adb"]["click"].as_string();
emulator_info.adb.display = emulator_json["adb"]["display"].as_string();
emulator_info.adb.display_regex = emulator_json["adb"]["displayRegex"].as_string();
}
emulator_info.x_offset = emulator_json["xOffset"].as_integer();
emulator_info.y_offset = emulator_json["yOffset"].as_integer();
if (emulator_json.exist("rightOffset")) {
emulator_info.right_offset = emulator_json["rightOffset"].as_integer();
}
if (emulator_json.exist("bottomOffset")) {
emulator_info.bottom_offset = emulator_json["bottomOffset"].as_integer();
}
emulator_info.width = DefaultWindowWidth + emulator_info.x_offset + emulator_info.right_offset;
emulator_info.height = DefaultWindowHeight + emulator_info.y_offset + emulator_info.bottom_offset;
m_handles.emplace(name, simulator_info);
temp.m_handles.emplace(name, emulator_info);
}
}
catch (json::exception& e) {
@@ -132,11 +198,15 @@ bool Configer::reload()
return false;
}
*this = std::move(temp);
DebugTrace("Load config succeed");
return true;
}
bool Configer::setParam(const std::string& type, const std::string& param, const std::string& value)
bool Configer::set_param(const std::string& type, const std::string& param, const std::string& value)
{
// 暂时只用到了这些,总的参数太多了,后面要用啥再加上
if (type == "task.type") {
if (m_tasks.find(param) == m_tasks.cend()) {
return false;
@@ -171,4 +241,40 @@ bool Configer::setParam(const std::string& type, const std::string& param, const
m_tasks[param].max_times = std::stoi(value);
}
return true;
}
std::optional<std::string> Configer::get_param(const std::string& type, const std::string& param)
{
// 暂时只用到了这些,总的参数太多了,后面要用啥再加上
if (type == "task.execTimes" && m_tasks.find(param) != m_tasks.cend()) {
return std::to_string(m_tasks.at(param).exec_times);
}
return std::nullopt;
}
void Configer::clear_exec_times()
{
for (auto&& t : m_tasks) {
t.second.exec_times = 0;
}
}
Configer& asst::Configer::operator=(const Configer& rhs)
{
m_version = rhs.m_version;
m_options = rhs.m_options;
m_tasks = rhs.m_tasks;
m_handles = rhs.m_handles;
return *this;
}
Configer& asst::Configer::operator=(Configer&& rhs) noexcept
{
m_version = std::move(rhs.m_version);
m_options = std::move(rhs.m_options);
m_tasks = std::move(rhs.m_tasks);
m_handles = std::move(rhs.m_handles);
return *this;
}

View File

@@ -6,7 +6,7 @@
using namespace asst;
using namespace cv;
bool Identify::addImage(const std::string& name, const std::string& path)
bool Identify::add_image(const std::string& name, const std::string& path)
{
Mat mat = imread(path);
if (mat.empty()) {
@@ -16,7 +16,7 @@ bool Identify::addImage(const std::string& name, const std::string& path)
return true;
}
void Identify::setUseCache(bool b) noexcept
void Identify::set_use_cache(bool b) noexcept
{
if (b) {
m_use_cache = true;
@@ -27,7 +27,7 @@ void Identify::setUseCache(bool b) noexcept
}
}
Mat Identify::image2Hist(const cv::Mat& src)
Mat Identify::image_2_hist(const cv::Mat& src)
{
Mat src_hsv;
cvtColor(src, src_hsv, COLOR_BGR2HSV);
@@ -46,12 +46,13 @@ Mat Identify::image2Hist(const cv::Mat& src)
return src_hist;
}
double Identify::imageHistComp(const cv::Mat& src, const cv::MatND& hist)
double Identify::image_hist_comp(const cv::Mat& src, const cv::MatND& hist)
{
return compareHist(image2Hist(src), hist, CV_COMP_CORREL);
// keep the interface return value unchanged
return 1 - compareHist(image_2_hist(src), hist, CV_COMP_BHATTACHARYYA);
}
std::pair<double, cv::Point> Identify::findImage(const cv::Mat& image, const cv::Mat& templ)
std::pair<double, cv::Point> Identify::find_image(const cv::Mat& image, const cv::Mat& templ)
{
Mat image_hsv;
Mat templ_hsv;
@@ -59,7 +60,7 @@ std::pair<double, cv::Point> Identify::findImage(const cv::Mat& image, const cv:
cvtColor(templ, templ_hsv, COLOR_BGR2HSV);
Mat matched;
matchTemplate(image_hsv, templ_hsv, matched, cv::TM_CCORR_NORMED);
matchTemplate(image_hsv, templ_hsv, matched, cv::TM_CCOEFF_NORMED);
double minVal = 0, maxVal = 0;
cv::Point minLoc, maxLoc;
@@ -67,27 +68,28 @@ std::pair<double, cv::Point> Identify::findImage(const cv::Mat& image, const cv:
return { maxVal, maxLoc };
}
std::tuple<int, double, asst::Rect> Identify::findImage(const Mat& cur, const std::string& templ, double threshold)
std::tuple<AlgorithmType, double, asst::Rect> Identify::find_image(const Mat& cur, const std::string& templ, double threshold)
{
if (m_mat_map.find(templ) == m_mat_map.cend()) {
return { 0, 0, asst::Rect() };
return { AlgorithmType::JustReturn, 0, asst::Rect() };
}
// 有缓存用直方图比较CPU占用会低很多但要保证每次按钮图片的位置不变
if (m_use_cache && m_cache_map.find(templ) != m_cache_map.cend()) {
auto&& [rect, hist] = m_cache_map.at(templ);
double value = imageHistComp(cur(rect), hist);
return { 2, value, cvRect2Rect(rect).center_zoom(0.8) };
double value = image_hist_comp(cur(rect), hist);
return { AlgorithmType::CompareHist, value, cvrect_2_rect(rect).center_zoom(0.8) };
}
else {
else { // 没缓存就模板匹配
auto&& templ_mat = m_mat_map.at(templ);
auto&& [value, point] = findImage(cur, templ_mat);
auto&& [value, point] = find_image(cur, templ_mat);
cv::Rect raw_rect(point.x, point.y, templ_mat.cols, templ_mat.rows);
if (m_use_cache && value >= threshold) {
m_cache_map.emplace(templ, std::make_pair(raw_rect, image2Hist(cur(raw_rect))));
m_cache_map.emplace(templ, std::make_pair(raw_rect, image_2_hist(cur(raw_rect))));
}
return { 1, value, cvRect2Rect(raw_rect).center_zoom(0.8) };
return { AlgorithmType::MatchTemplate, value, cvrect_2_rect(raw_rect).center_zoom(0.8) };
}
}

View File

@@ -0,0 +1,98 @@
#include "Updater.h"
#include <stdio.h>
#include <Windows.h>
#include <WinInet.h>
#include "json.h"
#include "AsstDef.h"
#include "Logger.hpp"
using namespace asst;
const std::string Updater::GithubReleaseLastestApiUrl = "https://api.github.com/repos/MistEO/MeoAssistance/releases/latest";
const std::string Updater::GithubReleaseApiUrl = "https://api.github.com/repos/MistEO/MeoAssistance/releases/latest";
Updater& Updater::get_instance()
{
static Updater unique_instance;
return unique_instance;
}
bool Updater::has_new_version()
{
auto req_ret = request_github_api();
if (!req_ret) {
DebugTraceInfo("Requeset Error");
return false;
}
auto parse_ret = json::parser::parse(req_ret.value());
if (!parse_ret) {
DebugTraceInfo("Parse Error");
return false;
}
json::value root = std::move(parse_ret).value();
std::unique_lock<std::mutex> lock(m_mutex);
try {
m_lastest_version.tag_name = root["tag_name"].as_string();
m_lastest_version.html_url = root["html_url"].as_string();
m_lastest_version.author_name = root["author"]["login"].as_string();
m_lastest_version.created_time = root["created_at"].as_string();
m_lastest_version.body = root["body"].as_string();
auto assets = root["assets"].as_array();
if (assets.size() == 1) {
m_lastest_version.down_url = assets[0]["browser_download_url"].as_string();
}
}
catch (json::exception& exp) {
DebugTraceError("Json Error", exp.what());
return false;
}
if (m_lastest_version.tag_name > Version) {
m_has_new_version = true;
return true;
}
else {
return false;
}
}
const VersionInfo & Updater::get_version_info() const noexcept
{
return m_lastest_version;
}
std::optional<std::string> Updater::request_github_api()
{
HINTERNET h_session = ::InternetOpenA("GithubRelease", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (h_session == NULL) {
return std::nullopt;
}
HINTERNET h_http = ::InternetOpenUrlA(h_session, GithubReleaseLastestApiUrl.c_str(), NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
if (h_http == NULL) {
return std::nullopt;
}
std::string response;
DWORD buff_size = 4096;
char *buffer = new char[buff_size];
DWORD number = 1;
while (number > 0) {
memset(buffer, 0, buff_size);
InternetReadFile(h_http, buffer, buff_size, &number);
if (number != 0) {
response += std::string(buffer, number);
}
}
delete[] buffer;
buffer = NULL;
InternetCloseHandle(h_http);
h_http = NULL;
InternetCloseHandle(h_session);
h_session = NULL;
return response;
}

View File

@@ -2,50 +2,53 @@
#include <vector>
#include <utility>
#include <ctime>
#include <algorithm>
#include <chrono>
#include <stdint.h>
#include <WinUser.h>
#include "Configer.h"
#include <opencv2/opencv.hpp>
#include "AsstDef.h"
#include "Logger.hpp"
#include "Configer.h"
using namespace asst;
WinMacro::WinMacro(const std::string& simulator_name, HandleType type)
: m_simulator_name(simulator_name),
WinMacro::WinMacro(const EmulatorInfo& info, HandleType type)
: m_emulator_info(info),
m_handle_type(type),
m_rand_engine(time(NULL))
m_rand_engine(std::chrono::system_clock::now().time_since_epoch().count())
{
findHandle();
}
bool WinMacro::captured() const noexcept
{
return m_handle != NULL;
return m_handle != NULL && ::IsWindow(m_handle);
}
bool WinMacro::findHandle()
{
std::vector<HandleInfo> handle_vec;
auto&& info = Configer::m_handles[m_simulator_name];
switch (m_handle_type) {
case HandleType::Window:
m_width = info.width;
m_height = info.height;
handle_vec = info.window;
m_width = m_emulator_info.width;
m_height = m_emulator_info.height;
handle_vec = m_emulator_info.window;
break;
case HandleType::View:
handle_vec = info.view;
handle_vec = m_emulator_info.view;
break;
case HandleType::Control:
m_xOffset = info.xOffset;
m_yOffset = info.yOffset;
handle_vec = info.control;
m_is_adb = m_emulator_info.is_adb;
//m_x_offset = m_emulator_info.x_offset;
//m_y_offset = m_emulator_info.y_offset;
handle_vec = m_emulator_info.control;
break;
default:
DebugTraceError("Handle type error!", static_cast<int>(m_handle_type));
DebugTraceError("Handle type error!", m_handle_type);
return false;
}
@@ -53,17 +56,17 @@ bool WinMacro::findHandle()
for (auto&& handle_info : handle_vec)
{
wchar_t* class_wbuff = NULL;
if (!handle_info.className.empty()) {
size_t class_len = (handle_info.className.size() + 1) * 2;
if (!handle_info.class_name.empty()) {
size_t class_len = (handle_info.class_name.size() + 1) * 2;
class_wbuff = new wchar_t[class_len];
::MultiByteToWideChar(CP_UTF8, 0, handle_info.className.c_str(), -1, class_wbuff, class_len);
::MultiByteToWideChar(CP_UTF8, 0, handle_info.class_name.c_str(), -1, class_wbuff, class_len);
}
wchar_t* window_wbuff = NULL;
if (!handle_info.windowName.empty()) {
size_t window_len = (handle_info.windowName.size() + 1) * 2;
if (!handle_info.window_name.empty()) {
size_t window_len = (handle_info.window_name.size() + 1) * 2;
window_wbuff = new wchar_t[window_len];
memset(window_wbuff, 0, window_len);
::MultiByteToWideChar(CP_UTF8, 0, handle_info.windowName.c_str(), -1, window_wbuff, window_len);
::MultiByteToWideChar(CP_UTF8, 0, handle_info.window_name.c_str(), -1, window_wbuff, window_len);
}
m_handle = ::FindWindowExW(m_handle, NULL, class_wbuff, window_wbuff);
@@ -77,8 +80,43 @@ bool WinMacro::findHandle()
window_wbuff = NULL;
}
}
if (m_is_adb && m_handle != NULL) {
DebugTrace("Handle:", m_handle, "Name:", m_simulator_name, "Type:", static_cast<int>(m_handle_type));
DWORD pid = 0;
::GetWindowThreadProcessId(m_handle, &pid);
HANDLE handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
LPSTR path_buff = new CHAR[MAX_PATH];
memset(path_buff, 0, MAX_PATH);
DWORD buff_size = MAX_PATH;
QueryFullProcessImageNameA(handle, 0, path_buff, &buff_size);
std::string adb_dir = path_buff;
if (path_buff != NULL) {
delete[] path_buff;
path_buff = NULL;
}
size_t pos = adb_dir.find_last_of('\\') + 1;
adb_dir = adb_dir.substr(0, pos);
adb_dir = '"' + StringReplaceAll(m_emulator_info.adb.path, "[EmulatorPath]", adb_dir) + '"';
std::string connect_cmd = adb_dir + m_emulator_info.adb.connect;
if (!callCmd(connect_cmd)) {
DebugTraceError("Connect Adb Error");
return false;
}
auto display_ret = callCmd(adb_dir + m_emulator_info.adb.display);
if (display_ret) {
std::string pipe_str = std::move(display_ret).value();
sscanf_s(pipe_str.c_str(), m_emulator_info.adb.display_regex.c_str(),
&m_emulator_info.adb.display_width, &m_emulator_info.adb.display_height);
}
else {
DebugTraceError("Get Display Error");
return false;
}
m_click_cmd = adb_dir + m_emulator_info.adb.click;
}
DebugTrace("Handle:", m_handle, "Name:", m_emulator_info.name, "Type:", m_handle_type);
if (m_handle != NULL) {
return true;
@@ -88,9 +126,74 @@ bool WinMacro::findHandle()
}
}
std::optional<std::string> asst::WinMacro::callCmd(const std::string& cmd, bool use_pipe)
{
// 初始化管道
constexpr int PipeBuffSize = 1024;
HANDLE pipe_read = NULL;
HANDLE pipe_write = NULL;
SECURITY_ATTRIBUTES sa_out_pipe;
::ZeroMemory(&sa_out_pipe, sizeof(sa_out_pipe));
sa_out_pipe.nLength = sizeof(SECURITY_ATTRIBUTES);
sa_out_pipe.lpSecurityDescriptor = NULL;
sa_out_pipe.bInheritHandle = TRUE;
BOOL pipe_ret = FALSE;
if (use_pipe) {
pipe_ret = ::CreatePipe(&pipe_read, &pipe_write, &sa_out_pipe, PipeBuffSize);
DebugTrace("Create Pipe ret", pipe_ret);
}
// 准备启动ADB进程
STARTUPINFOA startup_info;
PROCESS_INFORMATION process_info;
ZeroMemory(&startup_info, sizeof(startup_info));
ZeroMemory(&process_info, sizeof(process_info));
startup_info.cb = sizeof(STARTUPINFO);
startup_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
startup_info.hStdOutput = pipe_write;
startup_info.hStdError = pipe_write;
startup_info.wShowWindow = SW_HIDE;
DWORD ret = -1;
if (!::CreateProcessA(NULL, const_cast<LPSTR>(cmd.c_str()), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startup_info, &process_info)) {
DebugTraceError("Create process error");
return std::nullopt;
}
::WaitForSingleObject(process_info.hProcess, 30000);
std::string pipe_str;
if (use_pipe && pipe_ret) {
DWORD read_num = 0;
DWORD std_num = 0;
if (::PeekNamedPipe(pipe_read, NULL, 0, NULL, &read_num, NULL) && read_num > 0) {
char pipe_buffer[PipeBuffSize] = { 0 };
::ReadFile(pipe_read, pipe_buffer, read_num, &std_num, NULL);
pipe_str = std::string(pipe_buffer, std_num);
}
}
::GetExitCodeProcess(process_info.hProcess, &ret);
::CloseHandle(process_info.hProcess);
::CloseHandle(process_info.hThread);
DebugTrace("Call", cmd, "ret", ret);
if (use_pipe) {
DebugTrace("Pipe:", pipe_str);
}
if (pipe_read != NULL) {
::CloseHandle(pipe_read);
}
if (pipe_write != NULL) {
::CloseHandle(pipe_write);
}
return pipe_str;
}
bool WinMacro::resizeWindow(int width, int height)
{
if (m_handle_type != HandleType::Window) {
if (m_handle_type != HandleType::Window || !::IsWindow(m_handle)) {
return false;
}
@@ -107,16 +210,16 @@ bool WinMacro::resizeWindow()
bool WinMacro::showWindow()
{
if (m_handle_type != HandleType::Window) {
if (m_handle_type != HandleType::Window || !::IsWindow(m_handle)) {
return false;
}
return ::ShowWindow(m_handle, SW_SHOW);
return ::ShowWindow(m_handle, SW_RESTORE);
}
bool WinMacro::hideWindow()
{
if (m_handle_type != HandleType::Window) {
if (m_handle_type != HandleType::Window || !::IsWindow(m_handle)) {
return false;
}
@@ -159,26 +262,30 @@ double WinMacro::getScreenScale()
bool WinMacro::click(const Point& p)
{
if (m_handle_type != HandleType::Control) {
if (m_handle_type != HandleType::Control || !::IsWindow(m_handle)) {
return false;
}
int x = (p.x + m_xOffset) / getScreenScale();
int y = (p.y + m_yOffset) / getScreenScale();
int x = p.x * m_control_scale;
int y = p.y * m_control_scale;
DebugTrace("Click, raw:", p.x, p.y, "corr:", x, y);
DebugTrace("click, raw:", p.x, p.y, "cor:", x, y);
LPARAM lparam = MAKELPARAM(x, y);
::SendMessage(m_handle, WM_LBUTTONDOWN, MK_LBUTTON, lparam);
::SendMessage(m_handle, WM_LBUTTONUP, 0, lparam);
return true;
if (m_is_adb) {
std::string cur_cmd = StringReplaceAll(m_click_cmd, "[x]", std::to_string(x));
cur_cmd = StringReplaceAll(cur_cmd, "[y]", std::to_string(y));
return callCmd(cur_cmd, false).has_value();
}
else {
LPARAM lparam = MAKELPARAM(x, y);
::SendMessage(m_handle, WM_LBUTTONDOWN, MK_LBUTTON, lparam);
::SendMessage(m_handle, WM_LBUTTONUP, 0, lparam);
return true;
}
}
bool WinMacro::clickRange(const Rect& rect)
bool WinMacro::click(const Rect& rect)
{
if (m_handle_type != HandleType::Control) {
if (m_handle_type != HandleType::Control || !::IsWindow(m_handle)) {
return false;
}
@@ -203,8 +310,21 @@ bool WinMacro::clickRange(const Rect& rect)
return click({ x, y });
}
void asst::WinMacro::setControlScale(double scale)
{
if (m_is_adb) {
m_control_scale = scale * scale * m_emulator_info.adb.display_width / Configer::DefaultWindowWidth;
}
else {
m_control_scale = scale / getScreenScale();
}
}
Rect WinMacro::getWindowRect()
{
if (!::IsWindow(m_handle)) {
return Rect();
}
RECT rect;
bool ret = ::GetWindowRect(m_handle, &rect);
if (!ret) {
@@ -217,7 +337,7 @@ Rect WinMacro::getWindowRect()
cv::Mat WinMacro::getImage(const Rect& rect)
{
if (m_handle_type != HandleType::View) {
if (m_handle_type != HandleType::View || !::IsWindow(m_handle)) {
return cv::Mat();
}
@@ -242,12 +362,12 @@ cv::Mat WinMacro::getImage(const Rect& rect)
DeleteDC(memDC);
ReleaseDC(m_handle, pDC);
/*
#ifdef _DEBUG
std::string filename = GetCurrentDir() + "\\print.bmp";
cv::imwrite(filename, dst_mat);
#endif
*/
/*
#ifdef _DEBUG
std::string filename = GetCurrentDir() + "\\print.bmp";
cv::imwrite(filename, dst_mat);
#endif
*/
return dst_mat;
}

View File

@@ -5,15 +5,22 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MeoAsstGui"
mc:Ignorable="d"
Title="MeoAssistance-明日方舟辅助" Height="500" Width="400">
Title="Meo明日方舟辅助" Height="520" Width="410" Loaded="OnLoaded">
<Grid>
<CheckBox x:Name="checkBox_useMedicine" Content="吃理智药" HorizontalAlignment="Left" Margin="50,100,0,0" VerticalAlignment="Top" Checked="checkBox_useMedicine_Checked" Unchecked="checkBox_useMedicine_Checked" IsChecked="True"/>
<CheckBox x:Name="checkBox_useStone" Content="吃石头" HorizontalAlignment="Left" Margin="50,150,0,0" VerticalAlignment="Top" Checked="checkBox_useStone_Checked" Unchecked="checkBox_useStone_Checked"/>
<TextBox x:Name="textBox_useStone" HorizontalAlignment="Left" Height="23" Margin="112,148,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top" Width="47" TextChanged="textBox_useStone_TextChanged" InputMethod.IsInputMethodEnabled="False"/>
<Label x:Name="label_stoneNumber" Content="颗" HorizontalAlignment="Left" Margin="164,144,0,0" VerticalAlignment="Top" RenderTransformOrigin="-5.771,-6.291"/>
<Button x:Name="button_startSanity" Content="开始刷理智" HorizontalAlignment="Left" Margin="50,200,0,0" VerticalAlignment="Top" Width="120" Height="50" Click="button_Click_startSanity"/>
<Button x:Name="button_stop" Content="停止" HorizontalAlignment="Left" Margin="50,280,0,0" VerticalAlignment="Top" Width="300" Height="50" Click="button_Click_stop"/>
<Button x:Name="button_startSanity" Content="开始刷理智" HorizontalAlignment="Left" Margin="50,300,0,0" VerticalAlignment="Top" Width="120" Height="50" Click="button_Click_startSanity"/>
<Button x:Name="button_stop" Content="停止" HorizontalAlignment="Left" Margin="50,380,0,0" VerticalAlignment="Top" Width="300" Height="50" Click="button_Click_stop"/>
<Label x:Name="catch_status" Content="" HorizontalAlignment="Left" Margin="50,30,0,0" VerticalAlignment="Top"/>
<Button x:Name="button_visit" Content="访问基建" HorizontalAlignment="Left" Margin="230,200,0,0" VerticalAlignment="Top" Width="120" Height="50" Click="button_Click_visit"/>
<Button x:Name="button_visit" Content="访问基建" HorizontalAlignment="Left" Margin="230,300,0,0" VerticalAlignment="Top" Width="120" Height="50" Click="button_Click_visit"/>
<Label x:Name="exec_times" Content="" HorizontalAlignment="Left" Margin="230,60,0,0" VerticalAlignment="Top"/>
<Label x:Name="stone_times" Content="" HorizontalAlignment="Left" Margin="230,144,0,0" VerticalAlignment="Top" RenderTransformOrigin="-0.702,0.403"/>
<CheckBox x:Name="checkBox_maxTimes" Content="指定次数" HorizontalAlignment="Left" Margin="50,200,0,0" VerticalAlignment="Top" Checked="checkBox_maxTimes_Checked" Unchecked="checkBox_maxTimes_Checked"/>
<TextBox x:Name="textBox_maxTimes" HorizontalAlignment="Left" Height="23" Margin="124,198,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top" Width="47" TextChanged="textBox_maxTimes_TextChanged" InputMethod.IsInputMethodEnabled="False"/>
<Label x:Name="label" Content="次" HorizontalAlignment="Left" Margin="176,193,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.397,-0.745"/>
<CheckBox x:Name="checkBox_shutdown" Content="刷完自动关机" HorizontalAlignment="Left" Margin="50,250,0,0" VerticalAlignment="Top" Checked="checkBox_shutdown_Checked"/>
<Label x:Name="label_status" Content="" HorizontalAlignment="Left" Margin="230,30,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>

View File

@@ -13,6 +13,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.Windows.Threading;
namespace MeoAsstGui
{
@@ -22,38 +23,57 @@ namespace MeoAsstGui
public partial class MainWindow : Window
{
[DllImport("MeoAssistance.dll")] static public extern IntPtr CreateAsst();
[DllImport("MeoAssistance.dll")] static public extern void DestoryAsst(IntPtr ptr);
[DllImport("MeoAssistance.dll")] static public extern bool AsstCatchSimulator(IntPtr ptr);
[DllImport("MeoAssistance.dll")] static public extern void AsstStart(IntPtr ptr, string task);
[DllImport("MeoAssistance.dll")] static public extern void AsstStop(IntPtr ptr);
[DllImport("MeoAssistance.dll")] static public extern bool AsstSetParam(IntPtr p_asst, string type, string param, string value);
[DllImport("MeoAssistance.dll")] static private extern IntPtr CreateAsst();
[DllImport("MeoAssistance.dll")] static private extern void DestoryAsst(IntPtr ptr);
[DllImport("MeoAssistance.dll")] static private extern bool AsstCatchEmulator(IntPtr ptr);
[DllImport("MeoAssistance.dll")] static private extern void AsstStart(IntPtr ptr, string task);
[DllImport("MeoAssistance.dll")] static private extern void AsstStop(IntPtr ptr);
[DllImport("MeoAssistance.dll")] static private extern bool AsstSetParam(IntPtr p_asst, string type, string param, string value);
[DllImport("MeoAssistance.dll")]
static private extern bool AsstGetParam(
IntPtr p_asst, string type, string param,
[In, Out] StringBuilder lp_string, int buffer_size);
private IntPtr p_asst;
UpdateDialog updateDialog;
private DispatcherTimer update_times = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
p_asst = CreateAsst();
}
~MainWindow()
{
DestoryAsst(p_asst);
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
updateDialog = new UpdateDialog();
updateDialog.CheckUpdateAndShowDialog();
updateDialog.Close();
p_asst = CreateAsst();
update_times.Tick += new EventHandler(updateExecTimes);
update_times.Interval = TimeSpan.FromSeconds(1);
}
private void button_Click_startSanity(object sender, RoutedEventArgs e)
{
bool catched = AsstCatchSimulator(p_asst);
bool catched = AsstCatchEmulator(p_asst);
catch_status.Content = "捕获模拟器窗口:" + catched;
AsstStart(p_asst, "SanityBegin");
update_times.Start();
}
private void button_Click_stop(object sender, RoutedEventArgs e)
{
AsstStop(p_asst);
catch_status.Content = "";
update_times.Stop();
exec_times.Content = "";
stone_times.Content = "";
label_status.Content = "";
}
private void checkBox_useMedicine_Checked(object sender, RoutedEventArgs e)
@@ -70,26 +90,97 @@ namespace MeoAsstGui
private void textBox_useStone_TextChanged(object sender, TextChangedEventArgs e)
{
AsstSetParam(p_asst, "task.maxTimes", "StoneConfirm", textBox_useStone.Text);
if (checkBox_useStone.IsChecked == true)
{
String text = textBox_useStone.Text != String.Empty ? textBox_useStone.Text : "0";
AsstSetParam(p_asst, "task.maxTimes", "StoneConfirm", text);
}
}
private void checkBox_useStone_Checked(object sender, RoutedEventArgs e)
{
if (checkBox_useMedicine.IsChecked == true)
if (checkBox_useStone.IsChecked == true)
{
AsstSetParam(p_asst, "task.type", "UseStone", "doNothing");
String text = textBox_useStone.Text != String.Empty ? textBox_useStone.Text : "0";
AsstSetParam(p_asst, "task.maxTimes", "StoneConfirm", text);
}
else
{
AsstSetParam(p_asst, "task.type", "UseStone", "stop");
AsstSetParam(p_asst, "task.maxTimes", "StoneConfirm", "0");
}
}
private void button_Click_visit(object sender, RoutedEventArgs e)
{
bool catched = AsstCatchSimulator(p_asst);
bool catched = AsstCatchEmulator(p_asst);
catch_status.Content = "捕获模拟器窗口:" + catched;
AsstStart(p_asst, "VisitBegin");
}
private void updateExecTimes(object sender, EventArgs e)
{
StringBuilder buff_start = new StringBuilder(16);
AsstGetParam(p_asst, "task.execTimes", "StartButton2", buff_start, 16);
exec_times.Content = "已开始行动 " + buff_start + " 次";
if (checkBox_useStone.IsChecked == true)
{
StringBuilder buff_stone = new StringBuilder(16);
AsstGetParam(p_asst, "task.execTimes", "StoneConfirm", buff_stone, 16);
stone_times.Content = "已碎石 " + buff_stone + " 个";
}
StringBuilder buff_running = new StringBuilder(4);
AsstGetParam(p_asst, "status", "running", buff_running, 4);
if (int.Parse(buff_running.ToString()) == 0)
{
update_times.Stop();
label_status.Content = "已刷完,自动停止";
if (checkBox_shutdown.IsChecked == true)
{
System.Diagnostics.Process.Start("shutdown.exe", "-s -t 60");
MessageBoxResult result = MessageBox.Show("已刷完,即将关机,是否取消?", "提示", MessageBoxButton.OK);
if (result == MessageBoxResult.OK)
{
System.Diagnostics.Process.Start("shutdown.exe", "-a");
}
}
}
else
{
label_status.Content = "正在运行中……";
}
}
private void checkBox_maxTimes_Checked(object sender, RoutedEventArgs e)
{
if (checkBox_maxTimes.IsChecked == true)
{
String text = textBox_maxTimes.Text != String.Empty ? textBox_maxTimes.Text : "0";
AsstSetParam(p_asst, "task.maxTimes", "StartButton1", text);
}
else
{
AsstSetParam(p_asst, "task.maxTimes", "StartButton1", int.MaxValue.ToString());
}
}
private void textBox_maxTimes_TextChanged(object sender, TextChangedEventArgs e)
{
if (checkBox_maxTimes.IsChecked == true)
{
String text = textBox_maxTimes.Text != String.Empty ? textBox_maxTimes.Text : "0";
AsstSetParam(p_asst, "task.maxTimes", "StartButton1", text);
}
}
private void checkBox_shutdown_Checked(object sender, RoutedEventArgs e)
{
}
}
}

View File

@@ -26,7 +26,7 @@
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<ApplicationVersion>0.4.0.0</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
@@ -54,6 +54,9 @@
<PropertyGroup>
<RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -75,6 +78,9 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="UpdateDialog.xaml.cs">
<DependentUpon>UpdateDialog.xaml</DependentUpon>
</Compile>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -87,6 +93,10 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="UpdateDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
@@ -126,6 +136,9 @@
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Resource Include="favicon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy /e /y /i $(SolutionDir)resource $(TargetDir)resource</PostBuildEvent>

View File

@@ -0,0 +1,16 @@
<Window x:Class="MeoAsstGui.UpdateDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MeoAsstGui"
mc:Ignorable="d"
Title="有新版本" Height="500" Width="400">
<Grid>
<Label x:Name="label_tag" Content="" HorizontalAlignment="Center" Margin="10,25,10.333,0" VerticalAlignment="Top" Height="50" Width="373" FontSize="24"/>
<Label x:Name="label_body" Content="" HorizontalAlignment="Left" Margin="50,80,-656.667,0" VerticalAlignment="Top" Height="281" Width="1000" FontSize="16"/>
<Button x:Name="button_confirm" Content="前往下载" HorizontalAlignment="Left" Margin="50,366,0,0" VerticalAlignment="Top" Width="120" Height="60" Click="button_confirm_Click"/>
<Button x:Name="button_cancer" Content="下次一定" HorizontalAlignment="Left" Margin="220,366,0,0" VerticalAlignment="Top" Width="120" Height="60" Click="button_cancer_Click"/>
</Grid>
</Window>

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
namespace MeoAsstGui
{
/// <summary>
/// UpdateDialog.xaml 的交互逻辑
/// </summary>
public partial class UpdateDialog : Window
{
[DllImport("MeoAssistance.dll")]
static private extern bool CheckVersionUpdate(
[In, Out] StringBuilder tag, int tag_bufsize,
[In, Out] StringBuilder html_url, int html_bufsize,
[In, Out] StringBuilder body, int body_bufsize);
public UpdateDialog()
{
InitializeComponent();
}
private String m_htmlUrl;
public void CheckUpdateAndShowDialog()
{
StringBuilder tag = new StringBuilder(64);
StringBuilder html_url = new StringBuilder(512);
StringBuilder body = new StringBuilder(4096);
bool ret = CheckVersionUpdate(tag, 64, html_url, 512, body, 4096);
if (!ret)
{
return;
}
label_tag.Content = "新版本:" + tag;
byte[] buffer1 = Encoding.Default.GetBytes(body.ToString());
byte[] buffer2 = Encoding.Convert(Encoding.UTF8, Encoding.Default, buffer1, 0, buffer1.Length);
string strBuffer = Encoding.Default.GetString(buffer2, 0, buffer2.Length);
strBuffer = strBuffer.Replace("\\r\\n", "\r\n");
int len = strBuffer.Length > 128 ? 128 : strBuffer.Length;
label_body.Content = strBuffer.Substring(0, len) + "\n......";
m_htmlUrl = html_url.ToString();
ShowDialog();
}
private void button_cancer_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void button_confirm_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Process.Start(m_htmlUrl);
Close();
}
}
}

BIN
MeoAsstGui/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -4,20 +4,24 @@ A game assistance for Arknights
一款明日方舟的游戏辅助供PC端安卓模拟器使用龟速开发中……
![截图](README/1.png)
![界面截图](readme/gui.png)
## 功能介绍
- 支持自动刷理智
- 支持自动吃完体力
- 支持根据设置自动吃石头
- 刷完后程序会自动停止
- 代理失败会自动放弃本次行动
- 支持自动访问好友基建
- 所有操作,都是点击按钮内随机位置,且模拟泊松分布,不会像鼠标宏一样一直是同一个点,没有封号风险
~~(虽然好像也没听说过谁用鼠标宏被封号的)~~
- 模拟器窗口可以被遮挡,即使全屏看视频、玩游戏,也完全不影响辅助运行
~~(但是模拟器还是不能最小化)~~
- 自动刷理智
- 可设置是否吃完理智
- 可设置是否吃石头以及数量
- 可设置刷的次数(可以用来刷剿灭)
- 可设置刷完自动关机
- 支持剿灭模式
- 支持打完升级了的情况
- 支持代理失败的情况,会自动放弃本次行动
- 支持每次刷完自动截图,可用于上传企鹅物流~
- 自动访问好友基建
- 访问完了还会贴心的帮你点进信用商店~
- 其他优势
- 所有操作,都是点击按钮内随机位置,且支持设置随机延时,没有封号风险
- 模拟器窗口可以被遮挡,即使全屏看视频、玩游戏,也不影响辅助运行(但模拟器窗口不能最小化)
- 支持多款主流模拟器
- 自适应分辨率及屏幕缩放
- 未来更多功能见[Todo](#Todo)
@@ -26,27 +30,35 @@ A game assistance for Arknights
#### 蓝叠模拟器
完美兼容,作者绝大部分测试均在蓝叠上进行,稳定性最能保障
完美支持,作者绝大部分测试均在蓝叠上进行,稳定性最能保障
#### MuMu模拟器
完美支持专门单独做了一套基于adb的控制逻辑。需要关闭模拟器的底部工具栏快捷键Alt+T
#### MuMu手游助手星云引擎
不支持MuMu不响应SendMessage鼠标消息而且这个版本不支持adb控制正在想办法……
#### 逍遥模拟器
完美兼容
支持,需要收起右侧侧边栏后使用,未多做测试
#### 雷电模拟器
完美兼容,需要收起右侧侧边栏后使用
支持,需要收起右侧侧边栏后使用,未多做测试
#### 夜神模拟器
兼容,但辅助开始后不可操作模拟器窗口
支持,效果不太好,且辅助开始后不可移动模拟器窗口,不推荐使用
#### 腾讯手游助手
兼容但需要手动设置分辨率设置中心——引擎设置——分辨率设置——1280x720——保存后重启模拟器
不支持,腾讯不支持句柄的窗口尺寸调节,有人需要的话再单独做
#### MuMu手游助手 && MuMu模拟器
#### 其他
不兼容MuMu所有的窗口句柄均不响应SendMessage鼠标消息但官方提供了adb的方式进行控制有时间再做
若需要使用其他模拟器、或上述不兼容的模拟器。欢迎给我提[ISSUE](https://github.com/MistEO/MeoAssistance/issues),会根据情况尽量适配~
## 使用说明
@@ -54,20 +66,33 @@ A game assistance for Arknights
1. 使用支持的模拟器打开明日方舟
2. 解压压缩包,**使用管理员权限**,打开"MeoAsstGui.exe"
3. 注意:运行期间,模拟器窗口可以被遮挡,全屏玩游戏、看视频等,完全不影响,但是模拟器不能最小化
3. 注意:运行期间,模拟器窗口可以被遮挡,全屏玩游戏、看视频等,完全不影响,但是模拟器不能最小化
### 刷理智
1. 明日方舟打开**蓝色开始按钮**的界面
1. 根据你的需要勾选"吃理智药"和"吃石头"
2. 点击"开始刷理智"
3. 刷完了会自动停止的
2. 根据你的需要勾选"吃理智药"和"吃石头"
3. 点击"开始刷理智",开始后上面的选项也可以随时修改
4. 刷完了会自动停止的
### 访问好友基建
1. 明日方舟处于任意界面均可,会自动帮你点过去
2. 点击"访问基建"
3. 达到10次上限或者所有可访问的好友都访问完了就会自动停的
4. 然后会贴心的帮你跳转到信用商店,顺便收了当天信用~
### 设置操作延时
请手动修改`resource\config.json`文件中,`options`.`controlDelayRange`字段的值,格式为`[最小延时, 最大延时]`单位为毫秒例如想设置3~5秒的随机延时即设置为`[ 3000, 5000]` 即可。文件保存后请重新打开程序。
![图例](readme/controlDelayRange.png)
### 自动截图功能
每次刷完结算界面,会自动截一张图,保存在`screenshot`文件夹中
这个功能默认是打开的,不需要的话可以手动关掉:请手动修改`resource\config.json`文件中,`options`.`printWindow`字段的值,`true`是打开,`false`是关闭。文件保存后请重新打开程序。
![图例](readme/printWindow.png)
## Todo
@@ -78,7 +103,8 @@ A game assistance for Arknights
- [x] 基本图形化界面
- [ ] 图形化界面进一步完善
- [ ] 日志打印,错误提示
- [ ] 使模拟器窗口不可见的按钮
- [x] 刷完自动关机功能
- [ ] ~~操作随机延时支持设置~~
- [ ] 刷理智
- [x] 支持剿灭
- [x] 支持使模拟器窗口不可见
@@ -86,12 +112,14 @@ A game assistance for Arknights
- [x] 代理失败的情况
- [x] 支持等级提升
- [x] 支持自动勾选代理指挥
- [ ] 支持刷指定次数
- [x] 支持刷指定次数
- [x] 自动吃石头(根据设置,指定数量)
- [x] 操作随机延时
- [ ] 指定刷XX个某材料
- [ ] 支持凌晨4点更新数据
- [ ] 结束界面自动截图,可用于上传企鹅物流
- [x] 结束界面自动截图,可用于上传企鹅物流
- [ ] 持续监视理智,一有就自动刷掉
- [ ] 模拟器被最小化了,给出提示
- [x] 模拟器被最小化了,给出提示
- [x] 支持更多模拟器
- [x] 信用访问
- [ ] 基建收菜
@@ -100,9 +128,13 @@ A game assistance for Arknights
- [x] 更换算法为模板匹配找图,而不是当前的区域相似度对比
- [x] 优化算法效率,添加缓存功能
- [x] 优化任务队列,减少不必要的计算
- [ ] 掉落材料计数
- [ ] 窗口分辨率自适应针对MuMu、腾讯模拟器进一步适配
- [ ] 进一步优化任务队列效率
- [x] 其他
- [x] 尝试减小程序体积
- [x] 检查程序更新
- [ ] 程序自动更新
## 致谢

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -25,7 +25,7 @@
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{36bc08f3-71cf-429a-ae69-291be8962cb2}</ProjectGuid>
<RootNamespace>Test</RootNamespace>
<RootNamespace>Tools</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>Sanity</ProjectName>
</PropertyGroup>

View File

@@ -1,19 +1,28 @@
#include "Assistance.h"
#include "Updater.h"
#include "Logger.hpp"
int main(int argc, char** argv)
{
using namespace asst;
bool up = Updater::get_instance().has_new_version();
if (up) {
auto && info = Updater::get_instance().get_version_info();
std::cout << "ÓÐа汾£º" << info.tag_name << std::endl;
std::cout << "µØÖ·£º" << info.html_url << std::endl;
}
Assistance asst;
auto ret = asst.setSimulator();
auto ret = asst.set_emulator();
if (!ret) {
DebugTraceError("Can't Find Simulator or Permission denied.");
DebugTraceError("Can't Find Emulator or Permission denied.");
getchar();
return -1;
}
else {
DebugTraceInfo("Find Simulator:", ret.value());
DebugTraceInfo("Find Emulator:", ret.value());
}
DebugTraceInfo("Start");

View File

@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{4AC1CFFF-D7B8-4FDA-BCFD-E4754275979B}</ProjectGuid>
<RootNamespace>Tools</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>Screenshot</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)meojson\include;$(SolutionDir)MeoAssistance\include;$(IncludePath)</IncludePath>
<LibraryPath>$(TargetDir);$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)meojson\include;$(SolutionDir)MeoAssistance\include;$(IncludePath)</IncludePath>
<LibraryPath>$(TargetDir);$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc11</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>MeoAssistance.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(TargetDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc11</LanguageStandard_C>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>MeoAssistance.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(TargetDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

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>

30
Tools/Screenshot/main.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include "Assistance.h"
#include "AsstAux.h"
#include "Logger.hpp"
int main(int argc, char** argv)
{
using namespace asst;
Assistance asst;
auto ret = asst.set_emulator();
if (!ret) {
DebugTraceError("Can't Find Emulator or Permission denied.");
getchar();
return -1;
}
else {
DebugTraceInfo("Find Emulator:", ret.value());
}
char ch = 0;
while (ch != EOF) {
ch = getchar();
auto time_str = StringReplaceAll(StringReplaceAll(GetFormatTimeString(), " ", "_"), ":", "-");
std::string filename = GetCurrentDir() + "screenshot\\" + time_str + ".png";
asst.print_window(filename);
}
return 0;
}

Submodule meojson updated: e66deff929...d6d07f5e6c

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
readme/gui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
readme/printWindow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
resource/CollectCredit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
resource/CreditStore.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 36 KiB

BIN
resource/Mall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 54 KiB

BIN
resource/PopupCancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
resource/PopupConfirm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -1,12 +1,23 @@
{
"version": "0.3",
"version": "0.4",
"options": {
"delay": {
"type": "fixedTime",
"fixedTime": 1000
},
"cache": true
"identifyCache": true,
"identifyCache_Doc": "图像识别缓存功能开启后可以大幅降低CPU消耗但需要保证要识别的按钮每次的位置不会改变。true-开启false-关闭默认true",
"identifyDelay": 1000,
"identifyDelay_Doc": "图像识别延时越快操作越快但会增加CPU消耗。单位毫秒默认1000",
"printWindow": true,
"printWindow_Doc": "截图功能开启后每次结算界面会截图到screenshot目录下。true-开启false-关闭默认true",
"printWindowDelay": 3000,
"printWindowDelay_Doc": "截图延时每次到结算界面掉落物品不是一次性出来的有个动画所以需要等一会再截图。单位毫秒默认3000",
"printWindowCropOffset": 5,
"printWindowCropOffset_Doc": "截图额外裁剪再额外把边框裁减掉一圈不然企鹅物流有可能识别不出来。单位像素默认5",
"controlDelayRange": [
0,
0
],
"controlDelayRange_Doc": "点击随机延时:每次点击操作会进行随机延时,降低封号风险(好像也没听说过谁被封号的)。格式为 [ 最小延时, 最大延时 ]单位为毫秒。例如想设置3~5秒延时即修改为[ 3000, 5000 ]默认0~0"
},
"handle_Doc": "下面的和模拟器窗口捕获逻辑有关,不需要修改",
"handle": {
"BlueStacks": {
"window": [
@@ -35,10 +46,10 @@
"window": "BlueStacks Android PluginAndroid"
}
],
"width": 1294,
"height": 773,
"xOffset": -7,
"yOffset": -47
"xOffset": 11,
"yOffset": 46,
"rightOffset": 11,
"bottomOffset": 10
},
"Nox": {
"window": [
@@ -59,10 +70,10 @@
"window": "夜神模拟器"
}
],
"width": 1298,
"height": 754,
"xOffset": 0,
"yOffset": -32
"xOffset": 2,
"yOffset": 39,
"rightOffset": 39,
"bottomOffset": 9
},
"LDPlayer": {
"window": [
@@ -87,10 +98,8 @@
"window": "TheRender"
}
],
"width": 1304,
"height": 756,
"xOffset": 0,
"yOffset": -35
"yOffset": 35
},
"XYAZ": {
"window": [
@@ -115,10 +124,10 @@
"window": "MainWindowWindow"
}
],
"width": 1282,
"height": 769,
"xOffset": 0,
"yOffset": -47
"xOffset": 1,
"yOffset": 48,
"rightOffset": 1,
"bottomOffset": 1
},
"Tencent": {
"window": [
@@ -143,12 +152,71 @@
"window": "AEngineRenderWindow"
}
],
"width": 1282,
"height": 769,
"xOffset": 1,
"yOffset": 42
},
"MuMuAsst": {
"window": [
{
"class": "Qt5QWindowIcon",
"window": "明日方舟 - 星云引擎"
}
],
"view": [
{
"class": "Qt5QWindowIcon",
"window": "明日方舟 - 星云引擎"
}
],
"control": [
{
"class": "Qt5QWindowIcon",
"window": "明日方舟 - 星云引擎"
}
],
"adb": {
"path": "[EmulatorPath]..\\vmonitor\\bin\\adb_server.exe",
"connect": " connect 127.0.0.1:7555",
"click": " shell input tap [x] [y]",
"display": " shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayRegex": "cur=%dx%d"
},
"xOffset": 0,
"yOffset": -42
"yOffset": 36
},
"MuMuEmulator": {
"window": [
{
"class": "Qt5QWindowIcon",
"window": "明日方舟 - MuMu模拟器"
}
],
"view": [
{
"class": "Qt5QWindowIcon",
"window": "明日方舟 - MuMu模拟器"
}
],
"control": [
{
"class": "Qt5QWindowIcon",
"window": "明日方舟 - MuMu模拟器"
}
],
"adb": {
"path": "[EmulatorPath]..\\vmonitor\\bin\\adb_server.exe",
"connect": " connect 127.0.0.1:7555",
"click": " shell input tap [x] [y]",
"display": " shell dumpsys window displays | grep init= | awk ' { print $3 } '",
"displayRegex": "cur=%dx%d"
},
"xOffset": 0,
"yOffset": 36,
"rightOffset": 0,
"bottomOffset": 0
}
},
"tasks_Doc": "下面的和任务队列执行逻辑有关,不需要修改",
"tasks": {
"SanityBegin": {
"filename": "",
@@ -167,7 +235,7 @@
},
"UsePrts": {
"filename": "UsePrts.png",
"threshold": 0.97,
"threshold": 0.8,
"type": "clickSelf",
"next": [
"StartButton1"
@@ -175,7 +243,7 @@
},
"StartButton1": {
"filename": "StartButton1.png",
"threshold": 0.94,
"threshold": 0.8,
"type": "clickSelf",
"next": [
"StartButton2",
@@ -184,22 +252,29 @@
]
},
"StartButton2": {
"id": 2,
"filename": "StartButton2.png",
"threshold": 0.99,
"type": "clickSelf",
"rearDelay": 10000,
"rearDelay": 20000,
"next": [
"StartButton2",
"PRTS"
]
},
"PRTS": {
"filename": "PRTS.png",
"threshold": 0.99,
"type": "doNothing",
"rearDelay": 5000,
"next": [
"PRTS",
"PrtsErrorConfirm",
"EndOfAction"
]
},
"EndOfAction": {
"filename": "",
"threshold": 0,
"type": "printWindow",
"next": [
"Random"
]
},
@@ -221,7 +296,6 @@
},
"Loading": {
"filename": "Loading.png",
"threshold": 0.99,
"type": "doNothing",
"next": [
"StartButton1"
@@ -229,7 +303,6 @@
},
"UseMedicine": {
"filename": "UseMedicine.png",
"threshold": 0.99,
"type": "doNothing",
"next": [
"MedicineConfirm"
@@ -237,15 +310,16 @@
},
"MedicineConfirm": {
"filename": "MedicineConfirm.png",
"threshold": 0.98,
"type": "clickSelf",
"reduceOtherTimes": [
"StartButton1"
],
"next": [
"StartButton1"
]
},
"UseStone": {
"filename": "UseStone.png",
"threshold": 0.99,
"type": "doNothing",
"next": [
"StoneConfirm"
@@ -253,16 +327,17 @@
},
"StoneConfirm": {
"filename": "MedicineConfirm.png",
"threshold": 0.98,
"type": "clickSelf",
"maxTimes": 0,
"reduceOtherTimes": [
"StartButton1"
],
"next": [
"StartButton1"
]
},
"PrtsErrorConfirm": {
"filename": "PrtsErrorConfirm.png",
"threshold": 0.98,
"type": "doNothing",
"next": [
"AbandonAction"
@@ -270,8 +345,12 @@
},
"AbandonAction": {
"filename": "AbandonAction.png",
"threshold": 0.98,
"type": "clickSelf",
"reduceOtherTimes": [
"StartButton1",
"StartButton2",
"Loading"
],
"next": [
"Random"
]
@@ -286,21 +365,22 @@
"StartToVisit",
"VisitNext",
"VisitNextBlack",
"Return"
"ReturnToFriends"
]
},
"Return": {
"ReturnToFriends": {
"filename": "Return.png",
"threshold": 0.98,
"threshold": 0.85,
"cacheThreshold": 0.85,
"type": "clickSelf",
"next": [
"Friends",
"Return"
"ReturnToFriends"
]
},
"Friends": {
"filename": "Friends.png",
"threshold": 0.98,
"preDelay": 1000,
"type": "clickSelf",
"next": [
"FriendsList"
@@ -308,7 +388,6 @@
},
"FriendsList": {
"filename": "FriendsList.png",
"threshold": 0.98,
"type": "clickSelf",
"next": [
"StartToVisit"
@@ -316,7 +395,6 @@
},
"StartToVisit": {
"filename": "StartToVisit.png",
"threshold": 0.98,
"type": "clickSelf",
"next": [
"VisitNext"
@@ -324,23 +402,74 @@
},
"VisitNext": {
"filename": "VisitNext.png",
"threshold": 0.999,
"type": "clickSelf",
"maxTimes": 10,
"maxTimes": 21,
"exceededNext": [
"ReturnToMall"
],
"next": [
"VisitNext",
"VisitNextBlack"
]
},
"ReturnToMall": {
"filename": "Return.png",
"type": "clickSelf",
"next": [
"Mall",
"ReturnToMall",
"ReturnToMallConfirm"
]
},
"ReturnToMallConfirm": {
"filename": "PopupConfirm.png",
"type": "clickSelf",
"next": [
"ReturnToMall"
]
},
"Mall": {
"filename": "Mall.png",
"type": "clickSelf",
"next": [
"CreditStore"
]
},
"CreditStore": {
"filename": "CreditStore.png",
"threshold": 0.85,
"rearDelay": 1000,
"type": "clickSelf",
"next": [
"CollectCredit",
"Stop"
]
},
"CollectCredit": {
"filename": "CollectCredit.png",
"type": "clickSelf",
"next": [
"Stop"
]
},
"VisitLimited": {
"filename": "VisitLimited.png",
"threshold": 0.65,
"type": "stop",
"next": []
"threshold": 1,
"type": "doNothing",
"next": [
"ReturnToMall"
]
},
"VisitNextBlack": {
"filename": "VisitNextBlack.png",
"threshold": 0.98,
"type": "doNothing",
"next": [
"ReturnToMall"
]
},
"Stop": {
"filename": "",
"threshold": 0,
"type": "stop",
"next": []
}

2
update_resource.bat Normal file
View File

@@ -0,0 +1,2 @@
xcopy /e /y /i resource x64\Debug\resource
xcopy /e /y /i resource x64\Release\resource