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": [