Files

457 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 对指定区域进行OCR文字识别
* @param {number} x - 区域左上角x坐标默认为0
* @param {number} y - 区域左上角y坐标默认为0
* @param {number} w - 区域宽度默认为1920
* @param {number} h - 区域高度默认为1080
* @returns {Promise<string|null>} 返回识别到的文本内容如果识别失败则返回null
*/
async function ocrRegion(x = 0,
y = 0,
w = 1920,
h = 1080) {
// 创建OCR识别对象使用指定的坐标和尺寸
let recognitionObjectOcr = RecognitionObject.Ocr(x, y, w, h);
// 捕获游戏区域图像
let region3 = captureGameRegion()
try {
// 在捕获的区域中查找OCR识别对象
let res = region3.find(recognitionObjectOcr);
// 返回识别到的文本内容如果不存在则返回undefined
return res?.text
} catch (e) {
// 捕获并记录错误信息
log.error("识别异常:{1}", e.message)
return null
} finally {
// 确保释放区域资源
region3.dispose()
}
}
/**
* 获取当前日期的星期信息
* @param {boolean} [calibrationGameRefreshTime=true] 是否进行游戏刷新时间校准
* @returns {Object} 返回包含星期数字和星期名称的对象
*/
async function getDayOfWeek(calibrationGameRefreshTime = true) {
// 获取当前日期对象
let today = new Date();//4点刷新 所以要减去4小时
if (calibrationGameRefreshTime) {
today.setHours(today.getHours() - 4); // 减去 4 小
}
// 获取当前日期是星期几0代表星期日1代表星期一以此类推
const day = today.getDay();
// 创建包含星期名称的数组
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
let weekDay = `${weekDays[day]}`;
log.debug(`今天是[{day}]`, day)
log.debug(`今天是[{weekDays}]`, weekDay)
// 返回包含星期数字和对应星期名称的对象
return {
day: day,
dayOfWeek: weekDay
}
}
const commonPath = 'assets/'
const commonMap = new Map([
['main_ui', {
path: `${commonPath}`,
name: 'paimon_menu',
type: '.png',
}],
['yue', {
path: `${commonPath}`,
name: 'yue',
type: '.png',
}],
['200', {
path: `${commonPath}`,
name: '200',
type: '.png',
}],
['add_button', {
path: `${commonPath}`,
name: 'add_button',
type: '.jpg',
}],
['out_domain', {
path: `${commonPath}`,
name: 'out_domain',
type: '.jpg',
}],
])
const genshinJson = {
width: 1920,//genshin.width,
height: 1080,//genshin.height,
}
/**
* 根据键值获取JSON路径
* @param {string} key - 要查找的键值
* @returns {any} 返回与键值对应的JSON路径值
*/
function getJsonPath(key) {
return commonMap.get(key); // 通过commonMap的get方法获取指定键对应的值
}
// 判断是否在主界面的函数
const isInMainUI = () => {
// let name = '主界面'
let main_ui = getJsonPath('main_ui');
// 定义识别对象
let paimonMenuRo = RecognitionObject.TemplateMatch(
file.ReadImageMatSync(`${main_ui.path}${main_ui.name}${main_ui.type}`),
0,
0,
genshinJson.width / 3.0,
genshinJson.width / 5.0
);
let captureRegion = captureGameRegion();
try {
let res = captureRegion.find(paimonMenuRo);
return !res.isEmpty();
} finally {
captureRegion.dispose()
}
};
async function toMainUi() {
let ms = 300
let index = 1
await sleep(ms);
while (!isInMainUI()) {
await sleep(ms);
await genshin.returnMainUi(); // 如果未启用,则返回游戏主界面
await sleep(ms);
if (index > 3) {
throwError(`多次尝试返回主界面失败`);
}
index += 1
}
}
const isInOutDomainUI = async () => {
// // let name = '主界面'
// let main_ui = getJsonPath('out_domain');
// // 定义识别对象
// let paimonMenuRo = RecognitionObject.TemplateMatch(
// file.ReadImageMatSync(`${main_ui.path}${main_ui.name}${main_ui.type}`),
// 0,
// 0,
// genshinJson.width / 3.0,
// genshinJson.width / 5.0
// );
// let captureRegion = captureGameRegion();
// try {
// let res = captureRegion.find(paimonMenuRo);
// return !res.isEmpty();
// }finally {
// captureRegion.dispose()
// }
//509, 259, 901, 563
const text = "退出秘境";
const ocrRegion = {
x: 509,
y: 259,
w: 901,
h: 563
}
const find = await findText(text, ocrRegion.x, ocrRegion.y, ocrRegion.w, ocrRegion.h)
log.debug("识别结果:{1}", find)
return find && find.includes(text)
};
/**
* 退出秘境的UI处理函数
* 该函数用于处理退出秘境界面的相关操作,包括点击确认按钮和检测界面状态
*/
async function outDomainUI() {
log.info(`{0}`,"退出秘境");
const ocrRegion = {
x: 509,
y: 259,
w: 901,
h: 563
}
let ms = 300
let index = 1
let tryMax = false
let inMainUI = false
await sleep(ms);
//点击确认按钮
await findTextAndClick('地脉异常')
await sleep(ms);
while (!await isInOutDomainUI()) {
if (isInMainUI()) {
inMainUI = true
break
}
await sleep(ms);
await keyPress("ESCAPE");
await sleep(ms * 2);
if (index > 3) {
log.error(`多次尝试匹配退出秘境界面失败 假定已经退出处理`);
tryMax = true
break
}
index += 1
}
if ((!tryMax) && (!inMainUI) && await isInOutDomainUI()) {
try {
//点击确认按钮
await findTextAndClick('确认', ocrRegion.x, ocrRegion.y, ocrRegion.w, ocrRegion.h)
} catch (e) {
// log.error(`多次尝试点击确认失败 假定已经退出处理`);
}
}
}
const isInOutStygianOnslaughtUI = async () =>{
const text = "退出挑战";
const ocrRegion = {
x: 509,
y: 259,
w: 901,
h: 563
}
const find = await findText(text, ocrRegion.x, ocrRegion.y, ocrRegion.w, ocrRegion.h)
log.debug("识别结果:{1}", find)
return find && find.includes(text)
}
async function outStygianOnslaughtUI() {
log.info(`{0}`,"退出挑战");
const ocrRegion = {
x: 509,
y: 259,
w: 901,
h: 563
}
let ms = 300
let index = 1
let tryMax = false
let inMainUI = false
await sleep(ms);
while (!await isInOutStygianOnslaughtUI()) {
if (isInMainUI()) {
inMainUI = true
break
}
await sleep(ms);
await keyPress("ESCAPE");
await sleep(ms * 2);
if (index > 3) {
log.error(`多次尝试匹配退出秘境界面失败 假定已经退出处理`);
tryMax = true
break
}
index += 1
}
if ((!tryMax) && (!inMainUI) && await isInOutStygianOnslaughtUI()) {
try {
//点击确认按钮
await findTextAndClick('退出挑战', ocrRegion.x, ocrRegion.y, ocrRegion.w, ocrRegion.h)
} catch (e) {
// log.error(`多次尝试点击确认失败 假定已经退出处理`);
}
}
}
/**
* 在指定区域内查找文本内容
* @param {string} text - 要查找的文本内容
* @param {number} x - 查找区域的左上角x坐标默认为0
* @param {number} y - 查找区域的左上角y坐标默认为0
* @param {number} w - 查找区域的宽度默认为1920
* @param {number} h - 查找区域的高度默认为1080
* @param {number} attempts - 尝试查找的次数默认为5
* @param {number} interval - 每次尝试之间的间隔时间(毫秒)默认为50
* @returns {Promise<string>} 返回找到的文本内容,如果未找到则返回空字符串
*/
async function findText(
text,
x = 0,
y = 0,
w = 1920,
h = 1080,
attempts = 5,
interval = 50,
) {
const keyword = text.toLowerCase(); // 将搜索关键字转换为小写,实现不区分大小写的搜索
for (let i = 0; i < attempts; i++) { // 循环尝试查找文本最多尝试attempts次
const gameRegion = captureGameRegion(); // 捕获游戏区域图像
try {
const ro = RecognitionObject.Ocr(x, y, w, h); // 创建OCR识别对象指定识别区域
const results = gameRegion.findMulti(ro); // 在区域内查找所有匹配的文本
// 遍历查找结果
for (let j = 0; j < results.count; j++) {
const res = results[j];
// 检查结果是否存在、包含文本内容,并且文本包含搜索关键字
if (
res.isExist() &&
res.text &&
res.text.toLowerCase().includes(keyword)
) {
return res.text; // 找到匹配文本,直接返回
}
}
} finally {
gameRegion.dispose(); // 确保释放游戏区域资源
}
await sleep(interval); // 等待指定的时间后进行下一次尝试
}
return ""; // 未找到匹配文本,返回空字符串
}
/**
* 通用找文本并点击OCR
* @param {string} text 目标文本(单个文本)
* @param {number} [x=0] OCR 区域左上角 X
* @param {number} [y=0] OCR 区域左上角 Y
* @param {number} [w=1920] OCR 区域宽度
* @param {number} [h=1080] OCR 区域高度
* @param {number} [attempts=5] OCR 尝试次数
* @param {number} [interval=50] 每次 OCR 之间的等待间隔(毫秒)
* @param {number} [preClickDelay=50] 点击前等待时间(毫秒)
* @param {number} [postClickDelay=50] 点击后等待时间(毫秒)
*
* @returns
* - RecognitionResult | null
*/
async function findTextAndClick(
text,
x = 0,
y = 0,
w = 1920,
h = 1080,
attempts = 5,
interval = 50,
preClickDelay = 50,
postClickDelay = 50
) {
const keyword = text.toLowerCase();
for (let i = 0; i < attempts; i++) {
const gameRegion = captureGameRegion();
try {
const ro = RecognitionObject.Ocr(x, y, w, h);
const results = gameRegion.findMulti(ro);
for (let j = 0; j < results.count; j++) {
const res = results[j];
if (
res.isExist() &&
res.text &&
res.text.toLowerCase().includes(keyword)
) {
await sleep(preClickDelay);
res.click();
await sleep(postClickDelay);
return res;
}
}
} finally {
gameRegion.dispose();
}
await sleep(interval);
}
return null;
}
/**
* 通用找图并点击支持图片文件路径、Mat
* @param {string|Mat} target 图片路径或已构造的 Mat
* @param {number} [x=0] 识别区域左上角 X
* @param {number} [y=0] 识别区域左上角 Y
* @param {number} [w=1920] 识别区域宽度
* @param {number} [h=1080] 识别区域高度
* @param {number} [timeout=1000] 识别时间上限(毫秒)
* @param {number} [interval=50] 每次识别之间的等待间隔(毫秒)
* @param {number} [preClickDelay=50] 点击前等待时间(毫秒)
* @param {number} [postClickDelay=50] 点击后等待时间(毫秒)
*
* @returns
* - RecognitionResult | null
*/
async function findImgAndClick(
target,
x = 0,
y = 0,
w = 1920,
h = 1080,
timeout = 1000,
interval = 50,
preClickDelay = 50,
postClickDelay = 50
) {
const ro =
typeof target === 'string'
? RecognitionObject.TemplateMatch(
file.readImageMatSync(target),
x, y, w, h
)
: RecognitionObject.TemplateMatch(
target,
x, y, w, h
);
const start = Date.now();
while (Date.now() - start <= timeout) {
const gameRegion = captureGameRegion();
try {
const res = gameRegion.find(ro);
if (!res.isEmpty()) {
await sleep(preClickDelay);
res.click();
await sleep(postClickDelay);
return res;
}
} finally {
gameRegion.dispose();
}
await sleep(interval);
}
return null;
}
/**
* 抛出错误函数
* 该函数用于显示错误通知并抛出错误对象
* @param {string} msg - 错误信息,将用于通知和错误对象
*/
function throwError(msg, isNotification = false) {
// 使用notification组件显示错误通知
// notification.error(`${msg}`);
if (isNotification) {
notification.error(`${msg}`);
}
// 抛出一个包含错误信息的Error对象
throw new Error(`${msg}`);
}
export {
ocrRegion,
getDayOfWeek,
getJsonPath,
isInMainUI,
toMainUi,
isInOutDomainUI,
outDomainUI,
isInOutStygianOnslaughtUI,
outStygianOnslaughtUI,
findTextAndClick,
findImgAndClick,
throwError,
}