js:采集cd管理 AAA狗粮批发 (#2894)

This commit is contained in:
mno
2026-02-18 22:33:37 +08:00
committed by GitHub
parent 3b377e63c3
commit eb3e6f879d
7 changed files with 83 additions and 47 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -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);

View File

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

View File

@@ -53,7 +53,7 @@
- blacklists/ 文件夹保存各个账户名的黑名单物品信息可以在这里手动编辑注意需要符合json格式
- record/ 文件夹保存各个账户名的运行记录与cd信息
### 、**⚙️ 其他说明**
### 、**⚙️ 其他说明**
1. 伪造日志(不影响游戏)
- 生成的日志可以被日志分析识别,方便查看路线运行情况。
@@ -79,4 +79,18 @@
- 妙妙小工具
- 性能测试:测测你的电脑性能
- 食材加工极速版与采集cd管理中相同的食材加工
- 更多妙妙小工具可以加群获取
- 更多妙妙小工具可以加群获取
### 五、**⚙️ 更新日志**
<details>
<summary>📋 点击查看历史更新</summary>
### 2026/2/18
1. 对食材加工过程中可能出现的道具数量超过上限进行处理
### 2026/2/17
1. 增加通知优先采集阶段和路径组切换
2. 优化部分日志和展示的自定义配置
3. 更新日志回归
</details>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -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<fileName, 原对象> 只改 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);

View File

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