首页 > 开发 > Java > 正文

微信跳一跳刷分java代码实现

2024-07-13 10:16:08
字体:
来源:转载
供稿:网友

朋友圈晒跳一跳成绩好久了,今天无意中看到以前一个同事小妞晒用代码刷分的视频,百度了一下果然看到了代码(代码在最后),几经波折,终于成功运行,刷了一点分数。

首先大概说一下步骤:

1.百度下载刷分代码

2.安装adb

3.找个手机使用USB调试模式连接电脑

4.启动跳一跳微信小程序

5.在eclipse中运行代码(此处要不断调试根据手机屏幕大小修改参数)

结果就是你的手机屏幕会自动按压然后让棋子跳。

再说下问题:

一、安装adb问题集:

下载adb工具地址

在此处的设备管理器中,如果没有安装在其他设备这里,adb就是一个感叹号,安装完毕后如图所示,会出现android device 这一行

Java,微信跳一跳刷分,Java微信跳一跳,Java跳一跳

安装的话在adb一栏里右击选择属性,弹出如下界面,点击更新驱动程序,选择浏览计算机选择程序(也就是第二个选项),此时会弹出一个浏览计算机上的驱动程序选项,选择安装包所在地,然后一切放行,就能安装。

Java,微信跳一跳刷分,Java微信跳一跳,Java跳一跳

Java,微信跳一跳刷分,Java微信跳一跳,Java跳一跳

问题来了:

安装完后,你在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提交漏洞,让电脑作为代理抓包修改数据,现在代码模拟点击(虽然不会生效。)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表