全自动地脉花4.4.8 (#2640)

* 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键退出机制
- 修复函数参数传递中的格式问题
- 优化代码格式和空行处理
- 增强异常情况下的原始模式回退逻辑
This commit is contained in:
云端客
2026-01-09 00:31:08 +08:00
committed by GitHub
parent 025cf2cf8c
commit 800b86ef40
4 changed files with 48 additions and 33 deletions

View File

@@ -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;
}
}

View File

@@ -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中的方法进行解决。",

View File

@@ -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}`);

View File

@@ -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(); // 切换到主界面