diff --git a/repo/js/AAA-Artifacts-Bulk-Supply/assets/targetItems/保留/禽肉.png b/repo/js/AAA-Artifacts-Bulk-Supply/assets/targetItems/保留/禽肉.png
new file mode 100644
index 000000000..3be94c9ad
Binary files /dev/null and b/repo/js/AAA-Artifacts-Bulk-Supply/assets/targetItems/保留/禽肉.png differ
diff --git a/repo/js/AAA-Artifacts-Bulk-Supply/main.js b/repo/js/AAA-Artifacts-Bulk-Supply/main.js
index 30f686160..e913b0d3e 100644
--- a/repo/js/AAA-Artifacts-Bulk-Supply/main.js
+++ b/repo/js/AAA-Artifacts-Bulk-Supply/main.js
@@ -665,55 +665,43 @@ async function switchPartyIfNeeded(partyName) {
}
}
-// 定义 readFolder 函数
-async function readFolder(folderPath, onlyJson) {
- // 新增一个堆栈,初始时包含 folderPath
- const folderStack = [folderPath];
- // 新增一个数组,用于存储文件信息对象
+/**
+ * 递归读取目录下所有文件
+ * @param {string} folderPath 起始目录
+ * @param {string} [ext=''] 需要的文件后缀,空字符串表示不限制;例如 'json' 或 '.json' 均可
+ * @returns {Array<{fullPath:string, fileName:string, folderPathArray:string[]}>}
+ */
+async function readFolder(folderPath, ext = '') {
+ // 统一后缀格式:确保前面有一个点,且全小写
+ const targetExt = ext ? (ext.startsWith('.') ? ext : `.${ext}`).toLowerCase() : '';
+
+ const folderStack = [folderPath];
const files = [];
- // 当堆栈不为空时,继续处理
while (folderStack.length > 0) {
- // 从堆栈中弹出一个路径
const currentPath = folderStack.pop();
-
- // 读取当前路径下的所有文件和子文件夹路径
- const filesInSubFolder = file.ReadPathSync(currentPath);
-
- // 临时数组,用于存储子文件夹路径
+ const filesInSubFolder = file.ReadPathSync(currentPath); // 同步读取当前目录
const subFolders = [];
+
for (const filePath of filesInSubFolder) {
if (file.IsFolder(filePath)) {
- // 如果是文件夹,先存储到临时数组中
- subFolders.push(filePath);
+ subFolders.push(filePath); // 子目录稍后处理
} else {
- // 如果是文件,根据 onlyJson 判断是否存储
- if (onlyJson) {
- if (filePath.endsWith(".json")) {
- const fileName = filePath.split('\\').pop(); // 提取文件名
- const folderPathArray = filePath.split('\\').slice(0, -1); // 提取文件夹路径数组
- files.push({
- fullPath: filePath,
- fileName: fileName,
- folderPathArray: folderPathArray
- });
- //log.info(`找到 JSON 文件:${filePath}`);
- }
- } else {
- const fileName = filePath.split('\\').pop(); // 提取文件名
- const folderPathArray = filePath.split('\\').slice(0, -1); // 提取文件夹路径数组
- files.push({
- fullPath: filePath,
- fileName: fileName,
- folderPathArray: folderPathArray
- });
- //log.info(`找到文件:${filePath}`);
+ // 后缀过滤
+ if (targetExt) {
+ const fileExt = filePath.toLowerCase().slice(filePath.lastIndexOf('.'));
+ if (fileExt !== targetExt) continue;
}
+
+ const fileName = filePath.split('\\').pop();
+ const folderPathArray = filePath.split('\\').slice(0, -1);
+ files.push({ fullPath: filePath, fileName, folderPathArray });
}
}
- // 将临时数组中的子文件夹路径按原顺序压入堆栈
- folderStack.push(...subFolders.reverse()); // 反转子文件夹路径
+
+ // 保持同层顺序,reverse 后仍按原顺序入栈
+ folderStack.push(...subFolders.reverse());
}
return files;
@@ -884,7 +872,7 @@ async function runPaths(folderFilePath, PartyName, doStop, furinaRequirement = "
if (folderFilePath === "") {
return;
}
- let Paths = await readFolder(folderFilePath, true);
+ let Paths = await readFolder(folderFilePath, "json");
let furinaChecked = false;
for (let i = 0; i < Paths.length; i++) {
let skiprecord = false;
@@ -1183,7 +1171,7 @@ async function runPath(fullPath, targetItemPath = null) {
//加载拾取物图片
async function loadTargetItems() {
const targetItemPath = 'assets/targetItems'; // 固定目录
- const items = await readFolder(targetItemPath, false);
+ const items = await readFolder(targetItemPath, "png");
// 统一预加载模板
for (const it of items) {
it.template = file.ReadImageMatSync(it.fullPath);
diff --git a/repo/js/AAA-Artifacts-Bulk-Supply/manifest.json b/repo/js/AAA-Artifacts-Bulk-Supply/manifest.json
index c99239c08..ca3ab20ea 100644
--- a/repo/js/AAA-Artifacts-Bulk-Supply/manifest.json
+++ b/repo/js/AAA-Artifacts-Bulk-Supply/manifest.json
@@ -1,13 +1,17 @@
{
"manifest_version": 1,
"name": "AAA狗粮批发",
- "version": "2.1.2",
+ "version": "2.1.3",
"tags": [
"狗粮"
],
"description": "直接利用“富98个上限点”1号/2号路线交替运行(路线不重复),来给收尾和额外路线卡时间,花最少的时间拿最多的狗粮",
"saved_files": [
- "records/*.txt"
+ "records/*.txt",
+ "assets/targetItems/保留/*.png",
+ "assets/targetItems/保留/*/*.png",
+ "assets/targetItems/保留/*/*/*.png",
+ "assets/targetItems/保留/*/*/*/*.png"
],
"authors": [
{
diff --git a/repo/js/采集cd管理/README.md b/repo/js/采集cd管理/README.md
index 7772c75c6..05095e0d1 100644
--- a/repo/js/采集cd管理/README.md
+++ b/repo/js/采集cd管理/README.md
@@ -53,7 +53,7 @@
- blacklists/ 文件夹:保存各个账户名的黑名单物品信息,可以在这里手动编辑,注意需要符合json格式
- record/ 文件夹:保存各个账户名的运行记录与cd信息
-### 三、**⚙️ 其他说明**
+### 四、**⚙️ 其他说明**
1. 伪造日志(不影响游戏)
- 生成的日志可以被日志分析识别,方便查看路线运行情况。
@@ -79,4 +79,18 @@
- 妙妙小工具
- 性能测试:测测你的电脑性能
- 食材加工极速版:与采集cd管理中相同的食材加工
- - 更多妙妙小工具可以加群获取
\ No newline at end of file
+ - 更多妙妙小工具可以加群获取
+
+### 五、**⚙️ 更新日志**
+
+📋 点击查看历史更新
+
+### 2026/2/18
+1. 对食材加工过程中可能出现的道具数量超过上限进行处理
+
+### 2026/2/17
+1. 增加通知优先采集阶段和路径组切换
+2. 优化部分日志和展示的自定义配置
+3. 更新日志回归
+
+
diff --git a/repo/js/采集cd管理/assets/RecognitionObject/道具数量超过上限.png b/repo/js/采集cd管理/assets/RecognitionObject/道具数量超过上限.png
new file mode 100644
index 000000000..629faf964
Binary files /dev/null and b/repo/js/采集cd管理/assets/RecognitionObject/道具数量超过上限.png differ
diff --git a/repo/js/采集cd管理/main.js b/repo/js/采集cd管理/main.js
index 456f698b4..c017993f3 100644
--- a/repo/js/采集cd管理/main.js
+++ b/repo/js/采集cd管理/main.js
@@ -181,7 +181,7 @@ let checkInterval = +settings.checkInterval || 50;
{
"name": "priorityItemsPartyName",
"type": "input-text",
- "label": "优先采集材料使用的配队名称"
+ "label": "优先采集材料使用的备用配队名称\n在指定路线不存在对应文件夹指定的配队时使用"
},
{
"name": "disableJsons",
@@ -512,6 +512,7 @@ let checkInterval = +settings.checkInterval || 50;
if (priorityList.length === 0) {
log.info("今日优先材料已达标,跳过优先采集阶段");
+ notification.send("今日优先材料已达标,跳过优先采集阶段");
}
/* ================================= */
@@ -761,8 +762,9 @@ let checkInterval = +settings.checkInterval || 50;
!runOnce.includes(f.fileName); // 本轮没跑过
})
.sort((a, b) => b._priorityEff - a._priorityEff);
- if (candidateRoutes.length === 0) {
- log.info('已无可用优先路线(可能全部在CD或已达标),退出优先采集阶段');
+ if (candidateRoutes.length === 0 && priorityList.length > 0) {
+ log.info('已无可用优先路线(可能全部在CD),退出优先采集阶段');
+ notification.send('已无可用优先路线(可能全部在CD),退出优先采集阶段');
break;
}
const bestRoute = candidateRoutes[0];
@@ -966,7 +968,12 @@ let checkInterval = +settings.checkInterval || 50;
await appendDailyPickup(state.runPickupLog);
state.runPickupLog = [];
}
+ if (priorityList.length <= 0) {
+ log.info('每日优先材料已达标,退出优先采集阶段');
+ notification.send('每日优先材料已达标,退出优先采集阶段');
+ }
}
+ await sleep(1000);
}
let loopattempts = 0;
// ==================== 路径组循环 ====================
@@ -981,6 +988,9 @@ let checkInterval = +settings.checkInterval || 50;
const folder = folderNames[i - 1] || `路径组${i}`;
const targetFolder = `pathing/${folder} `;
+ log.info(`开始执行路径组${i} 文件夹:${folder}`);
+ notification.send(`开始执行路径组${i} 文件夹:${folder}`);
+
/* 运行期同样用 Map 只改 cdTime */
const rawRecord = await file.readText(recordFilePath);
let recordArray = JSON.parse(rawRecord);
@@ -1956,6 +1966,16 @@ async function ingredientProcessing() {
await sleep(200);
/* 正常完成:仅领取,不移除 */
if (await clickPNG("全部领取", 3)) {
+ let dowait = false;
+ await sleep(4 * checkInterval);
+ while (await findPNG("道具数量超过上限")) {
+ await sleep(checkInterval * 4);
+ log.info("识别到道具数量超过上限,等待消失");
+ dowait = true;
+ }
+ if (dowait) {
+ await sleep(10 * checkInterval)
+ }
await clickPNG("点击空白区域继续");
await findPNG("食材加工2");
await sleep(100);
@@ -1965,6 +1985,16 @@ async function ingredientProcessing() {
/* ===== 2. 两轮扫描 ===== */
// 进入界面先领取一次
if (await clickPNG("全部领取", 3)) {
+ let dowait = false;
+ await sleep(4 * checkInterval);
+ while (await findPNG("道具数量超过上限")) {
+ await sleep(checkInterval * 4);
+ log.info("识别到道具数量超过上限,等待消失");
+ dowait = true;
+ }
+ if (dowait) {
+ await sleep(10 * checkInterval)
+ }
await clickPNG("点击空白区域继续");
await findPNG("食材加工2");
await sleep(100);
diff --git a/repo/js/采集cd管理/manifest.json b/repo/js/采集cd管理/manifest.json
index 65eaefa6e..758015709 100644
--- a/repo/js/采集cd管理/manifest.json
+++ b/repo/js/采集cd管理/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "采集cd管理",
- "version": "2.10.1",
+ "version": "2.10.4",
"bgi_version": "0.44.8",
"description": "仅面对会操作文件和读readme的用户,基于文件夹操作自动管理采集路线的cd,会按照路径组的顺序依次运行,直到指定的时间,并会按照给定的cd类型,自动跳过未刷新的路线",
"saved_files": [