From a964c164c9d9e08c9b5d88ae0f52d3059e15530b Mon Sep 17 00:00:00 2001 From: mno <718135749@qq.com> Date: Sun, 28 Dec 2025 15:23:52 +0800 Subject: [PATCH] =?UTF-8?q?js=EF=BC=9A=E9=87=87=E9=9B=86cd=E7=AE=A1?= =?UTF-8?q?=E7=90=86=20(#2576)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/RecognitionObject/选择加工数量.png | Bin 0 -> 6386 bytes repo/js/采集cd管理/main.js | 245 +++++++++++------- repo/js/采集cd管理/manifest.json | 2 +- 3 files changed, 154 insertions(+), 93 deletions(-) create mode 100644 repo/js/采集cd管理/assets/RecognitionObject/选择加工数量.png diff --git a/repo/js/采集cd管理/assets/RecognitionObject/选择加工数量.png b/repo/js/采集cd管理/assets/RecognitionObject/选择加工数量.png new file mode 100644 index 0000000000000000000000000000000000000000..02c3de00ea833e0fd199a04a55ed284d3525529c GIT binary patch literal 6386 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 literal 0 HcmV?d00001 diff --git a/repo/js/采集cd管理/main.js b/repo/js/采集cd管理/main.js index aa899f253..2ec1b21e5 100644 --- a/repo/js/采集cd管理/main.js +++ b/repo/js/采集cd管理/main.js @@ -1762,12 +1762,13 @@ async function isTimeRestricted(timeRule, threshold = 5) { return false; } + /** -* 食材加工主函数,用于自动前往指定地点进行食材或料理的加工制作 -* -* 该函数会根据 Foods 和 foodCount 数组中的食材名称和数量,依次查找并制作对应的料理/食材 -* 支持两种类型:普通料理(需滚动查找)和调味品类食材(直接在“食材加工”界面查找) -* +* 食材加工主函数,用于自动前往指定地点进行食材的加工 +* +* 该函数会根据 Foods 和 foodCount 数组中的食材名称和数量,依次查找并制作对应的料食材 +* 支持调味品类食材(直接在“食材加工”界面查找) +* * @returns {Promise} 无返回值,执行完所有加工流程后退出 */ async function ingredientProcessing() { @@ -1811,104 +1812,164 @@ async function ingredientProcessing() { } } await clickPNG("食材加工"); - for (let i = 0; i < Foods.length; i++) { - log.info(`开始加工${Foods[i]}`); - const targetFoods = new Set([ - "面粉", "兽肉", "鱼肉", "神秘的肉", "黑麦粉", "奶油", "熏禽肉", - "黄油", "火腿", "糖", "香辛料", "酸奶油", "蟹黄", "果酱", - "奶酪", "培根", "香肠" - ]); - if (targetFoods.has(Foods[i])) { + + // 固定列表只定义一次 + const targetFoods = new Set([ + "面粉", "兽肉", "鱼肉", "神秘的肉", "黑麦粉", "奶油", "熏禽肉", + "黄油", "火腿", "糖", "香辛料", "酸奶油", "蟹黄", "果酱", + "奶酪", "培根", "香肠" + ]); + + /* ===== 1. 公共加工流程 ===== */ + async function doCraft(i) { + await clickPNG("制作"); + await sleep(300); + + /* ---------- 1. 队列已满 ---------- */ + if (await findPNG("队列已满", 1)) { + log.warn(`检测到${Foods[i]}队列已满,等待图标消失`); + while (await findPNG("队列已满", 1)) { + log.warn(`检测到${Foods[i]}队列已满,等待图标消失`); + await sleep(300); + } if (await clickPNG("全部领取", 3)) { await clickPNG("点击空白区域继续"); await findPNG("食材加工2"); await sleep(100); } - let res1 = await clickPNG(Foods[i] + "1", 5); + return false; + } - if (res1) { - log.info(`${Foods[i]}已找到`); - } else { - try { - const rg = captureGameRegion(); - const foodItems = []; - try { - for (const flag of ['已加工0个', '已加工1个']) { - const mat = file.ReadImageMatSync(`assets/RecognitionObject/${flag}.png`); - const res = rg.findMulti(RecognitionObject.TemplateMatch(mat)); - for (let i = 0; i < res.count; ++i) { - foodItems.push({ x: res[i].x, y: res[i].y }); - } - mat.dispose(); - } - } finally { rg.dispose(); } - - // 依次筛选这些项目 - for (const item of foodItems) { - // 点击该项目 - click(item.x, item.y); - await sleep(200); - click(item.x, item.y); - if (await findPNG(Foods[i] + "2", 5)) { - log.info(`${Foods[i]}已找到`); - res1 = true; - break; - } - } - if (!res1) { - log.error(`未找到目标食材: ${Foods[i]}`); - continue; - } - } catch (error) { - log.error(`食材加工识别出错:${error.message}`); - } - } - - await clickPNG("制作"); - await sleep(300); - if (await findPNG("队列已满", 1)) { - log.warn(`检测到${Foods[i]}队列已满,等待图标消失`); - while (true) { - if (!await findPNG("队列已满", 1)) { - break; - } else { - log.warn(`检测到${Foods[i]}已满,等待图标消失`); - } - await sleep(300); - } - continue; - } - if (await findPNG("材料不足", 1)) { + /* ---------- 2. 材料不足 ---------- */ + if (await findPNG("材料不足", 1)) { + log.warn(`检测到${Foods[i]}材料不足,等待图标消失`); + while (await findPNG("材料不足", 1)) { log.warn(`检测到${Foods[i]}材料不足,等待图标消失`); - while (true) { - if (!await findPNG("材料不足", 1)) { - break; - } else { - log.warn(`检测到${Foods[i]}材料不足,等待图标消失`); - } - await sleep(300); - } - continue; - } - await sleep(800); - click(960, 460); - await sleep(800); - inputText(foodCount[i]); - log.info(`尝试制作${Foods[i]} ${foodCount[i]}个`); - log.warn("由于受到队列和背包食材数量限制,实际制作数量与上述数量可能不一致!"); - await clickPNG("确认加工"); - await sleep(500); - while (true) { - if (!await findPNG("已不能持有更多", 1)) { - break; - } else { - log.warn(`检测到${Foods[i]}已满,等待图标消失`); - } await sleep(300); } - await sleep(200); + if (await clickPNG("全部领取", 3)) { + await clickPNG("点击空白区域继续"); + await findPNG("食材加工2"); + await sleep(100); + } + Foods.splice(i, 1); + foodCount.splice(i, 1); + return false; + } + + /* ---------- 3. 正常加工流程 ---------- */ + await findPNG("选择加工数量"); + click(960, 460); + await sleep(800); + inputText(foodCount[i]); + log.info(`尝试制作${Foods[i]} ${foodCount[i]}个`); + await clickPNG("确认加工"); + await sleep(500); + + /* ---------- 4. 已不能持有更多 ---------- */ + if (await findPNG("已不能持有更多", 1)) { + log.warn(`检测到${Foods[i]}已满,等待图标消失`); + while (await findPNG("已不能持有更多", 1)) { + log.warn(`检测到${Foods[i]}已满,等待图标消失`); + await sleep(300); + } + if (await clickPNG("全部领取", 3)) { + await clickPNG("点击空白区域继续"); + await findPNG("食材加工2"); + await sleep(100); + } + Foods.splice(i, 1); + foodCount.splice(i, 1); + return false; + } + + await sleep(200); + /* 正常完成:仅领取,不移除 */ + if (await clickPNG("全部领取", 3)) { + await clickPNG("点击空白区域继续"); + await findPNG("食材加工2"); + await sleep(100); } } + + /* ===== 2. 两轮扫描 ===== */ + const done = new Array(Foods.length).fill(false); + + // 进入界面先领取一次 + if (await clickPNG("全部领取", 3)) { + await clickPNG("点击空白区域继续"); + await findPNG("食材加工2"); + await sleep(100); + } + + /* ---------- 第一轮:直接找 Foods[i]+"1" ---------- */ + for (let i = 0; i < Foods.length; i++) { + if (!targetFoods.has(Foods[i])) continue; + if (await clickPNG(Foods[i] + "1", 5)) { + log.info(`${Foods[i]}已找到`); + await doCraft(i); + done[i] = true; + } + } + + /* ---------- 第二轮:先点 item,再轮询 5 次识别 ---------- */ + const rg = captureGameRegion(); + const foodItems = []; + try { + for (const flag of ['已加工0个', '已加工1个']) { + const mat = file.ReadImageMatSync(`assets/RecognitionObject/${flag}.png`); + const res = rg.findMulti(RecognitionObject.TemplateMatch(mat)); + for (let k = 0; k < res.count; ++k) { + foodItems.push({ x: res[k].x, y: res[k].y }); + } + mat.dispose(); + } + } finally { rg.dispose(); } + + for (const item of foodItems) { + click(item.x, item.y); await sleep(200); + click(item.x, item.y); await sleep(200); + + const foodROs = []; + for (let i = 0; i < Foods.length; i++) { + if (!targetFoods.has(Foods[i])) continue; // 只处理目标食材 + const ro = RecognitionObject.TemplateMatch( + file.ReadImageMatSync(`assets/RecognitionObject/${Foods[i]}2.png`) + ); + ro.Threshold = 0.95; + ro.InitTemplate(); + foodROs.push({ idx: i, name: Foods[i], ro }); // 记住原数组下标 + } + + for (let round = 0; round < 5; round++) { + const rg = captureGameRegion(); + try { + let hit = false; + + /* 2. 在同一帧里用建好的模板依次匹配 */ + for (const it of foodROs) { + if (done[it.idx]) continue; // 已完成的跳过 + + const res = rg.find(it.ro); + if (res.isExist()) { + log.info(`${it.name}已找到`); + res.click(); + rg.dispose(); // 提前释放 + await doCraft(it.idx); + done[it.idx] = true; + hit = true; + break; // 一轮只处理一个 + } + } + + if (hit) break; // 本轮已处理,跳出 round + } finally { + rg.dispose(); // 确保释放截图 + } + } + + } + await genshin.returnMainUi(); } diff --git a/repo/js/采集cd管理/manifest.json b/repo/js/采集cd管理/manifest.json index 035de5aa0..6f33d7c55 100644 --- a/repo/js/采集cd管理/manifest.json +++ b/repo/js/采集cd管理/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "采集cd管理", - "version": "2.8.0", + "version": "2.8.1", "bgi_version": "0.44.8", "description": "仅面对会操作文件和读readme的用户,基于文件夹操作自动管理采集路线的cd,会按照路径组的顺序依次运行,直到指定的时间,并会按照给定的cd类型,自动跳过未刷新的路线", "saved_files": [