diff --git a/repo/js/AutoPlanDomain/assets/200.png b/repo/js/AutoPlanDomain/assets/200.png new file mode 100644 index 000000000..5fdf7d70b Binary files /dev/null and b/repo/js/AutoPlanDomain/assets/200.png differ diff --git a/repo/js/AutoPlanDomain/assets/add_button.jpg b/repo/js/AutoPlanDomain/assets/add_button.jpg new file mode 100644 index 000000000..cf344bf81 Binary files /dev/null and b/repo/js/AutoPlanDomain/assets/add_button.jpg differ diff --git a/repo/js/AutoPlanDomain/assets/paimon_menu.png b/repo/js/AutoPlanDomain/assets/paimon_menu.png new file mode 100644 index 000000000..c424325b1 Binary files /dev/null and b/repo/js/AutoPlanDomain/assets/paimon_menu.png differ diff --git a/repo/js/AutoPlanDomain/assets/yue.png b/repo/js/AutoPlanDomain/assets/yue.png new file mode 100644 index 000000000..dfa75916a Binary files /dev/null and b/repo/js/AutoPlanDomain/assets/yue.png differ diff --git a/repo/js/AutoPlanDomain/config/config.js b/repo/js/AutoPlanDomain/config/config.js index f43705077..01af38466 100644 --- a/repo/js/AutoPlanDomain/config/config.js +++ b/repo/js/AutoPlanDomain/config/config.js @@ -1,4 +1,5 @@ import {ocrUid} from "../utils/uid"; +import {ocrPhysical} from "../utils/physical"; const config = { //setting设置放在这个json @@ -21,6 +22,10 @@ const config = { }, user: { uid: undefined, + physical: { + min: 20,//最小体力 + current: 0,//当前体力 + } }, // path: { @@ -162,6 +167,11 @@ async function initConfig() { throw new Error("密钥不匹配!") } } + //流程->返回主页 打开地图 返回主页 + const physical = await ocrPhysical(true, true) + config.user.physical.current = physical.current + config.user.physical.min = physical.min + // 初始化uid config.user.uid = await ocrUid() config.bgi_tools.api.httpPullJsonConfig = settings.bgi_tools_http_pull_json_config config.bgi_tools.api.httpPushAllJsonConfig = settings.bgi_tools_http_push_all_json_config @@ -226,7 +236,6 @@ async function initConfig() { } - export { config, LoadType, LoadMap, checkKey, diff --git a/repo/js/AutoPlanDomain/utils/physical.js b/repo/js/AutoPlanDomain/utils/physical.js new file mode 100644 index 000000000..018e685cf --- /dev/null +++ b/repo/js/AutoPlanDomain/utils/physical.js @@ -0,0 +1,156 @@ +import { getJsonPath } from "../utils/tool"; +//==================================================== +const genshinJson = { + width: 1920,//genshin.width, + height: 1080,//genshin.height, +} +// const MinPhysical = settings.minPhysical?parseInt(settings.minPhysical+''):parseInt(20+'') +// const OpenModeCountMin = settings.openModeCountMin +// let AlreadyRunsCount=0 +// let NeedRunsCount=0 +const TemplateOrcJson={x: 1568, y: 16, width: 225, height: 60,} +//==================================================== + + +/** + * 从字符串中提取数字并组合成一个整数 + * @param {string} str - 包含数字的字符串 + * @returns {number} - 由字符串中所有数字组合而成的整数 + */ +async function saveOnlyNumber(str) { + // 使用正则表达式匹配字符串中的所有数字 + // \d+ 匹配一个或多个数字 + // .join('') 将匹配到的数字数组连接成一个字符串 + // parseInt 将连接后的字符串转换为整数 + return parseInt(str.match(/\d+/g).join('')); +} + +/** + * 识别原粹树脂(体力)的函数 + * @param {boolean} [opToMainUi=false] - 是否操作到主界面 + * @param {boolean} [openMap=false] - 是否打开地图界面 + * @param {number} [minPhysical=20] - 最小可执行体力值 + * @param {boolean} [isResinExhaustionMode=ture] - 是否启用体力识别功能 + * @returns {Promise} 返回一个包含识别结果的Promise对象 + * - ok {boolean}: 是否可执行(体力是否足够) + * - min {number}: 最小可执行体力值 + * - remainder {number}: 当前剩余体力值 + */ +async function ocrPhysical(opToMainUi = false,openMap=false,minPhysical=20,isResinExhaustionMode=true) { + // 检查是否启用体力识别功能,如果未启用则直接返回默认结果 + if (!isResinExhaustionMode) { + log.info(`===未启用===`) + return { + ok: true, + min: 0, + current: 0, + } + } + log.debug(`===开始识别原粹树脂===`) + let ms = 1000 // 定义操作延迟时间(毫秒) + if (opToMainUi) { + await toMainUi(); // 切换到主界面 + } + + if (openMap){ + //打开地图界面 + await keyPress('M') + } + await sleep(ms) + log.debug(`===[点击+]===`) + //点击+ 按钮 x=1264,y=39,width=18,height=19 + let add_buttonJSON = getJsonPath('add_button'); + let add_objJson = { + path: `${add_buttonJSON.path}${add_buttonJSON.name}${add_buttonJSON.type}`, + x: 1242, + y: 21, + width: 54, + height: 51, + } + let templateMatchAddButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${add_objJson.path}`), add_objJson.x, add_objJson.y, add_objJson.width, add_objJson.height); + let regionA = captureGameRegion() + try { + let buttonA = regionA.find(templateMatchAddButtonRo); + + await sleep(ms) + if (!buttonA.isExist()) { + log.error(`${add_objJson.path}匹配异常`) + throwError(`${add_objJson.path}匹配异常`) + } + await buttonA.click() + }finally { + regionA.Dispose() + } + + await sleep(ms) + + log.debug(`===[定位原粹树脂]===`) + //定位月亮 + let jsonPath = getJsonPath('yue'); + let tmJson = { + path: `${jsonPath.path}${jsonPath.name}${jsonPath.type}`, + x: TemplateOrcJson.x, + y: TemplateOrcJson.y, + width: TemplateOrcJson.width, + height: TemplateOrcJson.height, + } + let templateMatchButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${tmJson.path}`), tmJson.x, tmJson.y, tmJson.width, tmJson.height); + let region =captureGameRegion() + let button = region.find(templateMatchButtonRo); + try { + await sleep(ms) + if (!button.isExist()) { + log.error(`${tmJson.path} 匹配异常`) + throwError(`${tmJson.path} 匹配异常`) + } + }finally { + region.Dispose() + } + + + log.debug(`===[识别原粹树脂]===`) + //识别体力 x=1625,y=31,width=79,height=30 / x=1689,y=35,width=15,height=26 + let ocr_obj = { + // x: 1623, + x: button.x + button.width, + // y: 32, + y: button.y, + // width: 61, + width: Math.abs(genshinJson.width - button.x - button.width), + height: 26 + } + + log.debug(`ocr_obj: x={x},y={y},width={width},height={height}`, ocr_obj.x, ocr_obj.y, ocr_obj.width, ocr_obj.height) + let region3 = captureGameRegion() + + try { + let recognitionObjectOcr = RecognitionObject.Ocr(ocr_obj.x, ocr_obj.y, ocr_obj.width, ocr_obj.height); + let res = region3.find(recognitionObjectOcr); + + log.debug(`[OCR原粹树脂]识别结果: ${res.text}, 原始坐标: x=${res.x}, y=${res.y},width:${res.width},height:${res.height}`); + let text=res.text.split('/')[0] + let current = await saveOnlyNumber(text) + let execute = (current - minPhysical) >= 0 + log.debug(`最小可执行原粹树脂:{min},原粹树脂:{key}`, minPhysical, current,) + + // await keyPress('VK_ESCAPE') + return { + ok: execute, + min: minPhysical, + current: current, + } + } catch (e) { + throwError(`识别失败,err:${e.message}`) + } finally { + region3.Dispose() + //返回地图操作 + if (opToMainUi) { + await toMainUi(); // 切换到主界面 + } + } + +} + +export { + ocrPhysical, +} \ No newline at end of file diff --git a/repo/js/AutoPlanDomain/utils/tool.js b/repo/js/AutoPlanDomain/utils/tool.js index be35ab548..7f3e40fcf 100644 --- a/repo/js/AutoPlanDomain/utils/tool.js +++ b/repo/js/AutoPlanDomain/utils/tool.js @@ -49,8 +49,91 @@ async function getDayOfWeek() { 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', + }], +]) +/** + * 根据键值获取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(); + let res = captureRegion.find(paimonMenuRo); + captureRegion.Dispose() + return !res.isEmpty(); +}; + +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 + } + +} +/** + * 抛出错误函数 + * 该函数用于显示错误通知并抛出错误对象 + * @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 + getDayOfWeek, + getJsonPath, + isInMainUI, + toMainUi, + throwError, } \ No newline at end of file