朋友圈晒跳一跳成绩好久了,今天无意中看到以前一个同事小妞晒用代码刷分的视频,百度了一下果然看到了代码(代码在最后),几经波折,终于成功运行,刷了一点分数。
首先大概说一下步骤:
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中调用系统命令:
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);
全部代码:
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提交漏洞,让电脑作为代理抓包修改数据,现在代码模拟点击(虽然不会生效。)
更多内容大家可以参考专题《微信跳一跳》进行学习。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍微信跳一跳游戏Android刷分代码,包括了微信跳一跳游戏Android刷分代码的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了微信跳一跳游戏Android实现刷分,供大家参考,具体内容如下 更多内容大家可以参考专题《微信跳一跳》进行学习。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
本文向大家介绍微信跳一跳辅助Java代码实现,包括了微信跳一跳辅助Java代码实现的使用技巧和注意事项,需要的朋友参考一下 微信跳一跳辅助的Java具体实现代码,供大家参考,具体内容如下 1.参考知乎教你用Python来玩微信跳一跳,鉴于本人Python一直都是半吊子水平,之前打算用python刷分,可无奈安装python环境各种模块缺失,报错不停,于是乎,使用Java重新实现了一下。 2.环境配
本文向大家介绍微信跳一跳自动脚本C#代码实现,包括了微信跳一跳自动脚本C#代码实现的使用技巧和注意事项,需要的朋友参考一下 前言 CSDN前阵子推送了篇文章,讲的是微信跳一跳的技术实现,大致浏览,发现难度不高,很适合练手。 思路 ADB得到屏幕截图,转换成bitmap逐像素分析图像,得到跳跃起点和终点坐标,最后ADB按压屏幕进行跳跃 相关知识 ADB创建 ·在https://adb.clockw
本文向大家介绍微信小程序跳一跳游戏 python脚本跳一跳刷高分技巧,包括了微信小程序跳一跳游戏 python脚本跳一跳刷高分技巧的使用技巧和注意事项,需要的朋友参考一下 前言 小程序跳一跳最近很火,之前爆出微信游戏小程序漏洞,网上也不乏大神。这里就用一大神的python脚本来刷下高分。 跳一跳python脚本传送门 配置过程 注: 电脑环境未配置python环境,请自行谷歌或者百度配置,这里
本文向大家介绍安卓版本微信跳一跳自动执行代码剖析,包括了安卓版本微信跳一跳自动执行代码剖析的使用技巧和注意事项,需要的朋友参考一下 手动版的这里不多说,图像识别,坐标计算跳跃,要想得高分会点的手疼。这里主要剖析下自动版的,这里仅介绍安卓版本。 整体的结构 脚本的整体结构还是比较简洁的,如下图所示。 手机连接PC,PC通过adb命令对手机游戏界面进行截图; PC通过adb命令将该截图拷贝回PC; P
本文向大家介绍分数霸榜! python助你微信跳一跳拿高分,包括了分数霸榜! python助你微信跳一跳拿高分的使用技巧和注意事项,需要的朋友参考一下 前言 最近微信的跳一跳很火,大家看到排行榜上几百上千的分数,再看看自己百分左右的分数肯定很难过,我手残怪我吗?没关系,如果你跟着我来,也能让你分数霸榜。 原理 首先大家是有一个直观感受,根据两个箱子距离的不同,需要按压的时间也是不一样的,一般来说,