朋友圈晒跳一跳成绩好久了,今天无意中看到以前一个同事小妞晒用代码刷分的视频,百度了一下果然看到了代码(代码在最后),几经波折,终于成功运行,刷了一点分数。
首先大概说一下步骤:
1.百度下载刷分代码
2.安装adb
3.找个手机使用USB调试模式连接电脑
4.启动跳一跳微信小程序
5.在eclipse中运行代码(此处要不断调试根据手机屏幕大小修改参数)
结果就是你的手机屏幕会自动按压然后让棋子跳。
再说下问题:
一、安装adb问题集:
下载adb工具地址
在此处的设备管理器中,如果没有安装在其他设备这里,adb就是一个感叹号,安装完毕后如图所示,会出现android device 这一行
安装的话在adb一栏里右击选择属性,弹出如下界面,点击更新驱动程序,选择浏览计算机选择程序(也就是第二个选项),此时会弹出一个浏览计算机上的驱动程序选项,选择安装包所在地,然后一切放行,就能安装。
问题来了:
安装完后,你在cmd命令窗口下能使用adb,但是在eclipse中运行代码完全没有效果(程序不报错,手机里也没有截图),然后eclipse控制台就显示图片不存在,
此时需要把你安装好的一个exe程序,两个动态链接库dll拷贝到如下两个目录下:(找不到就在c盘全局搜一下)
adb.exe
AdbWinApi.dll
AdbWinUsbApi.dll
C:\Windows\System32
C:\Windows\SysWOW64
此时一定要放在SysWOW64下,我是win7 64位,所以有这个目录(网上其他人说win32就不需要放这个了,我没试过),
如果没有放SysWOW64目录,此时eclipse运行依旧没有效果:但如果你在cmd中运行adb shell screencap -p /sdcard/tencent/customerpic/current.png这条命令,发现手机里面会有current.png图片,这说明eclipse没有找到对应的adb工具。
我找出这个问题是通过cd到System32和安装目录(C:\Program Files (x86)\Thunder Network\Thunder\Program)下,我在Program中运行上述命令成功,在System32中运行报错:
---------------------------adb.exe - 系统错误---------------------------
无法启动此程序,因为计算机中丢失 AdbWinApi.DLL。尝试重新安装该程序以解决此问题。
---------------------------
确定
---------------------------
OK,这说明System32中的adb找不到AdbWinApi.Dll动态链接文件,但明明就有,机缘巧合之下,老夫看到了SysWOW64这个目录,然后百度这个目录是什么意思,什么作用,OK,将拷贝到System32目录下的三个文件再次拷贝一份到此SysWOW64目录下,搞定。
问题二:device offline
在cmd命令窗口运行adb shell结果报错device offline,我以为是我adb安装有问题,百度了一大堆,试过adb kill server,adb remount等命令都没用,后来换了发现代码里面是/sdcard/,一看这应该是外置SD卡吧,是不是路径不对,(我用的是vivo x9,这手机没有外置SD卡选项),换了旧一点的手机(vivo y27)后运行adb shell可以了,不过/sdcard不是外置SD卡路径,而是手机U盘路径。
那么就说明不应该是代码路径问题,又是百度了一番,被告知是adb工具太老,adb version得到版本 1.0.26,好吧,我也懒得去找新版adb,用老的vivo y27调试了下能刷就行。
列举一下我学到的:
1.知道有adb这东西,也知道使用adb shell可以得到手机的bash会话,可以截图,使用adb pull可以从手机里面得到文件,更多命令的话官网有,我看多了也记不住。
2.知道原来代码里面java使用Runtime.getRuntime().exec()可以在windows中调用系统命令:
1
2
3
4
5
6
|
process = Runtime.getRuntime().exec(command);
System.out.println( "exec command start: " + command);
process.waitFor();
process.getInputStream();
BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(process.getErrorStream()));
String line = bufferedReader.readLine();
|
3.明白代码中通过计算截图的RGB颜色值等分析一张图片int pixel = bufferedImage.getRGB(x, y);
全部代码:
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
|
package com.lw.test;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
/**
* 参考知乎
*
* @link <a href="https://zhuanlan.zhihu.com/p/32452473" rel="external nofollow" target="_blank">https://zhuanlan.zhihu.com/p/32452473</a>
*
* 跳一跳辅助
*
* @author LeeHo
*/
public class JumpJumpHelper
{
private static final String IMAGE_NAME = "current.png" ;
private static final String STORE_DIR = "d:/jump_screencapture" ;
//数量
private static final int imageLengthLength = 5 ;
//存放图片的大小
private static final long [] imageLength = new long [imageLengthLength];
private final RGBInfo rgbInfo = new RGBInfo();
private final String path = "/sdcard/tencent/customerpic/" ;
private final String[] ADB_SCREEN_CAPTURE_CMDS =
{ "adb shell screencap -p " +path + IMAGE_NAME,
"adb pull " +path+ "current.png " + STORE_DIR };
//截屏中游戏分数显示区域最下方的Y坐标,300是 1920x1080的值,根据实际情况修改
private final int gameScoreBottomY = 300 ;
//按压的时间系数,可根据具体情况适当调节
private final double pressTimeCoefficient = 2.05 ;
//按压的起始点坐标,也是再来一局的起始点坐标
private final int swipeX = 280 ;
private final int swipeY = 600 ;
//二分之一的棋子底座高度
private final int halfBaseBoardHeight = 20 ;
//棋子的宽度,从截屏中量取,自行调节
private final int halmaBodyWidth = 74 ;
//游戏截屏里的两个跳板的中点坐标,主要用来计算角度,可依据实际的截屏计算,计算XY的比例
private final int boardX1 = 813 ;
private final int boardY1 = 1122 ;
private final int boardX2 = 310 ;
private final int boardY2 = 813 ;
/**
* 获取跳棋以及下一块跳板的中心坐标
*
* @return
* @author LeeHo
* @throws IOException
* @update 2017年12月31日 下午12:18:22
*/
private int [] getHalmaAndBoardXYValue(File currentImage) throws IOException
{
BufferedImage bufferedImage = ImageIO.read(currentImage);
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
System.out.println( "宽度:" + width + ",高度:" + height);
int halmaXSum = 0 ;
int halmaXCount = 0 ;
int halmaYMax = 0 ;
int boardX = 0 ;
int boardY = 0 ;
//从截屏从上往下逐行遍历像素点,以棋子颜色作为位置识别的依据,最终取出棋子颜色最低行所有像素点的平均值,即计算出棋子所在的坐标
for ( int y = gameScoreBottomY; y < height; y++)
{
for ( int x = 0 ; x < width; x++)
{
processRGBInfo(bufferedImage, x, y);
int rValue = this .rgbInfo.getRValue();
int gValue = this .rgbInfo.getGValue();
int bValue = this .rgbInfo.getBValue();
//根据RGB的颜色来识别棋子的位置,
if (rValue > 50 && rValue < 60 && gValue > 53 && gValue < 63 && bValue > 95 && bValue < 110 )
{
halmaXSum += x;
halmaXCount++;
//棋子底行的Y坐标值
halmaYMax = y > halmaYMax ? y : halmaYMax;
}
}
}
if (halmaXSum != 0 && halmaXCount != 0 )
{
//棋子底行的X坐标值
int halmaX = halmaXSum / halmaXCount;
//上移棋子底盘高度的一半
int halmaY = halmaYMax - halfBaseBoardHeight;
//从gameScoreBottomY开始
for ( int y = gameScoreBottomY; y < height; y++)
{
processRGBInfo(bufferedImage, 0 , y);
int lastPixelR = this .rgbInfo.getRValue();
int lastPixelG = this .rgbInfo.getGValue();
int lastPixelB = this .rgbInfo.getBValue();
//只要计算出来的boardX的值大于0,就表示下个跳板的中心坐标X值取到了。
if (boardX > 0 )
{
break ;
}
int boardXSum = 0 ;
int boardXCount = 0 ;
for ( int x = 0 ; x < width; x++)
{
processRGBInfo(bufferedImage, x, y);
int pixelR = this .rgbInfo.getRValue();
int pixelG = this .rgbInfo.getGValue();
int pixelB = this .rgbInfo.getBValue();
//处理棋子头部比下一个跳板还高的情况
if (Math.abs(x - halmaX) < halmaBodyWidth)
{
continue ;
}
//从上往下逐行扫描至下一个跳板的顶点位置,下个跳板可能为圆形,也可能为方框,取多个点,求平均值
if ((Math.abs(pixelR - lastPixelR) + Math.abs(pixelG - lastPixelG) + Math.abs(pixelB - lastPixelB)) > 10 )
{
boardXSum += x;
boardXCount++;
}
}
if (boardXSum > 0 )
{
boardX = boardXSum / boardXCount;
}
}
//按实际的角度来算,找到接近下一个 board 中心的坐标
boardY = ( int ) (halmaY - Math.abs(boardX - halmaX) * Math.abs(boardY1 - boardY2)
/ Math.abs(boardX1 - boardX2));
if (boardX > 0 && boardY > 0 )
{
int [] result = new int [ 4 ];
//棋子的X坐标
result[ 0 ] = halmaX;
//棋子的Y坐标
result[ 1 ] = halmaY;
//下一块跳板的X坐标
result[ 2 ] = boardX;
//下一块跳板的Y坐标
result[ 3 ] = boardY;
return result;
}
}
return null ;
}
/**
* 执行命令
*
* @param command
* @author LeeHo
* @update 2017年12月31日 下午12:13:39
*/
private void executeCommand(String command)
{
Process process = null ;
try
{
process = Runtime.getRuntime().exec(command);
System.out.println( "exec command start: " + command);
process.waitFor();
process.getInputStream();
BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(process.getErrorStream()));
String line = bufferedReader.readLine();
if (line != null )
{
System.out.println(line);
}
bufferedReader = new BufferedReader( new InputStreamReader(process.getInputStream()));
String line02 = bufferedReader.readLine();
if (line02 != null )
{
System.out.println(line02);
}
System.out.println( "exec command end: " + command);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (process != null )
{
process.destroy();
}
}
}
/**
* ADB获取安卓截屏
*
* @author LeeHo
* @update 2017年12月31日 下午12:11:42
*/
private void executeADBCaptureCommands()
{
for (String command : ADB_SCREEN_CAPTURE_CMDS)
{
executeCommand(command);
}
}
/**
* 跳一下
*
* @param distance
* @author LeeHo
* @update 2017年12月31日 下午12:23:19
*/
private void doJump( double distance)
{
System.out.println( "distance: " + distance);
//计算按压时间,最小200毫秒
int pressTime = ( int ) Math.max(distance * pressTimeCoefficient, 200 );
System.out.println( "pressTime: " + pressTime);
//执行按压操作
String command = String.format( "adb shell input swipe %s %s %s %s %s" , swipeX, swipeY, swipeX, swipeY,
pressTime);
System.out.println(command);
executeCommand(command);
}
/**
* 再来一局
*
* @author LeeHo
* @update 2017年12月31日 下午12:47:06
*/
private void replayGame()
{
String command = String.format( "adb shell input tap %s %s" , swipeX, swipeY);
executeCommand(command);
}
/**
* 计算跳跃的距离,也即两个点之间的距离
*
* @param halmaX
* @param halmaY
* @param boardX
* @param boardY
* @return
* @author LeeHo
* @update 2017年12月31日 下午12:27:30
*/
private double computeJumpDistance( int halmaX, int halmaY, int boardX, int boardY)
{
return Math.sqrt(Math.pow(Math.abs(boardX - halmaX), 2 ) + Math.pow(Math.abs(boardY - halmaY), 2 ));
}
public static void main(String[] args)
{
JumpJumpHelper jumpjumpHelper = new JumpJumpHelper();
// String command = "adb shell screencap -p "+jumpjumpHelper.path + IMAGE_NAME;
//// command = "adb devices";
// jumpjumpHelper.executeCommand(command);
//
// if(true){return ;}
try
{
File storeDir = new File(STORE_DIR);
if (!storeDir.exists()) {
boolean flag = storeDir.mkdir();
if (!flag) {
System.err.println( "创建图片存储目录失败" );
return ;
}
}
//执行次数
int executeCount = 0 ;
for (;;)
{
//执行ADB命令,获取安卓截屏
jumpjumpHelper.executeADBCaptureCommands();
File currentImage = new File(STORE_DIR, IMAGE_NAME);
if (!currentImage.exists())
{
System.out.println( "图片不存在" );
continue ;
}
long length = currentImage.length();
imageLength[executeCount % imageLengthLength] = length;
//查看是否需要重新开局
jumpjumpHelper.checkDoReplay();
executeCount++;
System.out.println( "当前第" + executeCount + "次执行!" );
//获取跳棋和底板的中心坐标
int [] result = jumpjumpHelper.getHalmaAndBoardXYValue(currentImage);
if (result == null )
{
System.out.println( "The result of method getHalmaAndBoardXYValue is null!" );
continue ;
}
int halmaX = result[ 0 ];
int halmaY = result[ 1 ];
int boardX = result[ 2 ];
int boardY = result[ 3 ];
System.out.println( "halmaX: " + halmaX + ", halmaY: " + halmaY + ", boardX: " + boardX + ", boardY: "
+ boardY);
//计算跳跃的距离
double jumpDistance = jumpjumpHelper.computeJumpDistance(halmaX, halmaY, boardX, boardY);
jumpjumpHelper.doJump(jumpDistance);
//每次停留2.5秒
TimeUnit.MILLISECONDS.sleep( 2500 );
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 检查是否需要重新开局
*
* @author LeeHo
* @update 2017年12月31日 下午1:39:18
*/
private void checkDoReplay()
{
if (imageLength[ 0 ] > 0 && imageLength[ 0 ] == imageLength[ 1 ] && imageLength[ 1 ] == imageLength[ 2 ]
&& imageLength[ 2 ] == imageLength[ 3 ] && imageLength[ 3 ] == imageLength[ 4 ])
{
//此时表示已经连续5次图片大小一样了,可知当前屏幕处于再来一局
Arrays.fill(imageLength, 0 );
//模拟点击再来一局按钮重新开局
replayGame();
}
}
/**
* 获取指定坐标的RGB值
*
* @param bufferedImage
* @param x
* @param y
* @author LeeHo
* @update 2017年12月31日 下午12:12:43
*/
private void processRGBInfo(BufferedImage bufferedImage, int x, int y)
{
this .rgbInfo.reset();
int pixel = bufferedImage.getRGB(x, y);
//转换为RGB数字
this .rgbInfo.setRValue((pixel & 0xff0000 ) >> 16 );
this .rgbInfo.setGValue((pixel & 0xff00 ) >> 8 );
this .rgbInfo.setBValue((pixel & 0xff ));
}
class RGBInfo
{
private int RValue;
private int GValue;
private int BValue;
public int getRValue()
{
return RValue;
}
public void setRValue( int rValue)
{
RValue = rValue;
}
public int getGValue()
{
return GValue;
}
public void setGValue( int gValue)
{
GValue = gValue;
}
public int getBValue()
{
return BValue;
}
public void setBValue( int bValue)
{
BValue = bValue;
}
public void reset()
{
this .RValue = 0 ;
this .GValue = 0 ;
this .BValue = 0 ;
}
}
}
|
当然,现在刷了一会就被清空成绩,但作为一个程序员知道还是好的。从一开始的post提交漏洞,让电脑作为代理抓包修改数据,现在代码模拟点击(虽然不会生效。)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/lw18751836671/article/details/78981527