package xyz.wbsite.jmacro; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.RandomUtil; import xyz.wbsite.jmacro.base.Legend; import xyz.wbsite.jmacro.base.ViewColor; import xyz.wbsite.jmacro.base.ViewPoint; import xyz.wbsite.jmacro.base.ViewRect; import xyz.wbsite.jmacro.util.ColorUtil; import xyz.wbsite.jmacro.util.ImageUtil; import xyz.wbsite.jmacro.util.Logger; import xyz.wbsite.jmacro.util.TaskUtil; import java.awt.*; import java.awt.event.InputEvent; import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * 脚本 * * @author wangbing * @version 0.0.1 * @since 1.8 */ public abstract class JMacro { /** * 默认超时秒数 */ private int defaultTimeOut = 10; /** * 机器人操作实例 */ private final Robot robot; /** * 视口区域 */ protected ViewRect focusRect; public JMacro() { try { // 机器人初始化 this.robot = new JRoot(); this.robot.setAutoDelay(30); this.startFocus(); } catch (AWTException e) { throw new RuntimeException(e); } } public int getDefaultTimeOut() { return defaultTimeOut; } public void setDefaultTimeOut(int defaultTimeOut) { this.defaultTimeOut = defaultTimeOut; } public Robot getRobot() { return robot; } /** * 开始聚焦 */ public void startFocus() { TaskUtil.asyncTask(() -> { focusRect = TaskUtil.timeTask(this::focus, defaultTimeOut, TimeUnit.SECONDS); if (focusRect != null) { Logger.info("聚焦成功"); } else { Logger.error("聚焦失败"); } }); } /** * 获取视口区域 * * @return 视口区域 */ public abstract ViewRect focus(); /** * 执行脚本 */ public abstract void run(); /** * 键盘按键组 */ public void keyInput(int... keycodes) { for (int keycode : keycodes) { keyPress(keycode); } } /** * 键盘按键 * keycode Key to press (e.g. KeyEvent.VK_A) */ public void keyPress(int keycode) { this.robot.keyPress(keycode); } /** * 鼠标移动 * * @param point 坐标点 */ public void mouseMove(ViewPoint point) { mouseMove(point, false); } /** * 鼠标移动 * * @param point 坐标点 * @param smooth 平滑移动 */ public void mouseMove(ViewPoint point, boolean smooth) { int endX = point.getX(); int endY = point.getY(); if (smooth) { // 获取当前鼠标位置 Point mousePoint = MouseInfo.getPointerInfo().getLocation(); int startX = mousePoint.x; int startY = mousePoint.y; // 求两点距离 double absX = Math.abs(startX - endX); double absY = Math.abs(startY - endY); double absZ = Math.sqrt(Math.pow(absX, 2) + Math.pow(absY, 2)); int times = (int) (absZ / 15 + (absZ % 15 > 0 ? 1 : 0)); int interval = (int) Math.max((absZ/4) / times, 10); times = Math.min(times, 10); // 分times次移动到指定点 for (int i = 1; i <= times; i++) { float d = i * 1.0f / times; int dx = (int) (startX + (endX - startX) * d); int dy = (int) (startY + (endY - startY) * d); robot.mouseMove(dx, dy); delay(RandomUtil.randomInt(interval - 5, interval + 5)); } } else { robot.mouseMove(endX, endY); } } /** * 鼠标左键单击 * * @param rect 点 */ public void mouseLeftClick(ViewPoint rect) { mouseMove(rect); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); delay(100); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); } /** * 鼠标左键单击 * * @param rect 矩形区域 */ public void mouseLeftClick(ViewRect rect) { mouseLeftClick(new ViewPoint(rect.getCenter().getX(), rect.getCenter().getY())); } /** * 鼠标左键拖拽 * * @param start 开始位置 * @param end 结束位置 */ public void mouseLeftDrag(ViewPoint start, ViewPoint end) { mouseLeftDrag(start, end, false); } /** * 鼠标左键拖拽 * * @param start 开始位置 * @param end 结束位置 * @param smooth 平滑移动 */ public void mouseLeftDrag(ViewPoint start, ViewPoint end, boolean smooth) { mouseMove(start, smooth); delay(); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); delay(); mouseMove(end, smooth); delay(); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); } /** * 鼠标右键拖拽 * * @param start 开始位置 * @param end 结束位置 */ public void mouseRightDrag(ViewPoint start, ViewPoint end) { mouseRightDrag(start, end, false); } /** * 鼠标右键拖拽 * * @param start 开始位置 * @param end 结束位置 * @param smooth 平滑移动 */ public void mouseRightDrag(ViewPoint start, ViewPoint end, boolean smooth) { mouseMove(start, smooth); delayUnstable(); robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); delayUnstable(); mouseMove(end, smooth); delayUnstable(); robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); } /** * 鼠标滚轮单击 * * @param rect 矩形区域 */ public void mouseWheelClick(ViewRect rect) { delayUnstable(); robot.mouseMove(rect.getCenter().getX(), rect.getCenter().getY()); delayUnstable(); robot.mousePress(InputEvent.BUTTON2_DOWN_MASK); delayUnstable(); robot.mouseRelease(InputEvent.BUTTON2_DOWN_MASK); } /** * 鼠标右键单击 * * @param rect 矩形区域 */ public void mouseRightClick(ViewRect rect) { delayUnstable(); robot.mouseMove(rect.getCenter().getX(), rect.getCenter().getY()); delayUnstable(); robot.mousePress(InputEvent.BUTTON3_DOWN_MASK); delayUnstable(); robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK); } /** * 鼠标左键双击 * * @param rect 矩形区域 */ public void mouseLeftDoubleClick(ViewRect rect) { delayUnstable(); robot.mouseMove(rect.getCenter().getX(), rect.getCenter().getY()); delayUnstable(); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); delay(60); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); delay(100); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); delay(60); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); } /** * 捕获指定区域屏幕 */ public BufferedImage capture(Robot robot, ViewRect viewRect) { return robot.createScreenCapture(new Rectangle(viewRect.getLeft(), viewRect.getTop(), viewRect.getWidth(), viewRect.getHeight())); } /** * 获取聚焦区域 */ public ViewRect getFocusRect() { if (focusRect != null) { return focusRect; } // 返回屏幕区域 return getScreenRect(); } /** * 获取聚焦区域 */ public ViewRect getScreenRect() { if (focusRect != null) { return focusRect; } // 返回屏幕区域 Toolkit tk = Toolkit.getDefaultToolkit(); return new ViewRect(0, 0, tk.getScreenSize().width, tk.getScreenSize().height); } /** * 延迟 */ public void delay() { delay(100); } /** * 延迟 */ public void delay(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { throw new RuntimeException(e); } } /** * 抖动延迟 */ public void delayUnstable() { delayUnstable(500); } /** * 抖动延迟 */ public void delayUnstable(long millis) { if (millis < 200) { delay(millis); return; } delay(RandomUtil.randomLong(millis - 100, millis + 100)); } /** * 全屏查找图片 * * @param pic 图片 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findPic(File pic, double minSimilar) { return findPic(getFocusRect(), pic, minSimilar); } /** * 查找图片 * * @param viewRect 查找范围(不设时,取全屏) * @param pic 待查找图片 * @param minSimilar 相似度 * @return 匹配区域 */ public ViewRect findPic(ViewRect viewRect, File pic, double minSimilar) { if (!pic.exists()) { Logger.error("[{}] does not exist!", pic.getAbsolutePath()); return null; } if (!pic.isFile()) { Logger.error("[{}] is not a file!", pic.getAbsolutePath()); return null; } Logger.info("查找图片:{}", pic.getAbsolutePath()); BufferedImage bufferedImage = ImageUtil.load(pic); return findPic(viewRect, bufferedImage, minSimilar, true); } /** * 查找图片 * * @param viewRect 查找范围(不设时,取全屏) * @param pic 待查找图片 * @param minSimilar 相似度 * @param fast 是否快速查找(快速查找通过优先定位四个顶点+中心,因此图的边缘和中心不能存在半透明等情况) * @return 匹配区域 */ public ViewRect findPic(ViewRect viewRect, BufferedImage pic, double minSimilar, boolean fast) { // 当聚焦区域为null时,默认全屏查找 if (viewRect == null) { viewRect = getFocusRect() != null ? getFocusRect() : getScreenRect(); } // 当查找区域比图片还小时,直接返回失败 if (viewRect.getWidth() < pic.getWidth() || viewRect.getHeight() < pic.getHeight()) { Logger.error("视口尺寸小于图片"); return null; } if (minSimilar > 1) { throw new RuntimeException("this minSimilar must be less than 1"); } // 获取实时屏幕 BufferedImage screen = capture(robot, viewRect); ImageUtil.show(screen); int[][] screenData = ImageUtil.getImageRGB(screen); int[][] picData = ImageUtil.getImageRGB(pic); // 得到图片左上角范围 int xMin = viewRect.getLeft(); // 因为坐标取像素点是从0开始,因此需要-1 int xMax = viewRect.getRight() - pic.getWidth(); int yMin = viewRect.getTop(); // 因为坐标取像素点是从0开始,因此需要-1 int yMax = viewRect.getBottom() - pic.getHeight(); double maxSimilar = 0; for (int y = yMin; y <= yMax; y++) { for (int x = xMin; x <= xMax; x++) { if (fast) { // 对关键点进行先期匹配,降低运算复杂度。如果关键点本身就不匹配,就没必要再去匹配小图的每一个像素点 // 左上角 boolean lt = ColorUtil.isSimilar(screenData[x - xMin][y - yMin], picData[0][0]); // 右上角 boolean rt = ColorUtil.isSimilar(screenData[x - xMin + pic.getWidth() - 1][y - yMin], picData[pic.getWidth() - 1][0]); // 左下角 boolean lb = ColorUtil.isSimilar(screenData[x - xMin][y - yMin + pic.getHeight() - 1], picData[0][pic.getHeight() - 1]); // 右下角 boolean rb = ColorUtil.isSimilar(screenData[x - xMin + pic.getWidth() - 1][y - yMin + pic.getHeight() - 1], picData[pic.getWidth() - 1][pic.getHeight() - 1]); //中心点 boolean cc = ColorUtil.isSimilar(screenData[x - xMin + pic.getWidth() / 2][y - yMin + pic.getHeight() / 2], picData[pic.getWidth() / 2][pic.getHeight() / 2]); // 五个关键点不一致,则没必要继续比下去 // 但要注意四个顶点+中心存在半透明情况,会导致关键点定位不准 if (!lt || !rt || !lb || !rb || !cc) { continue; } } // 统计相似点数 int samePixels = 0; for (int smallY = 0; smallY < pic.getHeight(); smallY++) { for (int smallX = 0; smallX < pic.getWidth(); smallX++) { if (ColorUtil.isSimilar(screenData[x + smallX - xMin][y + smallY - yMin], picData[smallX][smallY])) { samePixels++; } } } // 计算相似度 double similar = (double) samePixels / (pic.getWidth() * pic.getHeight()); maxSimilar = Math.max(maxSimilar, similar); if (similar >= minSimilar) { return new ViewRect(x, y, x + pic.getWidth(), y + pic.getHeight(), similar); } } } if (fast) { } Logger.info("最大相似度{}", NumberUtil.formatPercent(maxSimilar, 0)); return null; } /** * 等待并查找图片 * * @param rect 查找区域 * @param pic 图片 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindPic(ViewRect rect, File pic, double minSimilar) { return waitAndFindPic(rect, pic, minSimilar, defaultTimeOut); } /** * 等待并查找图片 * * @param pic 图片 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindPic(File pic, double minSimilar) { return waitAndFindPic(getFocusRect(), pic, minSimilar, defaultTimeOut); } /** * 等待并查找图片 * * @param pic 图片 * @param minSimilar 最低相似度 * @param seconds 最长等待秒数 * @return 匹配区域 */ public ViewRect waitAndFindPic(File pic, double minSimilar, long seconds) { return waitAndFindPic(getFocusRect(), pic, minSimilar, seconds); } /** * 等待并查找图片 * * @param rect 查找区域 * @param picFile 图片 * @param minSimilar 最低相似度 * @param seconds 最长等待秒数 * @return 匹配区域 */ public ViewRect waitAndFindPic(ViewRect rect, File picFile, double minSimilar, long seconds) { Logger.info("等待并查找图片:{}", picFile.getAbsolutePath()); BufferedImage pic = ImageUtil.load(picFile); return TaskUtil.timeTask(() -> { while (JMainService.getInstance().run) { ViewRect result = findPic(rect, pic, minSimilar, true); if (result != null) { return result; } } return null; }, seconds, TimeUnit.SECONDS); } /** * 查找图片 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findLegend(String legend, double minSimilar) { return findLegend(Legend.inflate(legend), minSimilar); } /** * 查找图片 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findLegend(Legend legend, double minSimilar) { return findLegend(getFocusRect(), legend, minSimilar, true); } /** * 查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findLegend(ViewRect rect, String legend, double minSimilar) { return findLegend(rect, Legend.inflate(legend), minSimilar); } /** * 查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findLegend(ViewRect rect, Legend legend, double minSimilar) { return findLegend(rect, legend, minSimilar, false); } /** * 查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findLegend(ViewRect rect, String legend, double minSimilar, boolean fast) { return findLegend(rect, Legend.inflate(legend), minSimilar, fast); } /** * 查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect findLegend(ViewRect rect, Legend legend, double minSimilar, boolean fast) { Logger.info("查找图例:{}", legend.getName()); return findPic(rect, legend.getImage(), minSimilar, fast); } /** * 等待并查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindLegend(ViewRect rect, Legend legend, double minSimilar, long seconds) { Logger.info("等待并查找图例:{}", legend.getName()); return TaskUtil.timeTask(() -> { while (JMainService.getInstance().run) { ViewRect result = findPic(rect, legend.getImage(), minSimilar, true); if (result != null) { return result; } } return null; }, seconds, TimeUnit.SECONDS); } /** * 等待并查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindLegend(ViewRect rect, String legend, double minSimilar, long seconds) { return waitAndFindLegend(rect, Legend.inflate(legend), minSimilar, seconds); } /** * 等待并查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindLegend(Legend legend, double minSimilar, long seconds) { return waitAndFindLegend(getFocusRect(), legend, minSimilar, seconds); } /** * 等待并查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindLegend(String legend, double minSimilar, long seconds) { return waitAndFindLegend(getFocusRect(), Legend.inflate(legend), minSimilar, seconds); } /** * 等待并查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindLegend(Legend legend, double minSimilar) { return waitAndFindLegend(getFocusRect(), legend, minSimilar, defaultTimeOut); } /** * 等待并查找图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndFindLegend(String legend, double minSimilar) { return waitAndFindLegend(getFocusRect(), Legend.inflate(legend), minSimilar, defaultTimeOut); } /** * 匹配图例和点击 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 是否成功 */ public boolean matchLegendAndClick(String legend, double minSimilar) { ViewRect matchLegend = matchLegend(legend, minSimilar); if (matchLegend != null) { Logger.info("点击【{}】", legend); mouseLeftClick(matchLegend); delay(500); return true; } else { return false; } } /** * 匹配图例和点击 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 是否成功 */ public boolean matchLegendAndClick(Legend legend, double minSimilar) { ViewRect matchLegend = matchLegend(legend, minSimilar); if (matchLegend != null) { Logger.info("点击【{}】", legend); mouseLeftClick(matchLegend); delay(500); return true; } else { return false; } } /** * 匹配图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配图片 */ public ViewRect matchLegend(String legend, double minSimilar) { return matchLegend(Legend.inflate(legend), minSimilar); } /** * 匹配图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配图片 */ public ViewRect matchLegend(Legend legend, double minSimilar) { BufferedImage image = ImageUtil.load(legend.getFile()); // 获取图例相对坐标 int offsetX = legend.getLocation().getX(); int offsetY = legend.getLocation().getY(); // 根据原点计算图例绝对坐标 ViewRect viewRect = new ViewRect(); viewRect.setLeft(getFocusRect().getLeft() + offsetX); viewRect.setTop(getFocusRect().getTop() + offsetY); viewRect.setRight(viewRect.getLeft() + image.getWidth()); viewRect.setBottom(viewRect.getTop() + image.getHeight()); Logger.info("匹配图例:{},区域:{}", legend.getName(), viewRect); return findPic(viewRect, image, minSimilar, false); } /** * 等待并匹配图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @param seconds 最长等待秒数 * @return 匹配区域 */ public ViewRect waitAndMatchLegend(Legend legend, double minSimilar, long seconds) { BufferedImage image = ImageUtil.load(legend.getFile()); // 获取图例相对坐标 int offsetX = legend.getLocation().getX(); int offsetY = legend.getLocation().getY(); // 根据原点计算图例绝对坐标 ViewRect viewRect = new ViewRect(); viewRect.setLeft(getFocusRect().getLeft() + offsetX); viewRect.setTop(getFocusRect().getTop() + offsetY); viewRect.setRight(viewRect.getLeft() + image.getWidth()); viewRect.setBottom(viewRect.getTop() + image.getHeight()); Logger.info("等待并匹配图例:{},区域:{}", legend.getName(), viewRect); return TaskUtil.timeTask(() -> { while (JMainService.getInstance().run) { ViewRect result = findPic(viewRect, image, minSimilar, false); if (result != null) { return result; } } return null; }, seconds, TimeUnit.SECONDS); } /** * 等待并匹配图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @param seconds 最长等待秒数 * @return 匹配区域 */ public ViewRect waitAndMatchLegend(String legend, double minSimilar, long seconds) { return waitAndMatchLegend(Legend.inflate(legend), minSimilar, seconds); } /** * 等待并匹配图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndMatchLegend(String legend, double minSimilar) { return waitAndMatchLegend(legend, minSimilar, defaultTimeOut); } /** * 等待并匹配图例 * * @param legend 图例 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect waitAndMatchLegend(Legend legend, double minSimilar) { return waitAndMatchLegend(legend, minSimilar, defaultTimeOut); } /** * 图例组合匹配,图例区域结果和入参长度一致,任意图例检测到后则会返回,其他未检测到的区域则为null *

* 说明:一个操作之后可能会有多个预期结果,以发起【进攻】操作为例,可能会提示多种结果如下: * 1.成功发起 * 2.敌人已逃走 * 3.兵力不足 * 不同的操作返回结果,会有不同的后续操作;如果以获取某预期结果去检测,考虑处理时间延迟等需要加上等待时间 * 不同结果的获取就会依次串行,这样检查肯定会浪费大量检测时间。因此正对此情况做了并联检测机制。 * * @param legends 图例 * @param minSimilar 最低相似度 * @return 匹配图片 */ public ViewRect[] matchLegends(String[] legends, double minSimilar) { ViewRect[] viewRects = new ViewRect[legends.length]; for (int i = 0; i < legends.length; i++) { String legend = legends[i]; viewRects[i] = matchLegend(legend, minSimilar); if (viewRects[i] != null) { return viewRects; } } return viewRects; } /** * 等待并匹配图例组合 * * @param legends 图例组 * @param minSimilar 最低相似度 * @param seconds 最长等待秒数 * @return 匹配区域 */ public ViewRect[] waitAndMatchLegends(String[] legends, double minSimilar, long seconds) { if (legends.length == 0) { return new ViewRect[0]; } Logger.info("等待并匹配图例组合:{}", String.join(",", legends)); return TaskUtil.timeTask(() -> { while (JMainService.getInstance().run) { ViewRect[] viewRects = matchLegends(legends, minSimilar); for (ViewRect viewRect : viewRects) { if (viewRect != null) { return viewRects; } } } return null; }, seconds, TimeUnit.SECONDS); } /** * 等待并匹配图例组合 * * @param legends 图例组 * @param minSimilar 最低相似度 * @return 匹配区域 */ public ViewRect[] waitAndMatchLegends(String[] legends, double minSimilar) { return waitAndMatchLegends(legends, minSimilar, defaultTimeOut); } /** * 匹配指定坐标色值 * * @param color 色值坐标点 * @return 是否匹配 */ public boolean matchColor(ViewColor color) { ViewRect rect = new ViewRect(color.getX(), color.getY(), color.getX(), color.getY()); // 获取实时屏幕 BufferedImage pointImage = capture(robot, rect); ImageUtil.show(pointImage); int[][] pointData = ImageUtil.getImageRGB(pointImage); boolean similar = ColorUtil.isSimilar(pointData[0][0], color.getColor()); Logger.info("比较色值:{},{} ==> {}", Integer.toHexString(pointData[0][0]), Integer.toHexString(color.getColor()), similar ? "相似" : "不同"); return similar; } /** * 查找颜色值占比 0~1 * * @param color 颜色值例,如:#ffffff * @return 占比 */ public double findColor(int left, int top, int right, int bottom, String color) { return findColor(of(left, top, right, bottom), color); } /** * 查找颜色值占比 0~1 * * @param rect 查找区域 * @param color 颜色值例,如:#ffffff * @return 占比 */ public double findColor(ViewRect rect, String color) { // 获取实时屏幕 BufferedImage capture = capture(robot, rect); ImageUtil.show(capture); List colors = new ArrayList<>(); for (int y = 0; y < capture.getHeight(); y++) { for (int x = 0; x < capture.getWidth(); x++) { colors.add("#" + Integer.toHexString(capture.getRGB(x, y) & 0xFFFFFF)); } } Map countMap = new HashMap<>(); for (String c : colors) { countMap.put(c, countMap.getOrDefault(c, 0) + 1); } double has = countMap.getOrDefault(color, 0); return has / colors.size(); } /** * 指定区域查找颜色值,查到后点击 * * @param color 颜色值例,如:#ffffff */ public boolean hasColorAndClick(int left, int top, int right, int bottom, String... color) { ViewRect viewRect = of(left, top, right, bottom); boolean hasColor = hasColor(viewRect, color); if (hasColor) { Logger.info("点击【{}】", viewRect); mouseLeftClick(viewRect); delay(500); return true; } else { return false; } } /** * 指定区域查找颜色 * * @param color 颜色值例,如:#ffffff * @return 占比 */ public boolean hasColor(int left, int top, int right, int bottom, String... color) { return hasColor(of(left, top, right, bottom), color); } /** * 指定区域查找颜色值,查到后点击 * * @param rect 查找区域 * @param color 颜色值例,如:#ffffff * @return 操作结果 */ public boolean hasColorAndClick(ViewRect rect, String... color) { boolean hasColor = hasColor(rect, color); if (hasColor) { Logger.info("点击【{}】", rect); mouseLeftClick(rect); delay(500); return true; } else { return false; } } /** * 指定区域查找颜色值 * * @param rect 查找区域 * @param color 颜色值例,如:#ffffff * @return 占比 */ public boolean hasColor(ViewRect rect, String... color) { // 获取实时屏幕 BufferedImage capture = capture(robot, rect); ImageUtil.show(capture); for (int y = 0; y < capture.getHeight(); y++) { for (int x = 0; x < capture.getWidth(); x++) { String col = "#" + Integer.toHexString(capture.getRGB(x, y) & 0xFFFFFF); for (String s : color) { if (ColorUtil.isSimilar(ColorUtil.hexToColor(s), ColorUtil.hexToColor(col))) { return true; } } } } return false; } /** * 等待并匹配图例 * * @param color 色值坐标点 * @param seconds 最长等待秒数 * @return 匹配区域 */ public boolean waitAndMatchColor(ViewColor color, long seconds) { Boolean result = TaskUtil.timeTask(() -> { while (JMainService.getInstance().run) { if (matchColor(color)) { return true; } delayUnstable(); } return null; }, seconds, TimeUnit.SECONDS); return Convert.toBool(result, false); } /** * 获取图例 * * @return 图例 */ public Legend of(String legend) { return Legend.inflate(legend); } /** * 将相对坐标转为绝对坐标 * * @return 绝对区域 */ public ViewRect of(int left, int top, int right, int bottom) { int ox = getFocusRect().getLeft(); int oy = getFocusRect().getTop(); return new ViewRect(left + ox, top + oy, right + ox, bottom + oy); } /** * 将相对区域转为绝对区域 * * @param relativeRect 相对区域 * @return 绝对区域 */ public ViewRect of(ViewRect relativeRect) { return new ViewRect(relativeRect.getLeft(), relativeRect.getTop(), relativeRect.getRight(), relativeRect.getBottom()); } /** * 将相对坐标转为绝对坐标 * * @return 绝对坐标 */ public ViewPoint of(int x, int y) { int ox = getFocusRect().getLeft(); int oy = getFocusRect().getTop(); return new ViewPoint(x + ox, y + oy); } /** * 将相对坐标转为绝对坐标 * * @param relativePoint 相对坐标 * @return 绝对区域 */ public ViewPoint of(ViewPoint relativePoint) { return of(relativePoint.getX(), relativePoint.getY()); } /** * 将相对坐标转为色值坐标 * * @return 绝对坐标 */ public ViewColor of(int x, int y, String hexColor) { int ox = getFocusRect().getLeft(); int oy = getFocusRect().getTop(); return new ViewColor(x + ox, y + oy, hexColor); } /** * 将相对坐标转为色值坐标 * * @return 绝对坐标 */ public String[] of(String... legends) { return legends; } /** * 将相对坐标转为色值坐标 * * @param relativePoint 相对坐标 * @return 绝对区域 */ public ViewColor of(ViewPoint relativePoint, String hexColor) { return of(relativePoint.getX(), relativePoint.getY(), hexColor); } }