diff --git a/repo/js/背包材料统计/README.md b/repo/js/背包材料统计/README.md
index 45963bd74..0df212229 100644
--- a/repo/js/背包材料统计/README.md
+++ b/repo/js/背包材料统计/README.md
@@ -38,14 +38,15 @@
### 核心优势
1. **自动CD判断**:无需手动关注材料刷新状态,脚本自动识别CD是否就绪;
2. **灵活路径管理**:支持自定义添加路径,自动排除低效/无效路径;
-3. **独立名单识别**:不与路边NPC、神像交互;可自定义识别名单(操作见「四、问题解答」);
+3. **独立名单识别**:不与路边NPC、神像交互;可自定义识别名单(操作见「四、问题解答Q4」);
4. **实时弹窗保护**:内置弹窗模块(覆盖路边信件、过期物品、月卡、调查等场景),运行时全程保护路径不被弹窗干扰。
5. **自动黑名单**:内置拾取模块,联动材料统计,可识别爆满的路径材料,自动屏蔽。
## 二、用前须知
1. 需具备基础电脑操作能力(如文件夹复制、路径查找);
-2. 脚本不自带路径文件,需手动对目标文件夹进行操作(步骤见「三、使用方法」)。
+2. 非1080p显示器,使用前需要根据显示器调整背包物品界面的 拖动距离 ,推荐“一次划页稍小于4行材料的距离”;
+3. 脚本不自带路径文件,需手动对目标文件夹进行操作(步骤见「三、使用方法」)。
## 三、使用方法
@@ -110,14 +111,16 @@
| 配置项 | 功能说明 | 操作建议 |
|----------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------|
| 1. 目标数量 | 仅当背包材料数量**低于此值**时,该材料的路径才会被纳入执行序列 | 这是个统一值,管理路径下全部材料的目标数量 |
-| 2. 优先级材料 | 无视“目标数量”限制,直接纳入执行序列顶层(最高优先级) | 填写当前急需材料(例:“虹滴晶”“巡陆艇”) |
+| 2. 优先级材料 | 无视“目标数量”限制,直接纳入执行序列顶层(最高优先级) | 填写当前急需材料(例:虹滴晶,巡陆艇) |
| 3. 时间成本 | 当一个路径有3-5次运行记录后,自动计算“单材料获取时间”;超过30秒则跳过该路径 | 保持默认30秒即可,无需频繁修改(可过滤低效路径) |
| 4. 发送通知 | ① 每类材料跑完通知一次;② 全部材料跑完汇总通知一次(需开启BGI通知) | 建议开启,方便实时了解进度(接收端如企业微信需自行配置) |
| 5. 取消扫描 | 取消“每个路径执行后”的背包扫描,仅保留“全部执行前/后”2次扫描 | 有效路径记录达3条以上时可以开启,可节约运行时间 |
| 6. 仅 pathing 材料 | 仅扫描 `pathing` 文件夹内的材料,跳过其他分类,大幅缩短扫描时间 | 路径配置完成后开启,提升脚本运行效率 |
-| 7. 弹窗名 | 不填则默认循环执行 `assets\imageClick` 文件夹下所有弹窗;填写则仅执行指定弹窗 | 推荐默认,需单独适配某类弹窗时填写(例:仅处理月卡弹窗则填:月卡) |
-| 8. 采用的 CD 分类 | 仅执行 `materialsCD` 文件夹内配置的材料路径(支持新增CD分类txt) | 新增材料时,需在该文件夹同步配置CD规则(操作见「四、问题解答4」) |
-| 9. 拖动距离 | 解决非1080p分辨率下“划页过头”问题,需调整到“一次划页≤4行” | 拖动点建议选“第五行材料附近”;大于1080p屏可适当减小数值 |
+| 7. 弹窗名 | 不填则默认循环执行 `assets\imageClick` 文件夹下所有弹窗;填写则仅执行指定弹窗 | 推荐默认,需单独适配某类弹窗时填写(例:月卡,复苏) |
+| 8. 采用的 CD 分类 | 不填则默认执行 `materialsCD` 文件夹内配置的CD分类;填写则仅执行指定CD分类 | 新增材料时,需在该文件夹同步配置CD规则(操作见「四、问题解答Q2」) |
+| 9. 采用的识别名单 | 不填则默认执行 `targetText` 文件夹内配置的识别名单;填写则仅执行指定识别名单 | 新增名单时,需符合配置规则(操作见「四、问题解答Q4」) |
+| 10. 超量阈值 | 首次扫描后,超量的路径材料,将从识别名单中剔除,默认5000 | 不推荐9999,怪物材料有几千就够了,采用默认数值,可自动避免爆背包 |
+| 11. 拖动距离 | 解决非1080p分辨率下“划页过头”问题,需调整到“一次划页≤4行” | 拖动点建议选“第五行材料附近”;大于1080p屏可适当减小数值 |
## 四、注意事项
@@ -134,23 +137,9 @@
### Q1:如何排除不想要的路径?
A:1. 打开 `pathing` 文件夹(脚本路径:`BetterGI\User\JsScript\背包材料统计\pathing`);
2. 直接删除/移走目标材料/怪物的路径文件夹;
- 3. **注意**:不要将路径文件放入 `targetText` 或 `materialsCD` 文件夹(① 这两个文件夹默认全部读取,增加负担;② 也不安全,会被更新覆盖)。
+ **其他方法**:看「四、问题解答Q2」,按格式要求填入对应的材料名(或者从其他CD文件中复制过来),在「JS 自定义设置」【采用的 CD 分类】中输入新建的文件名,即可实现只加载该CD文件里材料的路径。
-### Q2:如何自定义识别名单?
-A:1. 打开 `targetText` 文件夹(脚本路径:`BetterGI\User\JsScript\背包材料统计\targetText`);
- 2. 新建/编辑txt文件,按格式填写:`自定义名称:目标1,目标2`(英文冒号+英文逗号,例:“新材料:霜盏花,便携轴承,”);
- 3. 若需排除怪物掉落材料:找到“掉落.txt”,删除对应材料名即可;
- 4. 操作参考截图:
-
-

-

-
-
-### Q3:如何识别不规范命名的路径文件夹(如“纳塔食材一条龙”“果园.json”)?
-A:将不规范的文件夹/文件,放入**适配的材料文件夹**中即可(路径CD由“所在材料文件夹”决定)。
- 例:“果园.json”放入“苹果”文件夹,将按“苹果”的CD规则执行。
-
-### Q4:如何添加新材料?
+### Q2:如何添加新材料?
A:1. 打开 `materialsCD` 文件夹(脚本路径:`BetterGI\User\JsScript\背包材料统计\materialsCD`);
2. 新建/编辑txt文件,按格式填写:`CD规则:材料1,材料2`(中文冒号+中文逗号,CD规则参考自带文件,例:“1次0点:月落银,宿影花,”),`材料1`或`材料2`将会作为标准名;
3. **关键要求**:路径文件夹名、材料图片名必须与“材料1或2”完全一致(多层文件夹默认读取最外层标准名文件夹);
@@ -160,6 +149,20 @@ A:1. 打开 `materialsCD` 文件夹(脚本路径:`BetterGI\User\JsScript\
+### Q3:如何识别不规范命名的路径文件夹(如“纳塔食材一条龙”“果园.json”)?
+A:将不规范的文件夹/文件,放入**适配的材料文件夹**中即可(路径CD由“所在材料文件夹”决定)。
+ 例:“果园.json”放入“苹果”文件夹,将按“苹果”的CD规则执行。
+
+### Q4:如何自定义识别名单?
+A:1. 打开 `targetText` 文件夹(脚本路径:`BetterGI\User\JsScript\背包材料统计\targetText`);
+ 2. 新建/编辑txt文件,按格式填写:`自定义名称:目标1,目标2`(英文冒号+英文逗号,例:“新材料:霜盏花,便携轴承,”);
+ 3. 若需排除怪物掉落材料:找到“掉落.txt”,删除对应材料名即可;
+ 4. 操作参考截图:
+
+

+

+
+
### Q5:如何取消路径执行后扫描背包?
A:在「JS自定义设置」中勾选“取消扫描”(依旧会保留“全部材料执行始/末”的2次扫描)。
@@ -209,4 +212,5 @@ A:记录文件夹位于 `BetterGI\User\JsScript\背包材料统计\` 下,各
| v2.41 | 修复“勾选分类的本地记录”bug;新增“仅背包统计”选项;补充记录损坏处理说明 |
| v2.42 | 新增“无路径间扫描”“noRecord模式”(适合成熟路径);新增怪物材料CD文件 |
| v2.50 | 新增独立名单拾取、弹窗模块;支持怪物名识别 |
-| v2.51 | 自定义设置新增“拖动距离/拖动点”;新增月卡弹窗识别;路径材料达9999自动上黑名单;修复怪物0收获记录 |
\ No newline at end of file
+| v2.51 | 自定义设置新增“拖动距离/拖动点”;新增月卡弹窗识别;路径材料达9999自动上黑名单;修复怪物0收获记录 |
+| v2.52 | 自定义设置新增“超量阈值”和“识别名单”输入框;新增多层弹窗逻辑 |
\ No newline at end of file
diff --git a/repo/js/背包材料统计/assets/imageClick/其他/F/config.json b/repo/js/背包材料统计/assets/imageClick/其他/F/config.json
new file mode 100644
index 000000000..4a23daa02
--- /dev/null
+++ b/repo/js/背包材料统计/assets/imageClick/其他/F/config.json
@@ -0,0 +1,10 @@
+{
+ "isSpecial": true,
+ "operationType": "key_press",
+ "keyCode": "VK_F",
+ "xOffset": 0,
+ "yOffset": 0,
+ "detectRegion": { "x": 1207, "y": 783, "width": 42, "height": 42 },
+ "nextLevelOnSuccess": "",
+ "nextLevelOnFailure": ""
+}
\ No newline at end of file
diff --git a/repo/js/背包材料统计/assets/imageClick/其他/F/icon/F_2.png b/repo/js/背包材料统计/assets/imageClick/其他/F/icon/F_2.png
new file mode 100644
index 000000000..cef22ceb2
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/其他/F/icon/F_2.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/其他/滚轮/config.json b/repo/js/背包材料统计/assets/imageClick/其他/滚轮/config.json
new file mode 100644
index 000000000..2326821af
--- /dev/null
+++ b/repo/js/背包材料统计/assets/imageClick/其他/滚轮/config.json
@@ -0,0 +1,10 @@
+{
+ "isSpecial": true,
+ "operationType": "key_mouse_script",
+ "scriptPath": "assets/滚轮下翻.json",
+ "xOffset": 0,
+ "yOffset": 0,
+ "detectRegion": { "x": 1206, "y": 175, "width": 44, "height": 735 },
+ "nextLevelOnSuccess": "assets\\imageClick\\其他\\F",
+ "nextLevelOnFailure": ""
+}
\ No newline at end of file
diff --git a/repo/js/背包材料统计/assets/imageClick/其他/滚轮/icon/F_2.png b/repo/js/背包材料统计/assets/imageClick/其他/滚轮/icon/F_2.png
new file mode 100644
index 000000000..cef22ceb2
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/其他/滚轮/icon/F_2.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/其他/调查/Picture/image6.png b/repo/js/背包材料统计/assets/imageClick/其他/调查/Picture/image6.png
new file mode 100644
index 000000000..1f6c9c4bd
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/其他/调查/Picture/image6.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/其他/调查/icon/123.png b/repo/js/背包材料统计/assets/imageClick/其他/调查/icon/123.png
new file mode 100644
index 000000000..f45347133
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/其他/调查/icon/123.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/复苏/Picture/全员复苏.png b/repo/js/背包材料统计/assets/imageClick/复苏/Picture/全员复苏.png
new file mode 100644
index 000000000..e11d2c8b1
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/复苏/Picture/全员复苏.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/复苏/icon/确认.png b/repo/js/背包材料统计/assets/imageClick/复苏/icon/确认.png
new file mode 100644
index 000000000..6a8d84c25
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/复苏/icon/确认.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/对话/config.json b/repo/js/背包材料统计/assets/imageClick/对话/config.json
new file mode 100644
index 000000000..bb476daf9
--- /dev/null
+++ b/repo/js/背包材料统计/assets/imageClick/对话/config.json
@@ -0,0 +1,15 @@
+{
+ "isSpecial": true,
+ "operationType": "key_press",
+ "keyCode": "VK_SPACE",
+ "xOffset": 950,
+ "yOffset": 1050,
+ "detectRegion": {
+ "x": 264,
+ "y": 36,
+ "width": 66,
+ "height": 24
+ },
+ "nextLevelOnSuccess": "assets\\imageClick\\其他\\滚轮",
+ "nextLevelOnFailure": ""
+}
\ No newline at end of file
diff --git a/repo/js/背包材料统计/assets/imageClick/对话/icon/NoUI.png b/repo/js/背包材料统计/assets/imageClick/对话/icon/NoUI.png
new file mode 100644
index 000000000..c3e42de61
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/对话/icon/NoUI.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/月卡/config.json b/repo/js/背包材料统计/assets/imageClick/月卡/config.json
new file mode 100644
index 000000000..3dd0434d6
--- /dev/null
+++ b/repo/js/背包材料统计/assets/imageClick/月卡/config.json
@@ -0,0 +1,6 @@
+{
+ "xOffset": 0,
+ "yOffset": 455,
+ "loopCount": 3,
+ "loopDelay": 1000
+}
\ No newline at end of file
diff --git a/repo/js/背包材料统计/assets/imageClick/登录/Picture/load.png b/repo/js/背包材料统计/assets/imageClick/登录/Picture/load.png
new file mode 100644
index 000000000..18c847767
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/登录/Picture/load.png differ
diff --git a/repo/js/背包材料统计/assets/imageClick/登录/config.json b/repo/js/背包材料统计/assets/imageClick/登录/config.json
new file mode 100644
index 000000000..a45f728f4
--- /dev/null
+++ b/repo/js/背包材料统计/assets/imageClick/登录/config.json
@@ -0,0 +1 @@
+{ "xOffset": -845, "yOffset": 325 }
\ No newline at end of file
diff --git a/repo/js/背包材料统计/assets/imageClick/登录/icon/setting.png b/repo/js/背包材料统计/assets/imageClick/登录/icon/setting.png
new file mode 100644
index 000000000..3877b3c4e
Binary files /dev/null and b/repo/js/背包材料统计/assets/imageClick/登录/icon/setting.png differ
diff --git a/repo/js/背包材料统计/lib/autoPick.js b/repo/js/背包材料统计/lib/autoPick.js
index e0038dec1..941db67c4 100644
--- a/repo/js/背包材料统计/lib/autoPick.js
+++ b/repo/js/背包材料统计/lib/autoPick.js
@@ -31,18 +31,31 @@ function readtargetTextCategories(targetTextDir) {
const targetTextFilePaths = readAllFilePaths(targetTextDir, 0, 1);
const materialCategories = {};
+ // 解析筛选名单
+ const pickTextNames = (settings.PickCategories || "")
+ .split(/[,,、 \s]+/).map(n => n.trim()).filter(n => n);
+
+ // 【新增:兜底日志】确认pickTextNames是否为空,方便排查
+ log.info(`筛选名单状态:${pickTextNames.length === 0 ? '未指定(空),将加载所有文件' : '指定了:' + pickTextNames.join(',')}`);
+
for (const filePath of targetTextFilePaths) {
if (state.cancelRequested) break;
const content = file.readTextSync(filePath);
if (!content) {
log.error(`加载文件失败:${filePath}`);
- continue; // 跳过当前文件
+ continue;
}
const sourceCategory = basename(filePath).replace('.txt', ''); // 去掉文件扩展名
+ // 【核心筛选:空名单直接跳过判断,加载所有】
+ if (pickTextNames.length === 0) {
+ // 空名单时,直接保留当前文件,不跳过
+ } else if (!pickTextNames.includes(sourceCategory)) {
+ // 非空名单且不在列表里,才跳过
+ continue;
+ }
materialCategories[sourceCategory] = parseCategoryContent(content);
}
- // log.info(`完成材料分类信息读取,分类信息:${JSON.stringify(materialCategories, null, 2)}`);
return materialCategories;
}
// 定义替换映射表
@@ -171,7 +184,7 @@ async function alignAndInteractTarget(targetTexts, fDialogueRo, textxRange, text
log.info("检测中...");
lastLogTime = currentTime;
}
- await sleep(50); // 关键50时可避免F多目标滚动中拾取错,背包js这边有弹窗模块,就没必要增加延迟降低效率了
+ await sleep(50);
cachedFrame?.dispose();
cachedFrame = captureGameRegion();
@@ -192,7 +205,6 @@ async function alignAndInteractTarget(targetTexts, fDialogueRo, textxRange, text
for (let targetText of targetTexts) {
let targetResult = ocrResults.find(res => res.text.includes(targetText));
if (targetResult) {
- // log.info(`找到目标文本: ${targetText}`);
// 生成唯一标识并更新识别计数(文本+Y坐标)
const materialId = `${targetText}-${targetResult.y}`;
@@ -203,7 +215,6 @@ async function alignAndInteractTarget(targetTexts, fDialogueRo, textxRange, text
// log.info(`目标文本 '${targetText}' 和 F 图标水平对齐`);
if (recognitionCount.get(materialId) >= 1) {
keyPress("F"); // 执行交互操作
- // log.info(`F键执行成功,识别计数: ${recognitionCount.get(materialId)}`);
log.info(`交互或拾取: ${targetText}`);
// F键后清除计数,确保单次交互
diff --git a/repo/js/背包材料统计/lib/backStats.js b/repo/js/背包材料统计/lib/backStats.js
index e75e40183..76320e18c 100644
--- a/repo/js/背包材料统计/lib/backStats.js
+++ b/repo/js/背包材料统计/lib/backStats.js
@@ -4,6 +4,7 @@ const holdX = Math.min(1920, Math.max(0, Math.floor(Number(settings.HoldX) || 10
const holdY = Math.min(1080, Math.max(0, Math.floor(Number(settings.HoldY) || 750)));
const totalPageDistance = Math.max(10, Math.floor(Number(settings.PageScrollDistance) || 711));
const targetCount = Math.min(9999, Math.max(0, Math.floor(Number(settings.TargetCount) || 5000))); // 设定的目标数量
+const exceedCount = Math.min(9999, Math.max(0, Math.floor(Number(settings.ExceedCount) || 5000))); // 设定的超量目标数量
const imageDelay = Math.min(1000, Math.max(0, Math.floor(Number(settings.ImageDelay) || 0))); // 识图基准时长 await sleep(imageDelay);
// 配置参数
@@ -383,7 +384,7 @@ async function scanMaterials(materialsCategory, materialCategoryMap) {
width: 66 + 2 * tolerance,
height: 22 + 2 * tolerance
};
- const ocrResult = await recognizeText(ocrRegion, 1000, 10, 5, 2, ra);
+ const ocrResult = await recognizeText(ocrRegion, 200, 10, 5, 2, ra);
materialInfo.push({ name, count: ocrResult || "?" });
if (!hasFoundFirstMaterial) {
@@ -516,7 +517,7 @@ var excessMaterialNames = []; // 超量材料名单
function filterLowCountMaterials(pathingMaterialCounts, materialCategoryMap) {
// 新增:超量阈值(普通材料9999,矿石处理后也是9999)
- const EXCESS_THRESHOLD = 9999;
+ const EXCESS_THRESHOLD = exceedCount;
// 新增:临时存储本次超量材料
const tempExcess = [];
diff --git a/repo/js/背包材料统计/lib/file.js b/repo/js/背包材料统计/lib/file.js
index a7d83cca6..a5d3d5666 100644
--- a/repo/js/背包材料统计/lib/file.js
+++ b/repo/js/背包材料统计/lib/file.js
@@ -1,16 +1,20 @@
+// ======================== 全局工具函数(只定义1次,所有函数共用)========================
+// 1. 路径标准化函数(统一处理,消除重复)
+function normalizePath(path) {
+ if (!path || typeof path !== 'string') return '';
+ let standardPath = path.replace(/\\/g, '/').replace(/\/+/g, '/');
+ return standardPath.endsWith('/') ? standardPath.slice(0, -1) : standardPath;
+}
-
-// ==============================================
-// 5. 角色识别与策略执行相关函数(保留原始功能)
-// ==============================================
-// 工具函数
+// 2. 提取路径最后一级名称
function basename(filePath) {
if (!filePath || typeof filePath !== 'string') return '';
- const normalizedPath = filePath.replace(/\\/g, '/');
+ const normalizedPath = normalizePath(filePath);
const lastSlashIndex = normalizedPath.lastIndexOf('/');
return lastSlashIndex !== -1 ? normalizedPath.substring(lastSlashIndex + 1) : normalizedPath;
}
+
/*
// 如果路径存在且返回的是数组,则认为是目录Folder
function pathExists(path) {
diff --git a/repo/js/背包材料统计/lib/imageClick.js b/repo/js/背包材料统计/lib/imageClick.js
index b82271560..1eeecf484 100644
--- a/repo/js/背包材料统计/lib/imageClick.js
+++ b/repo/js/背包材料统计/lib/imageClick.js
@@ -1,195 +1,457 @@
-// 新增:独立的预加载函数,负责所有资源预处理
+// ======================== 1. 预加载函数(精简日志版)========================
async function preloadImageResources(specificNames) {
- log.info("开始预加载所有图片资源");
+ // log.info("开始预加载所有图片资源");
+
+ function hasIconFolder(dirPath) {
+ try {
+ const entries = readAllFilePaths(dirPath, 0, 0, [], true);
+ return entries.some(entry => normalizePath(entry).endsWith('/icon'));
+ } catch (e) {
+ log.error(`检查目录【${dirPath}】是否有icon文件夹失败:${e.message}`);
+ return false;
+ }
+ }
- // 统一参数格式(与原逻辑一致)
let preSpecificNames = specificNames;
- if (typeof specificNames === 'string') {
- preSpecificNames = [specificNames];
- }
+ if (typeof specificNames === 'string') preSpecificNames = [specificNames];
const isAll = !preSpecificNames || preSpecificNames.length === 0;
- if (isAll) {
- log.info("未指定具体弹窗名称,将执行所有弹窗目录处理");
- } else {
- log.info(`指定处理弹窗名称:${preSpecificNames.join(', ')}`);
- }
+ // if (isAll) log.info("未指定具体弹窗名称,将执行所有含icon文件夹的弹窗目录处理");
+ // else log.info(`指定处理弹窗名称:${preSpecificNames.join(', ')}(仅含icon文件夹的目录)`);
- // 定义根目录(与原代码一致)
const rootDir = "assets/imageClick";
+ const rootDirNormalized = normalizePath(rootDir);
+ const subDirs = readAllFilePaths(rootDir, 0, 2, [], true);
- // 获取所有子目录(与原代码一致)
- const subDirs = readAllFilePaths(rootDir, 0, 0, [], true);
-
- // 筛选目标目录(与原代码一致)
- const targetDirs = isAll
- ? subDirs
- : subDirs.filter(subDir => {
- const dirName = basename(subDir);
- return preSpecificNames.includes(dirName);
- });
+ const targetDirs = subDirs.filter(subDir => {
+ const dirName = basename(subDir);
+ const hasIcon = hasIconFolder(subDir);
+ const matchName = isAll ? true : preSpecificNames.includes(dirName);
+ return hasIcon && matchName;
+ });
if (targetDirs.length === 0) {
- log.info(`未找到与指定名称匹配的目录,名称列表:${preSpecificNames?.join(', ') || '所有'}`);
+ // log.info("未找到符合条件的弹窗目录");
return [];
}
- // 预加载所有目录的资源(原imageClick内的资源加载逻辑)
const preloadedResources = [];
for (const subDir of targetDirs) {
const dirName = basename(subDir);
- // log.info(`开始预处理弹窗类型:${dirName}`);
+ const fullPath = normalizePath(subDir);
+ const pathSegments = fullPath.slice(rootDirNormalized.length + 1).split('/');
+ const level = pathSegments.length;
+ const isFirstLevel = level === 1;
- // 查找icon和Picture文件夹(与原代码一致)
- const entries = readAllFilePaths(subDir, 0, 1, [], true);
- const iconDir = entries.find(entry => entry.endsWith('\icon'));
- const pictureDir = entries.find(entry => entry.endsWith('\Picture'));
+ let popupConfig = {
+ isSpecial: false,
+ operationType: "click",
+ ocrConfig: null,
+ xOffset: 0,
+ yOffset: 0,
+ detectRegion: null,
+ nextLevelOnSuccess: "",
+ nextLevelOnFailure: "",
+ loopCount: 1,
+ loopDelay: 0
+ };
+ const configPath = normalizePath(`${subDir}/config.json`);
+ let isSpecialModule = false;
+ let specialDetectRegion = null;
- if (!iconDir) {
- log.warn(`未找到 icon 文件夹,跳过分类文件夹:${subDir}`);
- continue;
- }
- if (!pictureDir) {
- log.warn(`未找到 Picture 文件夹,跳过分类文件夹:${subDir}`);
- continue;
+ if (fileExists(configPath)) {
+ try {
+ const configContent = file.readTextSync(configPath);
+ popupConfig = { ...popupConfig, ...JSON.parse(configContent) };
+ isSpecialModule = popupConfig.isSpecial === true
+ && typeof popupConfig.detectRegion === 'object'
+ && popupConfig.detectRegion !== null
+ && popupConfig.detectRegion.x != null
+ && popupConfig.detectRegion.y != null
+ && popupConfig.detectRegion.width != null
+ && popupConfig.detectRegion.height != null
+ && popupConfig.detectRegion.width > 0
+ && popupConfig.detectRegion.height > 0;
+ specialDetectRegion = isSpecialModule ? popupConfig.detectRegion : null;
+ // log.info(`【${dirName}】加载配置成功:${isFirstLevel ? '第一级' : '第二级'} | 模块类型:${isSpecialModule ? '特殊模块' : '普通模块'}`);
+ } catch (e) {
+ log.error(`【${dirName}】解析配置失败,使用默认配置:${e.message}`);
+ isSpecialModule = false;
+ }
}
- // 读取图片文件(与原代码一致)
- const iconFilePaths = readAllFilePaths(iconDir, 0, 0, ['.png', '.jpg', '.jpeg']);
- const pictureFilePaths = readAllFilePaths(pictureDir, 0, 0, ['.png', '.jpg', '.jpeg']);
-
- // 预创建icon识别对象(与原代码一致)
- const iconRecognitionObjects = [];
- for (const filePath of iconFilePaths) {
- const mat = file.readImageMatSync(filePath);
- if (mat.empty()) {
- log.error(`加载图标失败:${filePath}`);
+ if (isSpecialModule) {
+ const entries = readAllFilePaths(subDir, 0, 1, [], true);
+ const iconDir = entries.find(entry => normalizePath(entry).endsWith('/icon'));
+ const iconFilePaths = readAllFilePaths(iconDir, 0, 0, ['.png', '.jpg', '.jpeg']);
+
+ if (iconFilePaths.length === 0) {
+ log.warn(`【${dirName}】特殊模块无有效icon文件,跳过`);
continue;
}
- const recognitionObject = RecognitionObject.TemplateMatch(mat, 0, 0, 1920, 1080);
- iconRecognitionObjects.push({ name: basename(filePath), ro: recognitionObject, iconDir });
- }
- // 预创建图库区域(与原代码一致)
- const pictureRegions = [];
- for (const filePath of pictureFilePaths) {
- const mat = file.readImageMatSync(filePath);
- if (mat.empty()) {
- log.error(`加载图库图片失败:${filePath}`);
+ const iconRecognitionObjects = [];
+ for (const filePath of iconFilePaths) {
+ const mat = file.readImageMatSync(filePath);
+ if (mat.empty()) {
+ log.error(`【${dirName}】特殊模块加载图标失败:${filePath}`);
+ continue;
+ }
+ iconRecognitionObjects.push({
+ name: basename(filePath),
+ ro: RecognitionObject.TemplateMatch(mat, 0, 0, 1920, 1080),
+ iconDir,
+ mat: mat
+ });
+ }
+
+ const targetIcon = iconRecognitionObjects[0];
+ const manualRegion = new ImageRegion(targetIcon.mat, specialDetectRegion.x, specialDetectRegion.y);
+ manualRegion.width = specialDetectRegion.width;
+ manualRegion.height = specialDetectRegion.height;
+
+ const foundRegions = [{
+ pictureName: "特殊模块",
+ iconName: targetIcon.name,
+ region: manualRegion,
+ iconDir: iconDir
+ }];
+ // log.info(`【${dirName}】特殊模块生成识别区域:x=${manualRegion.x}, y=${manualRegion.y}, 宽=${manualRegion.width}, 高=${manualRegion.height}`);
+
+ preloadedResources.push({
+ dirName,
+ fullPath,
+ foundRegions,
+ popupConfig,
+ isFirstLevel: isFirstLevel,
+ level: level
+ });
+
+ } else {
+ const entries = readAllFilePaths(subDir, 0, 1, [], true);
+ const iconDir = entries.find(entry => normalizePath(entry).endsWith('/icon'));
+ const pictureDir = entries.find(entry => normalizePath(entry).endsWith('/Picture'));
+
+ if (!pictureDir) {
+ log.warn(`【${dirName}】普通模块无Picture文件夹,跳过`);
continue;
}
- pictureRegions.push({ name: basename(filePath), region: new ImageRegion(mat, 0, 0) });
- }
- // 预计算匹配区域(与原代码一致)
- const foundRegions = [];
- for (const picture of pictureRegions) {
- for (const icon of iconRecognitionObjects) {
- const foundRegion = picture.region.find(icon.ro);
- if (foundRegion.isExist()) {
- foundRegions.push({
- pictureName: picture.name,
- iconName: icon.name,
- region: foundRegion,
- iconDir: icon.iconDir
- });
+ const iconFilePaths = readAllFilePaths(iconDir, 0, 0, ['.png', '.jpg', '.jpeg']);
+ const pictureFilePaths = readAllFilePaths(pictureDir, 0, 0, ['.png', '.jpg', '.jpeg']);
+
+ // 仅在资源为空时警告
+ if (iconFilePaths.length === 0) {
+ log.warn(`【${dirName}】普通模块无有效icon文件,跳过`);
+ continue;
+ }
+ if (pictureFilePaths.length === 0) {
+ log.warn(`【${dirName}】普通模块无有效Picture文件,跳过`);
+ continue;
+ }
+
+ const iconRecognitionObjects = [];
+ for (const filePath of iconFilePaths) {
+ const mat = file.readImageMatSync(filePath);
+ if (mat.empty()) {
+ log.error(`【${dirName}】加载图标失败:${filePath}`);
+ continue;
+ }
+ iconRecognitionObjects.push({
+ name: basename(filePath),
+ ro: RecognitionObject.TemplateMatch(mat, 0, 0, 1920, 1080),
+ iconDir
+ });
+ }
+
+ const pictureRegions = [];
+ for (const filePath of pictureFilePaths) {
+ const mat = file.readImageMatSync(filePath);
+ if (mat.empty()) {
+ log.error(`【${dirName}】加载图库图片失败:${filePath}`);
+ continue;
+ }
+ pictureRegions.push({
+ name: basename(filePath),
+ region: new ImageRegion(mat, 0, 0)
+ });
+ }
+
+ const foundRegions = [];
+ for (const picture of pictureRegions) {
+ for (const icon of iconRecognitionObjects) {
+ const foundRegion = picture.region.find(icon.ro);
+ if (foundRegion.isExist()) {
+ foundRegions.push({
+ pictureName: picture.name,
+ iconName: icon.name,
+ region: foundRegion,
+ iconDir: icon.iconDir
+ });
+ }
}
}
- }
+ if (foundRegions.length === 0) {
+ log.warn(`【${dirName}】普通模块无匹配图标,跳过`);
+ continue;
+ }
- // 保存预处理结果
- preloadedResources.push({
- dirName,
- foundRegions
- });
+ preloadedResources.push({
+ dirName,
+ fullPath,
+ foundRegions,
+ popupConfig,
+ isFirstLevel: isFirstLevel,
+ level: level
+ });
+ }
}
- log.info(`预加载完成,共处理 ${preloadedResources.length} 个目录`);
+ // log.info(`预加载完成,共${preloadedResources.length}个有效弹窗目录(第一级:${preloadedResources.filter(r => r.isFirstLevel).length}个,第二级:${preloadedResources.filter(r => !r.isFirstLevel).length}个)`);
return preloadedResources;
}
-// 新增:imageClick后台任务函数
+// ======================== 2. 后台任务函数(精简日志版)========================
async function imageClickBackgroundTask() {
log.info("imageClick后台任务已启动");
- const imageClickDelay = Math.min(99, Math.max(1, Math.floor(Number(settings.PopupClickDelay) || 5)))*1000;
- // 可以根据需要配置要处理的弹窗名称
+
+ // 配置参数
+ const taskDelay = Math.min(999, Math.max(1, Math.floor(Number(settings.PopupClickDelay) || 15)))*1000;
const specificNamesStr = settings.PopupNames || "";
const specificNames = specificNamesStr
.split(/[,,、 \s]+/)
.map(name => name.trim())
.filter(name => name !== "");
- // 调用独立预加载函数(循环前仅执行一次)
+ // 预加载资源
const preloadedResources = await preloadImageResources(specificNames);
if (preloadedResources.length === 0) {
- log.info("无可用预加载资源,任务结束");
+ log.info("无可用弹窗资源,任务结束");
return { success: false };
}
- // 循环执行,仅使用预加载资源
+ // 筛选一级弹窗
+ const firstLevelDirs = preloadedResources.filter(res => res.isFirstLevel);
+ if (firstLevelDirs.length === 0) {
+ log.warn("无第一级弹窗目录,任务终止");
+ return { success: false };
+ }
+
+ // 打印资源检测结果
+ log.info("\n==================== 现有弹窗加载结果 ====================");
+ log.info("1. 一级弹窗(共" + firstLevelDirs.length + "个):");
+ firstLevelDirs.forEach((res, idx) => log.info(` ${idx+1}. 【${res.dirName}】`));
+ const secondLevelResources = preloadedResources.filter(res => !res.isFirstLevel);
+ log.info("\n2. 二级弹窗(共" + secondLevelResources.length + "个):");
+ secondLevelResources.forEach((res, idx) => log.info(` ${idx+1}. 【${res.dirName}】`));
+ log.info("=============================================================\n");
+
+ // 核心逻辑:外循环遍历所有一级弹窗
while (!state.completed && !state.cancelRequested) {
- try {
- // 调用imageClick时传入预加载资源
- await imageClick(preloadedResources, null, specificNames, true);
- } catch (error) {
- log.info(`弹窗识别失败(继续重试):${error.message}`);
+ // log.info(`\n===== 外循环开始:遍历所有一级弹窗(共${firstLevelDirs.length}个) =====`);
+
+ // 遍历所有一级弹窗
+ for (const currentFirstLevel of firstLevelDirs) {
+ // 检查当前一级弹窗是否被触发
+ const levelResult = await imageClick([currentFirstLevel], null, [currentFirstLevel.dirName], true);
+
+ if (levelResult.success) {
+ log.info(`【${currentFirstLevel.dirName}】触发成功,进入内部流程...`);
+ const levelStack = [currentFirstLevel];
+
+ // 内循环处理内部流程
+ while (levelStack.length > 0 && !state.completed && !state.cancelRequested) {
+ const currentResource = levelStack[levelStack.length - 1];
+ const innerResult = await imageClick([currentResource], null, [currentResource.dirName], true);
+
+ if (innerResult.success) {
+ const nextPath = normalizePath(currentResource.popupConfig.nextLevelOnSuccess);
+ if (nextPath && nextPath.trim()) {
+ const nextResource = preloadedResources.find(res => res.fullPath === nextPath);
+ if (nextResource) {
+ levelStack.push(nextResource);
+ } else {
+ // log.warn(`内循环:下一级(${nextPath})不存在,回退`);
+ levelStack.pop();
+ }
+ } else {
+ levelStack.pop();
+ }
+ } else {
+ const nextPath = normalizePath(currentResource.popupConfig.nextLevelOnFailure);
+ if (nextPath && nextPath.trim()) {
+ const nextResource = preloadedResources.find(res => res.fullPath === nextPath);
+ if (nextResource) {
+ levelStack.push(nextResource);
+ } else {
+ // log.warn(`内循环:下一级(${nextPath})不存在,回退`);
+ levelStack.pop();
+ }
+ } else {
+ levelStack.pop();
+ }
+ }
+
+ await sleep(100);
+ }
+
+ log.info(`【${currentFirstLevel.dirName}】内部流程处理完毕`);
+ }
}
- // 短暂等待后再次执行
- await sleep(imageClickDelay);
+
+ // log.info(`===== 外循环结束:等待${taskDelay/1000}秒后开始下一次循环 =====`);
+ await sleep(taskDelay);
}
- log.info("imageClick后台任务已结束");
+ log.info("imageClick后台任务结束");
return { success: true };
}
-// 优化:使用预加载资源,保留所有原执行逻辑
+// ======================== 3. 识别与操作函数(精简日志版)========================
async function imageClick(preloadedResources, ra = null, specificNames = null, useNewScreenshot = false) {
- // 保留原参数格式处理(兼容历史调用)
if (typeof specificNames === 'string') {
specificNames = [specificNames];
}
const isAll = !specificNames || specificNames.length === 0;
+ let isAnySuccess = false;
- // 遍历预处理好的资源(原targetDirs循环逻辑)
for (const resource of preloadedResources) {
- const { dirName, foundRegions } = resource;
+ const { dirName, foundRegions, popupConfig } = resource;
+ const { xOffset, yOffset } = popupConfig;
+ let hasAnyIconDetected = false; // 标记是否有图标被识别
+
for (const foundRegion of foundRegions) {
- // 保留原识别对象创建逻辑(使用预处理的路径)
const tolerance = 1;
- const iconMat = file.readImageMatSync(`${foundRegion.iconDir}/${foundRegion.iconName}`);
+ const iconMat = file.readImageMatSync(`${normalizePath(foundRegion.iconDir)}/${foundRegion.iconName}`);
+
+ const { detectRegion } = popupConfig;
+ const defaultX = foundRegion.region.x - tolerance;
+ const defaultY = foundRegion.region.y - tolerance;
+ const defaultWidth = foundRegion.region.width + 2 * tolerance;
+ const defaultHeight = foundRegion.region.height + 2 * tolerance;
const recognitionObject = RecognitionObject.TemplateMatch(
iconMat,
- foundRegion.region.x - tolerance,
- foundRegion.region.y - tolerance,
- foundRegion.region.width + 2 * tolerance,
- foundRegion.region.height + 2 * tolerance
+ detectRegion?.x ?? defaultX,
+ detectRegion?.y ?? defaultY,
+ detectRegion?.width ?? defaultWidth,
+ detectRegion?.height ?? defaultHeight
);
recognitionObject.threshold = 0.85;
- // 保留原识别逻辑
const result = await recognizeImage(
recognitionObject,
ra,
- 1000, // timeout
- 500, // interval
+ 1000,
+ 500,
useNewScreenshot,
- dirName // iconType
+ dirName
);
- // 保留原点击逻辑
if (result.isDetected && result.x !== 0 && result.y !== 0) {
- const x = Math.round(result.x + result.width / 2);
- const y = Math.round(result.y + result.height / 2);
- log.info(`即将点击【${dirName}】类型下的图标:${foundRegion.iconName},位置: (${x}, ${y})`);
- await click(x, y);
- log.info(`点击【${dirName}】类型下的${foundRegion.iconName}成功`);
- await sleep(10);
- return { success: true };
- } else {
- // log.info(`未发现弹窗【${dirName}】的图标:${foundRegion.iconName}`);
+ hasAnyIconDetected = true;
+ isAnySuccess = true;
+ const centerX = Math.round(result.x + result.width / 2);
+ const centerY = Math.round(result.y + result.height / 2);
+ const actualX = centerX + xOffset;
+ const actualY = centerY + yOffset;
+ log.info(`识别到【${dirName}】弹窗,偏移后位置(${actualX}, ${actualY})`);
+
+ if (!popupConfig.isSpecial) {
+ // log.info(`点击【${dirName}】弹窗:(${actualX}, ${actualY})`);
+ // 新增:普通点击加循环(默认1次,0间隔,与原逻辑一致)
+ const clickCount = popupConfig.loopCount;
+ const clickDelay = popupConfig.loopDelay;
+ for (let i = 0; i < clickCount; i++) {
+ await click(actualX, actualY); // 保留原始点击逻辑
+ if (i < clickCount - 1) await sleep(clickDelay); // 非最后一次加间隔
+ }
+ } else {
+ switch (popupConfig.operationType) {
+ case "key_press": {
+ const targetKey = popupConfig.keyCode || "VK_SPACE";
+ // 新增:key_press用循环(默认3次,1000ms间隔,与原硬编码逻辑一致)
+ const pressCount = popupConfig.loopCount || 3;
+ const pressDelay = popupConfig.loopDelay || 1000;
+ for (let i = 0; i < pressCount; i++) {
+ keyPress(targetKey); // 保留原始按键逻辑
+ if (i < pressCount - 1) await sleep(pressDelay); // 非最后一次加间隔
+ }
+ log.info(`【${dirName}】弹窗触发按键【${targetKey}】,共${pressCount}次,间隔${pressDelay}ms`);
+ break;
+ }
+ case "ocr_click": {
+ isAnySuccess = false;
+ const { targetTexts, xRange, yRange, timeout = 2000 } = popupConfig.ocrConfig || {};
+ if (!targetTexts || !xRange || !yRange) {
+ log.error(`【${dirName}】弹窗OCR配置不全,跳过`);
+ break;
+ }
+ const ocrResults = await performOcr(targetTexts, xRange, yRange, timeout, ra);
+ if (ocrResults.length > 0) {
+ const ocrActualX = Math.round(ocrResults[0].x + ocrResults[0].width/2) + xOffset;
+ const ocrActualY = Math.round(ocrResults[0].y + ocrResults[0].height/2) + yOffset;
+ // 新增:OCR点击加循环(默认1次,0间隔,与原逻辑一致)
+ const ocrCount = popupConfig.loopCount;
+ const ocrDelay = popupConfig.loopDelay;
+ for (let i = 0; i < ocrCount; i++) {
+ await click(ocrActualX, ocrActualY); // 保留原始OCR点击逻辑
+ if (i < ocrCount - 1) await sleep(ocrDelay); // 非最后一次加间隔
+ }
+ log.info(`【${dirName}】弹窗OCR点击“${ocrResults[0].text}”:(${ocrActualX}, ${ocrActualY}),共${ocrCount}次,间隔${ocrDelay}ms`);
+ isAnySuccess = true;
+ } else {
+ log.warn(`【${dirName}】弹窗OCR未识别到文本`);
+ }
+ break;
+ }
+ case "key_mouse_script": {
+ try {
+ const scriptPath = normalizePath(popupConfig.scriptPath || "");
+ if (!scriptPath) {
+ log.error(`【${dirName}】弹窗未配置键鼠脚本路径,跳过执行`);
+ isAnySuccess = false;
+ break;
+ }
+ if (!fileExists(scriptPath)) {
+ log.error(`【${dirName}】弹窗键鼠脚本不存在:${scriptPath}`);
+ isAnySuccess = false;
+ break;
+ }
+ // 新增:键鼠脚本加循环(默认1次,0间隔,与原逻辑一致)
+ const scriptCount = popupConfig.loopCount;
+ const scriptDelay = popupConfig.loopDelay;
+ for (let i = 0; i < scriptCount; i++) {
+ await keyMouseScript.runFile(scriptPath); // 保留原始脚本执行逻辑
+ if (i < scriptCount - 1) await sleep(scriptDelay); // 非最后一次加间隔
+ }
+ log.info(`【${dirName}】弹窗键鼠脚本执行完成,共${scriptCount}次,间隔${scriptDelay}ms`);
+ isAnySuccess = true;
+ } catch (error) {
+ log.error(`【${dirName}】弹窗键鼠脚本执行失败:${error.message}`);
+ isAnySuccess = false;
+ }
+ break;
+ }
+ default:
+ log.error(`【${dirName}】弹窗未知操作类型:${popupConfig.operationType},默认执行点击`);
+ // 新增:默认操作加循环(默认1次,0间隔,与原逻辑一致)
+ const defaultCount = popupConfig.loopCount;
+ const defaultDelay = popupConfig.loopDelay;
+ for (let i = 0; i < defaultCount; i++) {
+ await click(actualX, actualY); // 保留原始默认点击逻辑
+ if (i < defaultCount - 1) await sleep(defaultDelay); // 非最后一次加间隔
+ }
+ isAnySuccess = true;
+ }
+ }
}
}
+
+ // 仅在该弹窗无任何图标识别时输出警告
+ if (!hasAnyIconDetected && !isAnySuccess) {
+ // log.warn(`【${dirName}】弹窗未发现任何有效图标`);
+ }
+ await sleep(10);
}
- // 所有目标处理完毕仍未成功(保留原返回逻辑)
- return { success: false };
+ return { success: isAnySuccess, message: isAnySuccess ? "弹窗识别操作成功" : "未识别到弹窗" };
}
diff --git a/repo/js/背包材料统计/main.js b/repo/js/背包材料统计/main.js
index a96f2eb4d..c2b189502 100644
--- a/repo/js/背包材料统计/main.js
+++ b/repo/js/背包材料统计/main.js
@@ -111,7 +111,6 @@ function parseMonsterMaterials() {
}
materialToMonsters[mat].add(monsterName);
});
- log.debug(`${CONSTANTS.LOG_MODULES.MONSTER}解析怪物材料:${monsterName} -> [${materials.join(', ')}]`);
}
});
} catch (error) {
@@ -155,7 +154,11 @@ function getSelectedMaterialCategories() {
return acc;
}, {});
- const finalSettings = { ...initialSettings, ...settings };
+ const finalSettings = Object.keys(initialSettings).reduce((acc, key) => {
+ // 若settings中有该键则使用其值,否则用默认的false(确保只处理material_mapping中的键)
+ acc[key] = settings.hasOwnProperty(key) ? settings[key] : initialSettings[key];
+ return acc;
+ }, {});
return Object.keys(finalSettings)
.filter(key => key !== "unselected")
@@ -294,6 +297,7 @@ function readMaterialCD() {
const materialCDCategories = {};
for (const filePath of materialFilePaths) {
+ if (state.cancelRequested) break;
const content = file.readTextSync(filePath);
if (!content) {
log.error(`${CONSTANTS.LOG_MODULES.CD}加载文件失败:${filePath}`);
@@ -1156,7 +1160,6 @@ function classifyNormalPathFiles(pathingDir, targetResourceNames, lowCountMateri
if (pathEntries.length > 0) {
log.info(`${CONSTANTS.LOG_MODULES.PATH}\n===== 匹配到的材料路径列表 =====`);
pathEntries.forEach((entry, index) => {
- log.info(`${index + 1}. 材料:${entry.resourceName},路径:${entry.path}`);
});
log.info(`=================================\n`);
} else {
@@ -1355,6 +1358,11 @@ ${Object.entries(totalDifferences).map(([name, diff]) => ` ${name}: +${diff}个
=========================================\n\n`;
writeContentToFile(summaryPath, content);
log.info(`${CONSTANTS.LOG_MODULES.RECORD}最终汇总已记录至 ${summaryPath}`);
+ // ==============================================
+ // 新增:汇总后强制触发结束指令,确保程序终止
+ // ==============================================
+ state.completed = true; // 标记任务完全完成
+ state.cancelRequested = true; // 终止所有后台任务(如图像点击、OCR)
}
// ==============================================
@@ -1387,11 +1395,15 @@ ${Object.entries(totalDifferences).map(([name, diff]) => ` ${name}: +${diff}个
}
// 关键补充:等待超量名单生成(由filterLowCountMaterials更新)
let waitTimes = 0;
- while (excessMaterialNames.length === 0 && waitTimes < 300) {
+ while (excessMaterialNames.length === 0 && !state.cancelRequested && waitTimes < 100) {
await sleep(1000); // 每1秒查一次
waitTimes++;
}
-
+ // 若收到终止信号,直接退出OCR任务(不再执行后续逻辑)
+ if (state.cancelRequested) {
+ log.info(`${CONSTANTS.LOG_MODULES.MAIN}OCR任务收到终止信号,已退出`);
+ return;
+ }
// 现在过滤才有效(确保excessMaterialNames已生成)
allTargetTexts = allTargetTexts.filter(name => !excessMaterialNames.includes(name));
log.info(`OCR最终目标文本(已过滤超量):${allTargetTexts.join('、')}`);
diff --git a/repo/js/背包材料统计/manifest.json b/repo/js/背包材料统计/manifest.json
index eeca672ea..ece08cf61 100644
--- a/repo/js/背包材料统计/manifest.json
+++ b/repo/js/背包材料统计/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "背包统计采集系统",
- "version": "2.52",
+ "version": "2.53",
"bgi_version": "0.44.8",
"description": "可统计背包养成道具、部分食物、素材的数量;根据设定数量、根据材料刷新CD执行挖矿、采集、刷怪等的路径。优势:\n+ 1. 自动判断材料CD,不需要管材料CD有没有好;\n+ 2. 可以随意添加路径,能自动排除低效、无效路径;\n+ 3. 有独立名单识别,不会交互路边的npc或是神像;可自定义识别名单,具体方法看【问题解答】增减识别名单\n+ 4. 有实时的弹窗模块,提供了常见的几种:路边信件、过期物品、月卡、调查;\n+ 5. 可识别爆满的路径材料,自动屏蔽;更多详细内容查看readme.md",
"saved_files": [
diff --git a/repo/js/背包材料统计/settings.json b/repo/js/背包材料统计/settings.json
index 10b129e01..a1dca168c 100644
--- a/repo/js/背包材料统计/settings.json
+++ b/repo/js/背包材料统计/settings.json
@@ -102,12 +102,27 @@
{
"name": "PopupClickDelay",
"type": "input-text",
- "label": "如 过期物品,信件,自定义文件夹名。注意分隔符和文件夹格式\n----------------------------------\n弹窗循环间隔(默认:5 秒)"
+ "label": "如 过期物品,信件,自定义文件夹名。注意文件夹结构\n----------------------------------\n弹窗循环间隔(默认:15 秒)"
},
{
"name": "CDCategories",
"type": "input-text",
- "label": "----------------------------------\n\n采用的CD分类(默认:全部)"
+ "label": "====================\n\n采用的CD分类(默认:全部) 举例:采集,怪物,木材"
+ },
+ {
+ "name": "PickCategories",
+ "type": "input-text",
+ "label": "根据CD分类来加载路径文件,具体看materialsCD目录\n====================\n\n采用的识别名单(默认:全部) 举例:交互,采集,宝箱"
+ },
+ {
+ "name": "ExceedCount",
+ "type": "input-text",
+ "label": "根据拾取分类来加载OCR名单,具体看targetText目录\n----------------------------------\n\n超量阈值(默认:5000)超量的路径材料将不拾取"
+ },
+ {
+ "name": "PageScrollDistance",
+ "type": "input-text",
+ "label": "====================\n拖动距离:(默认711像素点)"
},
{
"name": "HoldX",
@@ -118,10 +133,5 @@
"name": "HoldY",
"type": "input-text",
"label": "------------------------\n翻页拖动点Y坐标:0~1080(默认750)"
- },
- {
- "name": "PageScrollDistance",
- "type": "input-text",
- "label": "------------------------\n拖动距离:(默认711像素点)"
}
-]
\ No newline at end of file
+]