You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1207 lines
36 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
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. <code>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++) {
double d = ValueUtil.easeOut(i * 1.0D / times);
int dx = (int) (startX + (endX - startX) * d);
int dy = (int) (startY + (endY - startY) * d);
robot.mouseMove(dx, dy);
delay(RandomUtil.randomInt(interval - 3, interval + 3));
}
} else {
robot.mouseMove(endX, endY);
delay(10);
}
}
/**
* 鼠标左键单击
*
* @param rect 矩形区域
*/
public void mouseLeftClick(ViewRect rect) {
mouseLeftClick(rect, 100);
}
/**
* 鼠标左键单击
*
* @param rect 矩形区域
*/
public void mouseLeftClick(ViewRect rect, long delay) {
mouseLeftClick(new ViewPoint(rect.getCenter().getX(), rect.getCenter().getY()), delay);
}
/**
* 鼠标左键单击
*
* @param rect 点
*/
public void mouseLeftClick(ViewPoint rect) {
mouseLeftClick(rect, 100);
}
/**
* 鼠标左键单击
*
* @param rect 点
*/
public void mouseLeftClick(ViewPoint rect, long delay) {
// 获取当前鼠标位置
Point mousePoint = MouseInfo.getPointerInfo().getLocation();
if (mousePoint.x != rect.getX() || mousePoint.y != rect.getY()) {
Logger.info("鼠标移动至[{},{}]", rect.getX(), rect.getY());
mouseMove(rect);
}
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
delay(delay);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
}
/**
* 鼠标左键拖拽
*
* @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 void sendCopyCommand() {
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_C);
robot.keyRelease(KeyEvent.VK_C);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
/**
* 执行粘贴命令
*/
public void sendPasteCommand() {
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
/**
* 捕获指定区域屏幕
*/
public BufferedImage capture(Robot robot, ViewRect viewRect) {
return robot.createScreenCapture(new Rectangle(viewRect.getLeft(), viewRect.getTop(), viewRect.getWidth(), viewRect.getHeight()));
}
/**
* 获取聚焦区域
*/
public ViewRect getFocusRect() {
return focusRect;
}
/**
* 获取聚焦区域
*/
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.info("[{}] does not exist!", pic.getAbsolutePath());
return null;
}
if (!pic.isFile()) {
Logger.info("[{}] 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.info("视口尺寸小于图片");
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 boolean findLegendAndClick(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 findLegendAndClick(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 boolean findLegendAndClick(ViewRect rect, String legend, double minSimilar) {
ViewRect matchLegend = findLegend(rect, legend, minSimilar);
if (matchLegend != null) {
Logger.info("点击【{}】", legend);
mouseLeftClick(matchLegend);
delay(500);
return true;
} else {
return false;
}
}
/**
* 指定区域查找图例并点击
*
* @param legend 图例
* @param minSimilar 最低相似度
* @return 匹配区域
*/
public boolean findLegendAndClick(ViewRect rect, Legend legend, double minSimilar) {
ViewRect matchLegend = findLegend(rect, legend, minSimilar);
if (matchLegend != null) {
Logger.info("点击【{}】", legend);
mouseLeftClick(matchLegend);
delay(500);
return true;
} else {
return false;
}
}
/**
* 查找图片
*
* @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 rect 范围
* @param legend 图例
* @param minSimilar 最低相似度
* @return 匹配区域
*/
public ViewRect findLegend(ViewRect rect, String legend, double minSimilar) {
return findLegend(rect, Legend.inflate(legend), minSimilar);
}
/**
* 查找图例
*
* @param rect 范围
* @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
* <p>
* 说明:一个操作之后可能会有多个预期结果,以发起【进攻】操作为例,可能会提示多种结果如下:
* 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));
ViewRect[] result = TaskUtil.timeTask(() -> {
while (JMainService.getInstance().run) {
ViewRect[] viewRects = matchLegends(legends, minSimilar);
for (ViewRect viewRect : viewRects) {
if (viewRect != null) {
return viewRects;
}
}
}
return new ViewRect[legends.length];
}, seconds, TimeUnit.SECONDS);
if (result == null) {
result = new ViewRect[legends.length];
}
return result;
}
/**
* 等待并匹配图例组合
*
* @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<String> 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<String, Integer> 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);
}
}

Powered by TurnKey Linux.