From adf1e0fb7b6157a49087a00838737f58ccf03730 Mon Sep 17 00:00:00 2001
From: skyflag2022 <107539971+skyflag2022@users.noreply.github.com>
Date: Wed, 4 Feb 2026 07:37:01 +0800
Subject: [PATCH] =?UTF-8?q?=E5=90=83=E8=8D=AF=E7=BB=9F=E8=AE=A1=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=20(#2838)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* 增加延迟
* 更新
* 解决正则表达式注入风险
---
repo/js/营养袋吃药统计/README.md | 51 +-
repo/js/营养袋吃药统计/main.js | 711 +++++++++++++++++++--------
repo/js/营养袋吃药统计/manifest.json | 4 +-
repo/js/营养袋吃药统计/settings.json | 21 +-
4 files changed, 571 insertions(+), 216 deletions(-)
diff --git a/repo/js/营养袋吃药统计/README.md b/repo/js/营养袋吃药统计/README.md
index 71f716120..97387388d 100644
--- a/repo/js/营养袋吃药统计/README.md
+++ b/repo/js/营养袋吃药统计/README.md
@@ -1,12 +1,12 @@
-### 药品消耗统计脚本使用指南(更新版)
+### 药品消耗统计脚本使用说明
## 📋 一、脚本概述
-本脚本是专为《原神》设计的自动化药品消耗统计工具,核心能力升级如下:
-- **多模式识别**:支持「营养袋模式」「筛选模式」双模式适配不同场景的药品识别
-- **精准OCR读取**:自动识别背包中指定回血/复活药品数量,适配不同界面布局
+- **多模式识别**:支持「营养袋模式」「筛选模式」「综合模式」三模式适配不同场景的药品识别
+- **精准OCR读取**:自动识别背包中指定回血/复活/攻击/防御/其他药品数量,适配不同界面布局
- **灵活时间配置**:支持自定义每日统计刷新时间(默认4:00,可设0-24小时及一位小数)
- **智能数据管理**:自动保留30天历史记录,按自定义时间周期统计药品消耗/新增
- **多账户隔离**:不同账户数据独立存储,支持合规账户名校验(1-20位中英文/数字)
- **异常友好处理**:识别失败自动兜底、参数错误智能修正,拒绝进入世界的申请
+- **模块化设计**:代码结构优化,新增攻击药、防御药、其他药支持
## 🛠️ 二、环境与工具要求
### 必备工具:茶包版BGI
@@ -25,10 +25,13 @@
## ⚙️ 四、全参数配置说明(新增/细化)
| 参数项 | 类型 | 填写要求 | 默认值 | 核心说明 |
|--------|------|----------|--------|----------|
-| **runMode** | 下拉选择 | 二选一:「营养袋模式」/「筛选模式」 | 营养袋模式 | 营养袋模式:读取便携营养袋内药品;筛选模式:通过背包筛选搜索药品 |
+| **runMode** | 下拉选择 | 三选一:「营养袋模式」/「筛选模式」/「综合模式」 | 营养袋模式 | 营养袋模式:读取便携营养袋内药品;筛选模式:通过背包筛选搜索药品;综合模式:营养袋模式+筛选模式结合 |
| **initSelect** | 复选框 | 仅初始化/重置时临时勾选 | false | 勾选后运行脚本会删除当日同名记录,重新初始化数据(使用后务必取消) |
| **recoveryFoodName** | 文本输入 | 与游戏内回血药名称完全一致 | 空 | 例:「美味的甜甜花酿鸡」,名称错误会导致识别失败 |
| **resurrectionFoodName** | 文本输入 | 与游戏内复活药名称完全一致 | 空 | 例:「美味的提瓦特煎蛋」,支持全量游戏内可食用复活类物品 |
+| **attackFoodName** | 文本输入 | 与游戏内攻击药名称完全一致 | 空 | 例:「美味的堆高高」,支持全量游戏内攻击增益类物品 |
+| **defenseFoodName** | 文本输入 | 与游戏内防御药名称完全一致 | 空 | 例:「美味的贝壳彩糖」,支持全量游戏内防御增益类物品 |
+| **otherFoodName** | 文本输入 | 与游戏内其他药名称完全一致 | 空 | 例:「美味的风神杂烩菜」,支持全量游戏内其他增益类物品 |
| **userName** | 文本输入 | 1-20字符,仅支持中英文、数字 | 默认账户 | 多账户区分核心,违规名称自动替换为默认账户 |
| **refreshTime** | 文本输入 | 0-24之间,支持一位小数 | 4.0 | 自定义每日统计周期分界点(如4.5=4:30),错误值自动修正为4.0 |
| **loadDelay** | 文本输入 | 非负整数(单位:毫秒) | 800 | 界面打开/切换的等待延迟,低配置设备可适当增大 |
@@ -54,11 +57,18 @@
#### 筛选模式
- 脚本自动打开背包→进入食物分类→筛选搜索指定药品→读取数量
- 无需装备营养袋,适配未配置营养袋的场景,识别流程稍长
+- 只处理回血药和复活药
+
+#### 综合模式
+- 脚本自动执行:营养袋模式识别回血/复活药 + 筛选模式识别攻击/防御/其他药
+- 结合两种模式优势,支持全类型药品统计
+- 回血药和复活药通过营养袋模式获取,攻击药、防御药、其他药通过筛选模式获取
#### 通用规则
- 每日首次运行(自定义refreshTime后):记录为当日初始值
- 后续运行:对比初始值计算消耗/新增(正数=消耗,负数=新增)
- 每次运行自动保存记录,仅保留30天内数据,过期自动清理
+- 只记录数量大于0的药品数据
### 场景三:更换药品/重置统计数据
1. 在设置中勾选`initSelect`选项
@@ -77,8 +87,16 @@
```
时间:202X/XX/XX XX:XX:XX-【药品名称】-【数量】
时间:202X/XX/XX XX:XX:XX-【药品名称】-【数量】
+...
```
-每条记录包含时间戳+药品名+数量,双药品记录成对生成,保证数据完整性。
+每条记录包含时间戳+药品名+数量,支持5种药品类型:
+- 回血药
+- 复活药
+- 攻击药
+- 防御药
+- 其他药
+
+**注意**:只生成数量大于0的药品记录,保证数据有效性。
### 3. OCR识别异常处理
| 异常场景 | 处理逻辑 | 通知/日志 |
@@ -87,6 +105,7 @@
| 药品名称为空 | 识别结果无效 | log.warn「XX药名字没填」 |
| refreshTime非法 | 自动修正为4.0 | log.warn「刷新时间设置错误,使用默认值4.0」 |
| 账户名违规 | 替换为默认账户 | log.error「账户名XX违规,使用默认账户」 |
+| 数量为0 | 不记录数据 | 只记录数量大于0的药品数据,通知中只显示有效数据 |
## ⚠️ 七、重要注意事项(强化)
### 1. 运行时机建议
@@ -94,13 +113,20 @@
- 避免在两次脚本运行之间大批量制作/使用药品,防止统计偏差
- 低配置设备:适当增大loadDelay/stepDelay,提升识别成功率
-### 2. 双模式适配要点
+### 2. 三模式适配要点
| 模式 | 优势 | 注意事项 |
|------|------|----------|
| 营养袋模式 | 识别快、步骤少 | 必须装备便携营养袋,仅识别营养袋内药品 |
-| 筛选模式 | 无需装备营养袋 | 药品名称必须精准,依赖背包筛选功能正常 |
+| 筛选模式 | 无需装备营养袋 | 药品名称必须精准,依赖背包筛选功能正常,只处理回血药和复活药 |
+| 综合模式 | 支持全类型药品统计 | 结合营养袋模式和筛选模式,需要装备便携营养袋 |
-### 3. 常见误区修正
+### 3. 建议搭配JS通知使用
+- **推荐使用JS通知**:本脚本会发送各类通知,包括初始化完成、使用情况、异常提醒等
+- **通知好处**:及时获取统计结果,不错过重要信息,方便日常使用
+- **确保通知功能正常**:请确保BGI的JS通知功能已开启,以便接收脚本发送的各类通知
+- **通知内容**:包含账户信息、药品使用情况、库存信息等,格式清晰易读
+
+### 4. 常见误区修正
❌ 错误:`initSelect`长期勾选 → 每次运行都重置数据,无法统计消耗
✅ 正确:仅重置/换药品时勾选,运行后立即取消
@@ -113,8 +139,9 @@
## 🔧 八、故障排查指南(新增模式/参数排查)
| 问题现象 | 优先检查项 | 解决方案 |
|----------|------------|----------|
-| 药品数量识别为0 | 1. 运行模式是否匹配场景
2. 药品名称是否完全一致
| 1. 营养袋模式需装备营养袋;筛选模式检查背包食物分类
2. 复制游戏内药品全名(含「美味的/冷的」等前缀)
|
+| 药品数量识别为0 | 1. 运行模式是否匹配场景
2. 药品名称是否完全一致
3. 综合模式是否装备了营养袋 | 1. 营养袋模式需装备营养袋;筛选模式检查背包食物分类
2. 复制游戏内药品全名(含「美味的/冷的」等前缀)
3. 综合模式需要装备便携营养袋 |
| 统计周期错误 | 1. refreshTime是否合法
2. 系统时间是否准确 | 1. 确认值在0-24之间(如4.0/12.5),错误值会自动修正
2. 同步系统时间到网络标准时间 |
-| 脚本运行卡顿/超时 | 1. loadDelay/stepDelay是否过小
2. 设备性能是否不足 | 1. 逐步增大延迟值(如loadDelay改为1000)
2. 关闭后台无关程序,保证游戏前台运行 |
+| 脚本运行卡顿/超时 | 1. loadDelay/stepDelay是否过小
2. 设备性能是否不足
3. 综合模式下是否需要更长延迟 | 1. 逐步增大延迟值(如loadDelay改为1000)
2. 关闭后台无关程序,保证游戏前台运行
3. 综合模式包含更多步骤,可适当增大延迟 |
+| 部分药品未记录 | 1. 药品名称是否填写
2. 药品数量是否大于0
3. 对应模式是否支持该类型药品 | 1. 检查对应药品名称是否正确填写
2. 只记录数量大于0的药品数据
3. 筛选模式只处理回血药和复活药,攻击/防御/其他药需使用综合模式 |
| 多账户数据混淆 | 1. userName是否唯一
2. 记录文件是否存在重名 | 1. 为每个账户设置唯一名称(如「旅行者001/旅行者002」)
2. 检查assets目录,删除重名的错误记录文件 |
-| 模式切换后识别失败 | 1. 对应模式的模板图片是否存在
2. 点击坐标是否匹配分辨率 | 1. 确认assets目录有「营养袋.png」「筛选1.png」「筛选2.png」等
2. 重新确认游戏分辨率为1920×1080 |
+| 模式切换后识别失败 | 1. 对应模式的模板图片是否存在
2. 点击坐标是否匹配分辨率
3. 综合模式是否包含所有必要的模板图片 | 1. 确认assets目录有「营养袋.png」「筛选1.png」「筛选2.png」等
2. 重新确认游戏分辨率为1920×1080
3. 综合模式需要营养袋和筛选相关的所有模板图片 |
diff --git a/repo/js/营养袋吃药统计/main.js b/repo/js/营养袋吃药统计/main.js
index c2fd6f4c7..e480fceb5 100644
--- a/repo/js/营养袋吃药统计/main.js
+++ b/repo/js/营养袋吃药统计/main.js
@@ -1,7 +1,10 @@
let userName = settings.userName || "默认账户";
const mode = settings.runMode || "营养袋模式"
-let recoveryFoodName = settings.recoveryFoodName || "回血药名字没填";
-let resurrectionFoodName = settings.resurrectionFoodName || "复活药名字没填";
+let recoveryFoodName = settings.recoveryFoodName || "";
+let resurrectionFoodName = settings.resurrectionFoodName || "";
+let attackFoodName = settings.attackFoodName || "";
+let defenseFoodName = settings.defenseFoodName || "";
+let otherFoodName = settings.otherFoodName || "";
const ocrRegion = {
x: 1422,
y: 586,
@@ -31,11 +34,16 @@ if (isNaN(refreshTime) || refreshTime < 0 || refreshTime >= 24) {
const refreshHour = Math.floor(refreshTime);
const refreshMinute = Math.floor((refreshTime - refreshHour) * 60);
log.info(`刷新时间为: ${refreshHour}:${String(refreshMinute).padStart(2, '0')}`);
+
+// 正则特殊字符转义函数
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
(async function () {
// 检验账户名
async function getUserName() {
userName = userName.trim();
- // 数字,中英文,长度在20个字符以内
+ // 账户名规则:数字、中英文,长度1-20字符
if (!userName || !/^[\u4e00-\u9fa5A-Za-z0-9]{1,20}$/.test(userName)) {
log.error(`账户名${userName}违规,暂时使用默认账户名,请查看readme后修改`)
userName = "默认账户";
@@ -81,16 +89,22 @@ log.info(`刷新时间为: ${refreshHour}:${String(refreshMinute).padStart(2, '0
* 获取本地记录中当天4点至次日4点间的最早记录
* @param {string} filePath - 记录文件路径
* @returns {Promise