-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelper_single.py
231 lines (188 loc) · 8.95 KB
/
helper_single.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# -*- coding:utf-8 -*-
from __future__ import print_function
import ctypes, sys, time, os, random, json
import keyboard
import cv2
from cv2 import data
import win32gui,win32ui,win32api,win32con
from tqdm import tqdm
from datetime import datetime
class Helper():
def __init__(self,title_name='阴阳师-网易游戏',num_runs=100,config_file_index = 0,
device_width = 2560,device_height= 1440):
self.device_width = device_width
self.device_height = device_height
self.handle = win32gui.FindWindow(None,title_name)
self.notCheck = []
self.failNum = 0
self.wait = False # 暂停
#获取句柄窗口的大小信息
left, top, right, bot = win32gui.GetWindowRect(self.handle)
self.width = right - left
self.height = bot - top
# print(width,height)
#返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
self.handleDC = win32gui.GetWindowDC(self.handle)
#创建设备描述表
self.mfcDC = win32ui.CreateDCFromHandle(self.handleDC)
#创建内存设备描述表
self.saveDC = self.mfcDC.CreateCompatibleDC()
#创建位图对象准备保存图片
self.saveBitMap = win32ui.CreateBitmap()
#为bitmap开辟存储空间
self.saveBitMap.CreateCompatibleBitmap(self.mfcDC,self.width,self.height)
# Initialize configuration for target pixel and clicking area
print("选择配置文件")
for files in os.walk('./configs'):
for index,file in enumerate(files[2]):
print('[%d] %s' % (index,os.path.splitext(file)[0][7:]))
print()
print('默认选择 [%d],请输入:' % config_file_index,end="")
config_file_input = input()
config_file = './configs/' + (files[2][int(config_file_input)] if config_file_input != "" else files[2][int(config_file_index)])
# print(config_file)
with open(config_file,'r') as f:
config = json.load(f)
self.path = config.pop('path')
self.endFlag = config.pop('endFlag')
self.timeCost = config.pop('timeCost') # 流程最少耗时,单位秒
self.failFlag = config.pop('failFlag')
self.images = config
# Get the input for total running time
print("运行次数(默认%d):" % num_runs, end="")
num_runs_input = input()
num_runs = int(num_runs_input) if num_runs_input != "" else num_runs
print()
print('%s 开始运行 %s' % ('*'*20,'*'*20))
print()
print('配置文件:%s' % config_file)
print('运行次数:%d' % num_runs)
print('按下 F12 暂停/运行脚本')
print()
# Initialize progressing bar with the total running times
self.pbar = tqdm(total=num_runs, ascii=True)
keyboard.on_press_key("F12", self.pause)
def __del__(self):
self.pbar.close()
# Remove DCs
win32gui.DeleteObject(self.saveBitMap.GetHandle())
self.saveDC.DeleteDC()
self.mfcDC.DeleteDC()
win32gui.ReleaseDC(self.handle, self.handleDC)
def click(self,x, y):
long_position = win32api.MAKELONG(x,y)
win32api.SendMessage(self.handle, win32con.WM_LBUTTONDOWN, 0, long_position) # 模拟鼠标按下
time.sleep(0.01 + random.random() * 0.02)
win32api.SendMessage(self.handle, win32con.WM_LBUTTONUP, 0, long_position) # 模拟鼠标弹起
def screenshot(self):
path = os.path.abspath('.') + '\images\\'
#将截图保存到saveBitMap中
self.saveDC.SelectObject(self.saveBitMap)
#保存bitmap到内存设备描述表
self.saveDC.BitBlt((0,0), (self.width,self.height), self.mfcDC, (0, 0), win32con.SRCCOPY)
self.saveBitMap.SaveBitmapFile(self.saveDC, path+"screen.bmp")
def resize_img(self,img_path):
img1 = cv2.imread(img_path, 0)
img2 = cv2.imread('images/screen.bmp', 0)
height, width = img1.shape[:2]
ratio = self.device_width / img2.shape[1]
size = (int(width/ratio), int(height/ratio))
return cv2.resize(img1, size, interpolation = cv2.INTER_AREA)
def Image_to_position(self,image, m = 0, similarity = 0.9):
image_path = 'images/' + self.path + str(image) + '.bmp'
screen = cv2.imread('images/screen.bmp', 0)
# template = cv2.imread(image_path, 0)
template = self.resize_img(image_path)
methods = [cv2.TM_CCOEFF_NORMED, cv2.TM_SQDIFF_NORMED, cv2.TM_CCORR_NORMED]
image_x, image_y = template.shape[:2]
result = cv2.matchTemplate(screen, template, methods[m])
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# print(max_val)
if max_val >= similarity:
global center
# center = (max_loc[0] + image_y / 2, max_loc[1] + image_x / 2)
center = (max_loc[0], max_loc[1])
# print(center)
return center
else:
return False
def recursion(self,images):
for img,cnf in images.items():
if img in self.notCheck:
continue
similarity = cnf.get('similarity') if cnf.get('similarity') is not None else 0.9
# 查找图片
if self.Image_to_position(img, m = 0,similarity=similarity) != False:
# 找到图片看是否点击或继续递归查找
if cnf.get('found') is not None:
# 立即点击
if type(cnf.get('found')) == int:
self.now_img = img
time.sleep(0.2)
offsetX = int((cnf.get('offsetX') if cnf.get('offsetX') is not None else 0) * (self.width / self.device_width))
offsetY = int((cnf.get('offsetY') if cnf.get('offsetY') is not None else 0) * (self.height / self.device_height))
x = int(center[0]) + random.randrange(int(50 * (self.width / self.device_width))) + offsetX
y = int(center[1]) + random.randrange(int(25 * (self.height / self.device_height))) + offsetY
for i in range(cnf.get('found')):
self.click(x,y)
# print(img,x,y)
time.sleep(cnf.get('delay') if cnf.get('delay') is not None else 0)
# 单次流程不再检查
if cnf.get('checkAgain') is not None:
if cnf.get('checkAgain') == 0:
self.notCheck.append(cnf.get('checkImg'))
else:
self.recursion(cnf['found'])
else:
# 找不到图片看是否有操作或继续递归查找
if cnf.get('notFound') is not None:
if cnf.get('notFound') == 'pass':
pass
else:
self.recursion(cnf['notFound'])
def pause(self,key):
# print(key)
self.wait = not self.wait
if self.wait == True:
print('暂停运行,按 F12 继续运行')
else:
print('开始运行,按 F12 暂停运行')
def run(self):
self.now_img = ''
self.time = datetime.now()
while True:
while not self.wait:
self.screenshot()
self.recursion(self.images)
# 一个完整流程结束,可能多次点击
if self.now_img == self.endFlag:
# 判断当前时间与上次一次完整流程的时间差
if (datetime.now() - self.time).seconds >= self.timeCost:
self.time = datetime.now()
self.notCheck = []
self.pbar.update()
if self.pbar.n >= self.pbar.total:
return
time.sleep(0.5 + random.random() * 0.02)
elif self.now_img == self.failFlag:
self.failNum += 1
self.notCheck = []
print('已失败 %d 次!!!' % self.failNum)
time.sleep(2 + random.random() * 0.02)
# def is_admin():
# try:
# return ctypes.windll.shell32.IsUserAnAdmin()
# except:
# return False
if __name__ == '__main__':
# if is_admin():
device_width=2560
device_height=1440
config_file_index = 0
helper = Helper(title_name='阴阳师-网易游戏', config_file_index = config_file_index,
device_width=device_width,device_height=device_height)
helper.run()
helper.__del__()
# else:
# if sys.version_info[0] == 3:
# ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)