更新识别模式 (#2693)

This commit is contained in:
skyflag2022
2026-01-16 20:36:30 +08:00
committed by GitHub
parent 9ad8adc667
commit 8544338512
6 changed files with 378 additions and 200 deletions

View File

@@ -1,127 +1,120 @@
# 药品消耗统计脚本使用指南
### 药品消耗统计脚本使用指南(更新版)
## 📋 一、脚本概述
本脚本是一款专为《原神》设计的自动化工具,主要功能如下:
- **自动识别**通过OCR技术读取背包中指定药品的数量
- **智能统计**:记录每日药品消耗/新增变化统计周期为当日4点至次日4点
- **数据管理**自动保存30天历史记录过期数据自动清理
- **智能提醒**:通过系统通知推送药品变化信息
本脚本是专为《原神》设计的自动化药品消耗统计工具,核心能力升级如下:
- **多模式识别**:支持「营养袋模式」「筛选模式」双模式适配不同场景的药品识别
- **精准OCR读取**:自动识别背包中指定回血/复活药品数量,适配不同界面布局
- **灵活时间配置**支持自定义每日统计刷新时间默认4:00可设0-24小时及一位小数
- **智能数据管理**自动保留30天历史记录按自定义时间周期统计药品消耗/新增
- **多账户隔离**不同账户数据独立存储支持合规账户名校验1-20位中英文/数字)
- **异常友好处理**:识别失败自动兜底、参数错误智能修正,拒绝进入世界的申请
## 🛠️ 二、环境与工具要求
### 必备工具茶包版BGI
**为什么不推荐公版BGI**
公版BGI执行JS脚本时默认关闭自动吃药功能且无法通过脚本代码开启。本脚本的设计逻辑完全依赖自动吃药功能的正常运行
- 药品消耗主要发生在自动吃药场景中
- 脚本未内置开启自动吃药的适配代码
公版BGI默认关闭自动吃药功能且无法通过脚本开启本脚本依赖该功能实现消耗统计因此**必须使用茶包版BGI**。
### 系统配置要求
1. **游戏分辨率**1920×1080固定不可改
2. **游戏内设置**
- 装备「便携营养袋」
- 确保游戏界面无遮挡、无缩放
3. **模板文件**:确认`assets/RecognitionObject/`文件夹包含所有必要的模板图片
1. **游戏分辨率**固定1920×1080不可修改影响OCR识别区域定位
2. **游戏和js设置**
- 需装备「便携营养袋」
- 启用「筛选模式」需要填写完整的药名
## 📥 三、获取茶包版BGI
1. 优先方式:在脚本仓库搜索关键词「茶包」,进入作者主页下载
2. 备用方式查阅「锄地一条龙js」的README文档通过文档末尾群号加入测测莫酱交流群获取
1. **直接获取**:在脚本仓库搜索关键词「茶包」,进入作者主页下载
2. **备用方案**查阅「锄地一条龙js」的README文档通过文档末尾的群号加入测测莫酱交流群获取
## ⚙️ 四、全参数配置说明(新增/细化)
| 参数项 | 类型 | 填写要求 | 默认值 | 核心说明 |
|--------|------|----------|--------|----------|
| **runMode** | 下拉选择 | 二选一:「营养袋模式」/「筛选模式」 | 营养袋模式 | 营养袋模式:读取便携营养袋内药品;筛选模式:通过背包筛选搜索药品 |
| **initSelect** | 复选框 | 仅初始化/重置时临时勾选 | false | 勾选后运行脚本会删除当日同名记录,重新初始化数据(使用后务必取消) |
| **recoveryFoodName** | 文本输入 | 与游戏内回血药名称完全一致 | 空 | 例:「美味的甜甜花酿鸡」,名称错误会导致识别失败 |
| **resurrectionFoodName** | 文本输入 | 与游戏内复活药名称完全一致 | 空 | 例:「美味的提瓦特煎蛋」,支持全量游戏内可食用复活类物品 |
| **userName** | 文本输入 | 1-20字符仅支持中英文、数字 | 默认账户 | 多账户区分核心,违规名称自动替换为默认账户 |
| **refreshTime** | 文本输入 | 0-24之间支持一位小数 | 4.0 | 自定义每日统计周期分界点如4.5=4:30错误值自动修正为4.0 |
| **loadDelay** | 文本输入 | 非负整数(单位:毫秒) | 800 | 界面打开/切换的等待延迟,低配置设备可适当增大 |
| **stepDelay** | 文本输入 | 非负整数(单位:毫秒) | 500 | OCR识别/输入药名前的短暂等待,保证识别稳定性 |
## ⚙️ 四、使用前配置
### 1. 基础检查
- [ ] 游戏分辨率为1920×1080
- [ ] 已装备「便携营养袋」
- [ ] 茶包版BGI中已开启「自动吃药」功能
### 2. 参数设置(关键步骤)
| 参数项 | 填写要求 | 示例 |
|--------|----------|------------|
| **userName** | 1-20字符仅支持中英文、数字 | "旅行者001" |
| **recoveryFoodName** | 与游戏内名称完全一致 | "美味的甜甜花酿鸡" |
| **resurrectionFoodName** | 与游戏内名称完全一致 | "美味的提瓦特煎蛋" |
| **initSelect** | 默认关闭,仅初始化时临时开启 | 取消勾选 |
**重要**:药品名称必须完全匹配。
## 🔄 五、操作流程
### 配置优先级
脚本运行时参数读取规则:`自定义配置 > 默认值`,参数错误时自动兜底为默认值并输出警告日志。
## 🔄 五、操作流程(适配双模式)
### 场景一:首次使用 / 新账户
1. 启用筛选模式需要完成参数配置(填写药品名称),启用营养袋模式则需要营养袋装备两种药品
2. 确认游戏分辨率1920×1080、BGI自动吃药功能开启便携营养袋已装备
3. 运行脚本,自动执行:
- 校验账户名合法性 → 打开背包 → 按选定模式识别药品数量
-`assets/`目录生成「账户名.txt」记录文件
4. 收到「今日初始化完成」通知,首次配置完成
1. 完成上述配置后运行脚本
2. 脚本自动执行:
- 校验账户名合法性
- 打开背包识别药品数量
- 创建记录文件(路径:`assets/账户名.txt`
3. 收到「今日初始化完成」通知
### 场景二:日常使用(分模式)
#### 营养袋模式
- 脚本自动打开背包→进入小道具→读取便携营养袋内回血/复活药数量
- 无需手动筛选,识别速度更快,依赖便携营养袋装备状态
### 场景二:日常使用
#### 筛选模式
- 脚本自动打开背包→进入食物分类→筛选搜索指定药品→读取数量
- 无需装备营养袋,适配未配置营养袋的场景,识别流程稍长
- **每日首次运行**4点后记录为当日初始值
- **后续运行**:对比最新数量,计算消耗/新增
- **自动记录**:每次运行都会保存一次记录数据
- **智能清理**仅保留30天内数据
#### 通用规则
- 每日首次运行自定义refreshTime后记录为当日初始值
- 后续运行:对比初始值计算消耗/新增(正数=消耗,负数=新增)
- 每次运行自动保存记录,仅保留30天内数据,过期自动清理
### 场景三:更换药品重置数据
### 场景三:更换药品/重置统计数据
1. 在设置中勾选`initSelect`选项
2. 确认药品名称已更新为新名称(如需更换)
3. 运行脚本一次,收到「强制初始化完成」通知
4. **立即取消`initSelect`勾选**(避免后续运行重复初始化)
1. 在设置中**勾选`initSelect`选项**
2. 运行脚本一次
3. **务必取消勾选`initSelect`**
**效果**:删除当日同名药品记录,以当前数量重新初始化。
## 📊 六、核心机制说明
### 统计周期规则
- 以**凌晨4点**为分界点
- 举例当前时间3点统计昨天4点至今的数据
- 当前时间5点统计今天4点起的数据
### 记录格式示例
## 📊 六、核心机制(新增/补充)
### 1. 自定义统计周期计算规则
`refreshTime`为分界点,脚本自动判定统计范围:
- 当前时间 < 当日refreshTime统计「昨日refreshTime → 今日refreshTime」数据
- 当前时间 ≥ 当日refreshTime统计「今日refreshTime → 明日refreshTime」数据
示例refreshTime=4.54:30当前时间3:00 → 统计昨天4:30至今当前时间5:00 → 统计今天4:30起。
### 2. 记录文件格式
```
时间:2023/10/15 14:30:45-美味的甜甜花酿鸡-18
时间:2023/10/15 14:30:45-美味的提瓦特煎蛋-6
时间:202X/XX/XX XX:XX:XX-【药品名称】-【数量】
时间:202X/XX/XX XX:XX:XX-【药品名称】-【数量】
```
每条记录包含时间戳+药品名+数量,双药品记录成对生成,保证数据完整性。
### 异常处理机制
### 3. OCR识别异常处理
| 异常场景 | 处理逻辑 | 通知/日志 |
|----------|----------|-----------|
| OCR未识别到文本 | 数量设为0 | 推送「未识别到XX药数量设置为0」通知 |
| 药品名称为空 | 识别结果无效 | log.warn「XX药名字没填」 |
| refreshTime非法 | 自动修正为4.0 | log.warn「刷新时间设置错误使用默认值4.0」 |
| 账户名违规 | 替换为默认账户 | log.error「账户名XX违规使用默认账户」 |
| 异常情况 | 自动处理方式 |
|----------|-------------|
| 药品未识别 | 数量设为0发送通知提醒 |
| 记录文件格式错误 | 自动重置文件 |
## ⚠️ 七、重要注意事项(强化)
### 1. 运行时机建议
- 每日首次运行:在锄地/刷本前、药品制作后执行,保证初始值准确
- 避免在两次脚本运行之间大批量制作/使用药品,防止统计偏差
- 低配置设备适当增大loadDelay/stepDelay提升识别成功率
## ⚠️ 七、重要注意事项
### 2. 双模式适配要点
| 模式 | 优势 | 注意事项 |
|------|------|----------|
| 营养袋模式 | 识别快、步骤少 | 必须装备便携营养袋,仅识别营养袋内药品 |
| 筛选模式 | 无需装备营养袋 | 药品名称必须精准,依赖背包筛选功能正常 |
### 每日首次使用时机建议
### 3. 常见误区修正
❌ 错误:`initSelect`长期勾选 → 每次运行都重置数据,无法统计消耗
✅ 正确:仅重置/换药品时勾选,运行后立即取消
- **在锄地一条龙前**
- **在药品制作后**
- **避免**在两次脚本运行之间制作大量药品
❌ 错误随意修改refreshTime后未重启脚本 → 统计周期混乱
✅ 正确修改refreshTime后重新运行脚本生效新的统计分界点
### 常见误区
1. **`initSelect`常开**:导致每次运行都重新初始化
2. **名称不准确**:最常导致识别失败的原因
3. **窗口遮挡**影响OCR识别准确率
4. **多账户混淆**:每个账户有独立记录文件
## 🔧 八、故障排查指南
### 快速自查表
| 问题现象 | 优先检查项 |
|----------|------------|
| 药品数量识别为0 | 1. 药品名称准确性<br>2. 背包中是否有该药品<br>3. 分辨率是否为1920×1080 |
| 统计数据异常 | 1. 是否在脚本运行期间操作药品<br>2. 是否每日4点后首次运行<br>3. `initSelect`是否误开启 |
| 自动吃药无效 | 1. 是否使用茶包版BGI<br>2. BGI中自动吃药功能是否开启 |
❌ 错误分辨率改为非1920×1080 → OCR识别区域错位
✅ 正确固定游戏分辨率为1920×1080不可自定义
## 🔧 八、故障排查指南(新增模式/参数排查)
| 问题现象 | 优先检查项 | 解决方案 |
|----------|------------|----------|
| 药品数量识别为0 | 1. 运行模式是否匹配场景<br>2. 药品名称是否完全一致<br>| 1. 营养袋模式需装备营养袋;筛选模式检查背包食物分类<br>2. 复制游戏内药品全名(含「美味的/冷的」等前缀)<br>|
| 统计周期错误 | 1. refreshTime是否合法<br>2. 系统时间是否准确 | 1. 确认值在0-24之间如4.0/12.5),错误值会自动修正<br>2. 同步系统时间到网络标准时间 |
| 脚本运行卡顿/超时 | 1. loadDelay/stepDelay是否过小<br>2. 设备性能是否不足 | 1. 逐步增大延迟值如loadDelay改为1000<br>2. 关闭后台无关程序,保证游戏前台运行 |
| 多账户数据混淆 | 1. userName是否唯一<br>2. 记录文件是否存在重名 | 1. 为每个账户设置唯一名称如「旅行者001/旅行者002」<br>2. 检查assets目录删除重名的错误记录文件 |
| 模式切换后识别失败 | 1. 对应模式的模板图片是否存在<br>2. 点击坐标是否匹配分辨率 | 1. 确认assets目录有「营养袋.png」「筛选1.png」「筛选2.png」等<br>2. 重新确认游戏分辨率为1920×1080 |

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,14 +1,36 @@
let userName = settings.userName || "默认账户";
const recoveryFoodName = settings.recoveryFoodName || "回血药名字没填";
const resurrectionFoodName = settings.resurrectionFoodName || "复活药名字没填";
const mode = settings.runMode || "营养袋模式"
let recoveryFoodName = settings.recoveryFoodName || "回血药名字没填";
let resurrectionFoodName = settings.resurrectionFoodName || "复活药名字没填";
const ocrRegion = {
x: 110,
x: 1422,
y: 586,
width: 300,
height: 40
};
const ocrRegion1 = {
x: 1420,
y: 687,
width: 300,
height: 40
};
const ocrRegion2 = {
x: 105,
y: 242,
width: 124,
height: 32
width: 140,
height: 40
};
const loadDelay = +settings.loadDelay || 800;
const stepDelay = +settings.stepDelay || 500;
let refreshTime = parseFloat(settings.refreshTime) || 4.0;
if (isNaN(refreshTime) || refreshTime < 0 || refreshTime >= 24) {
refreshTime = 4.0;
log.warn(`刷新时间设置错误使用默认值4.0`);
}
// 计算刷新时间的小时和分钟
const refreshHour = Math.floor(refreshTime);
const refreshMinute = Math.floor((refreshTime - refreshHour) * 60);
log.info(`刷新时间为: ${refreshHour}:${String(refreshMinute).padStart(2, '0')}`);
(async function () {
// 检验账户名
async function getUserName() {
@@ -21,6 +43,23 @@ const stepDelay = +settings.stepDelay || 500;
return userName;
}
async function close_join_world_popup_window() {
const game_region = captureGameRegion();
const text_x = 762;
const text_y = 29;
const text_w = 210;
const text_h = 40;
const ocr_res = game_region.find(RecognitionObject.ocr(text_x, text_y, text_w, text_h));
if (ocr_res) {
if (ocr_res.text.includes("进入世界申请")) {
log.info("检测到有人申请进入世界,拒绝申请");
click(1051, 51);//选择珍贵物品
await clickPNG('拒绝', 10);
}
}
game_region.dispose();
}
async function close_expired_stuff_popup_window() {
const game_region = captureGameRegion();
const text_x = 850;
@@ -62,26 +101,24 @@ const stepDelay = +settings.stepDelay || 500;
if (lines.length === 0) return result;
// 获取当前时间范围(当天4点至次日4点
// 获取当前时间范围(根据自定义刷新时间
const now = new Date();
let startTime, endTime;
if (now.getHours() < 4) {
// 当前时间在4点前时间范围为昨天4点至今天4点
startTime = new Date(now);
startTime.setDate(now.getDate() - 1);
startTime.setHours(4, 0, 0, 0);
// 创建今天的刷新时间点
const todayRefresh = new Date(now);
todayRefresh.setHours(refreshHour, refreshMinute, 0, 0);
endTime = new Date(now);
endTime.setHours(4, 0, 0, 0);
if (now < todayRefresh) {
// 当前时间在刷新时间前,时间范围为昨天刷新时间至今天刷新时间
startTime = new Date(todayRefresh);
startTime.setDate(startTime.getDate() - 1);
endTime = new Date(todayRefresh);
} else {
// 当前时间在4点后,时间范围为今天4点至明天4点
startTime = new Date(now);
startTime.setHours(4, 0, 0, 0);
endTime = new Date(now);
endTime.setDate(now.getDate() + 1);
endTime.setHours(4, 0, 0, 0);
// 当前时间在刷新时间后,时间范围为今天刷新时间至明天刷新时间
startTime = new Date(todayRefresh);
endTime = new Date(todayRefresh);
endTime.setDate(endTime.getDate() + 1);
}
// 时间格式正则:匹配 "时间:YYYY/MM/DD HH:mm:ss"
@@ -195,22 +232,23 @@ const stepDelay = +settings.stepDelay || 500;
// 如果需要删除当天同名记录
if (deleteSameDayRecords) {
// 获取当前时间范围(当天4点至次日4点
// 获取当前时间范围(根据自定义刷新时间
let startTime, endTime;
if (now.getHours() < 4) {
// 当前时间在4点前时间范围为昨天4点至今天4
startTime = new Date(now);
startTime.setDate(now.getDate() - 1);
startTime.setHours(4, 0, 0, 0);
endTime = new Date(now);
endTime.setHours(4, 0, 0, 0);
// 创建今天的刷新时间
const todayRefresh = new Date(now);
todayRefresh.setHours(refreshHour, refreshMinute, 0, 0);
if (now < todayRefresh) {
// 当前时间在刷新时间前,时间范围为昨天刷新时间至今天刷新时间
startTime = new Date(todayRefresh);
startTime.setDate(startTime.getDate() - 1);
endTime = new Date(todayRefresh);
} else {
// 当前时间在4点后,时间范围为今天4点至明天4点
startTime = new Date(now);
startTime.setHours(4, 0, 0, 0);
endTime = new Date(now);
endTime.setDate(now.getDate() + 1);
endTime.setHours(4, 0, 0, 0);
// 当前时间在刷新时间后,时间范围为今天刷新时间至明天刷新时间
startTime = new Date(todayRefresh);
endTime = new Date(todayRefresh);
endTime.setDate(endTime.getDate() + 1);
}
// 创建药品匹配正则
@@ -275,7 +313,6 @@ const stepDelay = +settings.stepDelay || 500;
if (!res || !res.text) {
continue;
}
const numberMatch = res.text.match(pattern);
if (numberMatch) {
const number = parseInt(numberMatch[1] || numberMatch[0]);
@@ -296,6 +333,55 @@ const stepDelay = +settings.stepDelay || 500;
return null;
}
async function recognizeFoodItemByOCR(ocrRegion, pattern) {
let captureRegion = null;
try {
const ocrRo = RecognitionObject.ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height);
captureRegion = captureGameRegion();
const resList = captureRegion.findMulti(ocrRo);
if (!resList || resList.length === 0) {
log.warn("OCR未识别到任何文本");
return { name: null, count: null };
}
for (const res of resList) {
if (!res || !res.text) {
continue;
}
const match = res.text.match(pattern);
if (match) {
let name = null;
let count = null;
if (match[1]) {
name = match[1].trim();
}
if (match[2]) {
count = parseInt(match[2]);
if (isNaN(count)) {
count = null;
}
}
if (name || count) {
return { name, count };
}
}
}
}
catch (error) {
log.error(`OCR识别时发生异常: ${error.message}`);
}
finally {
if (captureRegion) {
captureRegion.dispose();
}
}
return { name: null, count: null };
}
async function findAndClick(target, doClick = true, maxAttempts = 60) {
for (let i = 0; i < maxAttempts; i++) {
const rg = captureGameRegion();
@@ -308,72 +394,155 @@ const stepDelay = +settings.stepDelay || 500;
return false;
}
async function clickPNG(png, maxAttempts = 20) {
async function clickPNG(png, maxAttempts = 20, doClick=true) {
// log.info(`调试-点击目标${png},重试次数${maxAttempts}`);
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/${png}.png`));
pngRo.Threshold = 0.95;
pngRo.InitTemplate();
return await findAndClick(pngRo, true, maxAttempts);
return await findAndClick(pngRo, doClick, maxAttempts);
}
async function main() {
// 设置分辨率和缩放
setGameMetrics(1920, 1080, 1);
await genshin.returnMainUi();
keyPress("B");//打开背包
await sleep(1000);
await close_expired_stuff_popup_window()
await sleep(loadDelay);
click(863, 51);//选择食物
await sleep(loadDelay);
await clickPNG('筛选1', 1);
await clickPNG('筛选2', 1);
await clickPNG('重置');
await sleep(stepDelay);
await clickPNG('搜索');
await sleep(loadDelay);
log.info(`搜索${recoveryFoodName}`)
inputText(recoveryFoodName);
await clickPNG('确认筛选');
await sleep(stepDelay);
let recoveryNumber=await recognizeNumberByOCR(ocrRegion,/\d+/) //识别回血药数量
// 处理回血药识别结果
if (recoveryNumber === null) {
recoveryNumber = 0;
notification.send(`未识别到回血药数量(数量小于10识别不到)设置数量为0药品名${recoveryFoodName}`)
await sleep(5000);
click(863, 51);//选择食物
let recoveryNumber = 0;
let resurrectionNumber = 0;
// 设置分辨率和缩放
setGameMetrics(1920, 1080, 1);
await genshin.returnMainUi();
keyPress("B");//打开背包
await sleep(1000);
// 关闭弹窗
await close_expired_stuff_popup_window();
await close_join_world_popup_window();
await sleep(loadDelay);
// 打开界面
let maxRetries = 5; // 最大重试次数
let retryCount = 0;
let successClick = false;
// 根据模式选择点击的位置
let clickX, clickY;
if (mode === "营养袋模式") {
clickX = 1051; // 选择小道具
clickY = 51;
} else if (mode === "筛选模式") {
clickX = 863; // 选择食物
clickY = 51;
}
while (retryCount < maxRetries && !successClick) {
retryCount++;
await close_join_world_popup_window();
click(clickX, clickY);
await sleep(loadDelay);
// 检查是否进入了申请界面(通过查找"拒绝"按钮)
if (await clickPNG('拒绝', 3)) { // 找到拒绝按钮,说明在申请界面
log.info("检测到进入世界申请,已拒绝,重新尝试点击分类标签");
await sleep(stepDelay);
continue; // 继续下一次循环
}
if (mode === "营养袋模式") {
if (await clickPNG('营养袋', 1, false)) { // 只检查不点击
successClick = true;
log.info("成功进入小道具界面");
break;
}
} else if (mode === "筛选模式") {
if (await clickPNG('筛选1', 1, false)||await clickPNG('筛选2', 1, false)) { // 只检查不点击
successClick = true;
log.info("成功进入食物界面");
break;
}
}
log.warn(`尝试点击分类标签失败,第${retryCount}次重试`);
await sleep(stepDelay);
}
if (!successClick) {
log.error("多次尝试点击分类标签失败,脚本终止");
return { recoveryNumber, resurrectionNumber};
}
if (mode === "营养袋模式") {
// 营养袋模式
await clickPNG('营养袋', 1);
await sleep(loadDelay);
const pattern = /(.+?)\s*[\(](\d+)[份\s]*[\)]/;
// 识别回血药
let result = await recognizeFoodItemByOCR(ocrRegion, pattern);
if (result.name && result.count !== null) {
log.info(`识别到: ${result.name}, 份数: ${result.count}`);
} else {
log.warn("未识别到有效的回血药信息");
}
recoveryNumber = result.count; // 识别回血药数量
recoveryFoodName = result.name || '未识别到回血药名称'; // 如果识别失败使用settings中的名字
// 处理回血药识别结果
if (recoveryNumber === null) {
recoveryNumber = 0;
notification.send(`未识别到回血药数量设置数量为0药品名${recoveryFoodName}`);
}
// 识别复活药
result = await recognizeFoodItemByOCR(ocrRegion1, pattern);
if (result.name && result.count !== null) {
log.info(`识别到: ${result.name}, 份数: ${result.count}`);
} else {
log.warn("未识别到有效的复活药信息");
}
resurrectionNumber = result.count; // 识别复活药数量
resurrectionFoodName = result.name || '未识别到复活药名称'; // 如果识别失败使用settings中的名字
// 处理复活药识别结果
if (resurrectionNumber === null) {
resurrectionNumber = 0;
notification.send(`未识别到复活药数量设置数量为0药品名${resurrectionFoodName}`);
}
} else if (mode === "筛选模式") {
// 食物筛选模式
// 先识别回血药
await clickPNG('筛选1', 1);
await clickPNG('筛选2', 1);
await clickPNG('重置');
await sleep(stepDelay);
await clickPNG('搜索');
await sleep(loadDelay);
log.info(`搜索${recoveryFoodName}`);
inputText(recoveryFoodName);
await clickPNG('确认筛选');
await sleep(loadDelay);
recoveryNumber = await recognizeNumberByOCR(ocrRegion2, /\d+/); // 识别回血药数量
// 处理回血药识别结果
if (recoveryNumber === null) {
recoveryNumber = 0;
notification.send(`未识别到回血药数量设置数量为0药品名${recoveryFoodName}`);
await sleep(5000);
click(863, 51); // 选择食物
await sleep(1000);
}
// 重置筛选,识别复活药
await clickPNG('筛选1', 1);
await clickPNG('筛选2', 1);
await clickPNG('重置');
await sleep(stepDelay);
await clickPNG('搜索');
await sleep(loadDelay);
log.info(`搜索${resurrectionFoodName}`);
inputText(resurrectionFoodName);
await clickPNG('确认筛选');
await sleep(loadDelay);
resurrectionNumber = await recognizeNumberByOCR(ocrRegion2, /\d+/); // 识别复活药数量
// 处理复活药识别结果
if (resurrectionNumber === null) {
resurrectionNumber = 0;
notification.send(`未识别到复活药数量设置数量为0药品名${resurrectionFoodName}`);
await sleep(5000);
click(863, 51); // 选择食物
await sleep(1000);
}
// 重置筛选
await clickPNG('筛选1', 1);
await clickPNG('筛选2', 1);
await clickPNG('重置');
await sleep(stepDelay);
await clickPNG('确认筛选');
}
await genshin.returnMainUi();
return { recoveryNumber, resurrectionNumber };
}
await sleep(loadDelay);
await clickPNG('筛选1', 1);
await clickPNG('筛选2', 1);
await clickPNG('重置');
await sleep(stepDelay);
await clickPNG('搜索');
await sleep(loadDelay);
log.info(`搜索${resurrectionFoodName}`)
inputText(resurrectionFoodName);
await clickPNG('确认筛选');
await sleep(stepDelay);
let resurrectionNumber=await recognizeNumberByOCR(ocrRegion,/\d+/) //识别复活药数量
// 处理复活药识别结果
if (resurrectionNumber === null) {
resurrectionNumber = 0;
notification.send(`未识别到复活药数量(数量小于10识别不到)设置数量为0药品名${resurrectionFoodName}`)
await sleep(5000);
click(863, 51);//选择食物
await sleep(1000);
}
await clickPNG('筛选1', 1);
await clickPNG('筛选2', 1);
await clickPNG('重置');
await sleep(stepDelay);
await clickPNG('确认筛选');
await genshin.returnMainUi();
return { recoveryNumber, resurrectionNumber };
}
// 主执行流程
userName = await getUserName();
const recordPath = `assets/${userName}.txt`;

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "吃药统计",
"version": "1.6.1",
"version": "1.7",
"bgi_version": "0.51",
"description": "用于统计指定两个食物的消耗,推荐锄地前后使用",
"authors": [

View File

@@ -1,9 +1,13 @@
[
{
"name": "userName",
"type": "input-text",
"label": "账户名称\n用于多账户运行时区分不同账户",
"default": "默认账户"
"name": "runMode",
"type": "select",
"label": "运行模式",
"options": [
"营养袋模式",
"筛选模式"
],
"default": "营养袋模式"
},
{
"name": "initSelect",
@@ -11,7 +15,7 @@
"label": "重新初始化药品数量",
"default": false
},
{
{
"name": "recoveryFoodName",
"type": "input-text",
"label": "回血药名称",
@@ -23,16 +27,28 @@
"label": "复活药名称",
"default": ""
},
{
"name": "userName",
"type": "input-text",
"label": "账户名称\n用于多账户运行时区分不同账户",
"default": "默认账户"
},
{
"name": "refreshTime",
"type": "input-text",
"label": "每日刷新时间\n用来定义当日刷新时间0-24之间支持一位小数",
"default": "4.0"
},
{
"name": "loadDelay",
"type": "input-text",
"label": "加载等待延迟\n用于界面打开和切换的等待\n默认800单位毫秒",
"label": "加载等待延迟\n用于界面打开和切换的等待默认800单位毫秒",
"default": "800"
},
{
"name": "stepDelay",
"type": "input-text",
"label": "操作间隔延迟\n用于OCR前和输入药名前的短暂等待\n默认500单位毫秒",
"label": "操作间隔延迟\n用于OCR前和输入药名前的短暂等待默认500单位毫秒",
"default": "500"
}
]