From 800b86ef40c8b3f5d334fa2ada6590b319a05a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E7=AB=AF=E5=AE=A2?= <107686912+Kirito520Asuna@users.noreply.github.com> Date: Fri, 9 Jan 2026 00:31:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E8=87=AA=E5=8A=A8=E5=9C=B0=E8=84=89?= =?UTF-8?q?=E8=8A=B14.4.8=20(#2640)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(physical): 修复原粹树脂识别逻辑 - 注释掉定位200的调试日志 - 移除按钮2存在性检查的代码块 - 调整OCR识别区域的坐标计算逻辑 - 修改OCR识别区域的宽度和高度参数 - 优化原粹树脂数值提取,只取分数前半部分 * refactor(physical): 优化图像识别和OCR处理的资源管理 - 将region.Dispose()操作移至try-finally块中确保资源正确释放 - 修改图像匹配异常提示信息为更简洁的格式 - 调整OCR识别代码中region3的创建位置并确保在finally块中释放资源 - 通过try-catch-finally结构增强代码的健壮性,防止内存泄漏 * refactor(physical): 调整模板匹配逻辑结构 - 将 try 语句块移至模板匹配操作之后 - 确保匹配结果在异常处理前已获取 - 优化代码执行流程和错误处理机制 * feat(AutoLeyLineOutcrop): 添加manifest.json读取和日志记录功能 - 添加读取manifest.json文件并记录脚本名称和版本信息 - 添加异常处理机制记录manifest.json读取错误 * chore(release): 更新版本号到 4.4.8 - 更新 manifest.json 中的版本号从 4.4.7 到 4.4.8 * fix(physical): 修复按钮宽度计算逻辑 - 将硬编码的屏幕宽度值1920替换为动态的genshinJson.width变量 - 确保按钮宽度计算适配不同分辨率的屏幕尺寸 * fix(resin): 修复树脂数量统计功能异常处理 - 添加OCR识别失败时的ESC键退出机制 - 修复函数参数传递中的格式问题 - 优化代码格式和空行处理 - 增强异常情况下的原始模式回退逻辑 --- repo/js/AutoLeyLineOutcrop/main.js | 10 +++- repo/js/AutoLeyLineOutcrop/manifest.json | 2 +- .../utils/calCountByResin.js | 19 ++++--- repo/js/AutoLeyLineOutcrop/utils/physical.js | 50 +++++++++++-------- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/repo/js/AutoLeyLineOutcrop/main.js b/repo/js/AutoLeyLineOutcrop/main.js index b82bedb75..f27512278 100644 --- a/repo/js/AutoLeyLineOutcrop/main.js +++ b/repo/js/AutoLeyLineOutcrop/main.js @@ -109,6 +109,12 @@ async function initialize() { } catch (error) { throw new Error(`JS文件缺失: ${error.message}`); } + try { + let manifest = JSON.parse(file.readTextSync("manifest.json")); + log.info(`脚本名称: {name},版本:{version}`, manifest.name, manifest.version); + } catch (e) { + log.warn(`error:{e}`, e.message); + } // 2. 加载配置文件 try { config = JSON.parse(file.readTextSync("config.json")); @@ -237,8 +243,8 @@ async function recheckResinAndContinue() { recheckCount++; if (physical.OpenModeCountMin) { physical.AlreadyRunsCount++; - if (physical.NeedRunsCount<=physical.AlreadyRunsCount){ - log.info(`[已开启取小值]树脂耗尽模式:任务已完成,已经运行{count}次`,physical.AlreadyRunsCount); + if (physical.NeedRunsCount <= physical.AlreadyRunsCount) { + log.info(`[已开启取小值]树脂耗尽模式:任务已完成,已经运行{count}次`, physical.AlreadyRunsCount); return; } } diff --git a/repo/js/AutoLeyLineOutcrop/manifest.json b/repo/js/AutoLeyLineOutcrop/manifest.json index 276de2756..dd7692756 100644 --- a/repo/js/AutoLeyLineOutcrop/manifest.json +++ b/repo/js/AutoLeyLineOutcrop/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "全自动地脉花", - "version": "4.4.7", + "version": "4.4.8", "tags": ["地脉花"], "bgi_version": "0.52.0", "description": "基于OCR图像识别的全自动刷取地脉花。\n💡更多信息请查看README! \n\n----------注意事项----------\n●仅支持BetterGI 0.52.0 及以上版本!\n●部分地脉花因特殊原因不支持全自动,具体的点位请在手册中查看。\n●树脂使用的优先级:2倍原粹树脂 > 浓缩树脂 > 原粹树脂。\n●运行时会传送到七天神像设置中设置的七天神像,需要关闭七天神像设置中的“是否就近七天神像恢复血量”,并指定七天神像。\n●战斗策略注意调度器设置中地图追踪行走配置里的“允许在JsSpript中使用”和“覆盖JS中的自动战斗配置”,只有在都打开的情况下脚本才会使用下面的战斗配置,否则会使用独立任务中的战斗策略。战斗超时时间不能大于脚本自定义配置中的时间。\n\n如果遇到问题,请先参照README中的方法进行解决。", diff --git a/repo/js/AutoLeyLineOutcrop/utils/calCountByResin.js b/repo/js/AutoLeyLineOutcrop/utils/calCountByResin.js index 33d2a2d96..809a54427 100644 --- a/repo/js/AutoLeyLineOutcrop/utils/calCountByResin.js +++ b/repo/js/AutoLeyLineOutcrop/utils/calCountByResin.js @@ -205,17 +205,20 @@ async function recognizeNumberByOCR(ocrRegion, pattern) { * 统计原粹树脂数量 * @returns {number} 原粹树脂数量 */ -async function countOriginalResin(tryOriginalMode,opToMainUi,openMap) { +async function countOriginalResin(tryOriginalMode, opToMainUi, openMap) { if (tryOriginalMode) { log.info("尝试使用原始模式"); return await countOriginalResinBackup() } else { log.info('尝试使用优化模式'); - let ocrPhysical = await physical.ocrPhysical(opToMainUi,openMap); + let ocrPhysical = await physical.ocrPhysical(opToMainUi, openMap); await sleep(600) + // ocrPhysical = false//模拟异常 if (ocrPhysical && ocrPhysical.ok) { return ocrPhysical.remainder; } else { + //异常 退出至地图 尝试使用原始模式 + await keyPress("VK_ESCAPE") log.error(`ocrPhysical error`); throw new Error("ocrPhysical error"); } @@ -468,7 +471,7 @@ this.countAllResin = async function () { let tryPass = true; try { log.info("[开始]统计补充树脂界面中的树脂"); - resinCounts.original = await countOriginalResin(false,false); + resinCounts.original = await countOriginalResin(false, false); moveMouseTo(CONFIG.COORDINATES.AVOID_SELECTION.x, CONFIG.COORDINATES.AVOID_SELECTION.y) await sleep(500); resinCounts.transient = await countTransientResin(); @@ -481,7 +484,7 @@ this.countAllResin = async function () { } await sleep(CONFIG.UI_DELAY); log.info("开始统计地图界面中的树脂"); - if (!tryPass){ + if (!tryPass) { // 如果第一次尝试失败,则切换到蒙德 await switchtoCountrySelection(CONFIG.COORDINATES.MONDSTADT.x, CONFIG.COORDINATES.MONDSTADT.y) resinCounts.original = await countOriginalResin(!tryPass); @@ -539,23 +542,23 @@ this.calCountByResin = async function () { // 1. 原粹树脂:优先消耗40/次,不满40消耗20/次,不满20不消耗 let originalResinTimes = 0; let remainingOriginalResin = countResult.originalResinCount; - + // 先计算40树脂的次数 if (remainingOriginalResin >= 40) { const times40 = Math.floor(remainingOriginalResin / 40); originalResinTimes += times40; remainingOriginalResin = remainingOriginalResin - (times40 * 40); } - + // 再计算20树脂的次数 if (remainingOriginalResin >= 20) { const times20 = Math.floor(remainingOriginalResin / 20); originalResinTimes += times20; remainingOriginalResin = remainingOriginalResin - (times20 * 20); } - + log.info(`原粹树脂可刷取次数: ${originalResinTimes}`); - + // 2. 浓缩树脂:每个计算为1次 let condensedResinTimes = countResult.condensedResinCount; log.info(`浓缩树脂可刷取次数: ${condensedResinTimes}`); diff --git a/repo/js/AutoLeyLineOutcrop/utils/physical.js b/repo/js/AutoLeyLineOutcrop/utils/physical.js index 45abf8ffd..bd321557e 100644 --- a/repo/js/AutoLeyLineOutcrop/utils/physical.js +++ b/repo/js/AutoLeyLineOutcrop/utils/physical.js @@ -96,16 +96,19 @@ async function ocrPhysical(opToMainUi = false,openMap=false) { } let templateMatchAddButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${add_objJson.path}`), add_objJson.x, add_objJson.y, add_objJson.width, add_objJson.height); let regionA = captureGameRegion() - // let buttonA = captureGameRegion().find(templateMatchAddButtonRo); - let buttonA = regionA.find(templateMatchAddButtonRo); - regionA.Dispose() + try { + let buttonA = regionA.find(templateMatchAddButtonRo); - await sleep(ms) - if (!buttonA.isExist()) { - log.error(`未找到${add_objJson.path}请检查路径是否正确`) - throwError(`未找到${add_objJson.path}请检查路径是否正确`) + await sleep(ms) + if (!buttonA.isExist()) { + log.error(`${add_objJson.path}匹配异常`) + throwError(`${add_objJson.path}匹配异常`) + } + await buttonA.click() + }finally { + regionA.Dispose() } - await buttonA.click() + // let add_obj = { // x: 1264, // y: 39, @@ -125,16 +128,18 @@ async function ocrPhysical(opToMainUi = false,openMap=false) { } let templateMatchButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${tmJson.path}`), tmJson.x, tmJson.y, tmJson.width, tmJson.height); let region =captureGameRegion() - // let button = captureGameRegion().find(templateMatchButtonRo); let button = region.find(templateMatchButtonRo); - region.Dispose() - await sleep(ms) - if (!button.isExist()) { - log.error(`${tmJson.path} 匹配异常`) - throwError(`${tmJson.path} 匹配异常`) + try { + await sleep(ms) + if (!button.isExist()) { + log.error(`${tmJson.path} 匹配异常`) + throwError(`${tmJson.path} 匹配异常`) + } + }finally { + region.Dispose() } - log.debug(`===[定位/200]===`) +/* log.debug(`===[定位/200]===`) //定位200 let jsonPath2 = getJsonPath('200'); let tmJson2 = { @@ -153,30 +158,30 @@ async function ocrPhysical(opToMainUi = false,openMap=false) { if (!button2.isExist()) { log.error(`${tmJson2.path} 匹配异常`) throwError(`${tmJson2.path} 匹配异常`) - } + }*/ 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-20, + x: button.x + button.width, // y: 32, y: button.y, // width: 61, - width: Math.abs(button2.x - button.x - button.width+20), - height: button2.height + 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 region3 = captureGameRegion() let res = region3.find(recognitionObjectOcr); - region3.Dispose() log.info(`[OCR原粹树脂]识别结果: ${res.text}, 原始坐标: x=${res.x}, y=${res.y},width:${res.width},height:${res.height}`); - let remainder = await saveOnlyNumber(res.text) + let text=res.text.split('/')[0] + let remainder = await saveOnlyNumber(text) let execute = (remainder - minPhysical) >= 0 log.info(`最小可执行原粹树脂:{min},原粹树脂:{key}`, minPhysical, remainder,) @@ -189,6 +194,7 @@ async function ocrPhysical(opToMainUi = false,openMap=false) { } catch (e) { throwError(`识别失败,err:${e.message}`) } finally { + region3.Dispose() //返回地图操作 if (opToMainUi) { await toMainUi(); // 切换到主界面