From 19b89d8a76bdbc4254a80bac1fff787c674beb97 Mon Sep 17 00:00:00 2001 From: mno <718135749@qq.com> Date: Wed, 24 Dec 2025 19:19:10 +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=E5=92=8C=E9=94=84=E5=9C=B0=E4=B8=80=E6=9D=A1=E9=BE=99?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20(#2566)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * js:锄地一条龙 1.优化坐标检验,新增与地图追踪中坐标比较 2.新增自定义标签处理,允许填自定义标签 3.增加怪物数量警告,配置不合理时将警告去读readme 4.增加分辨率警告,不为1080p时警告 5.修改默认匹配阈值为0.9 * js:采集cd管理 1.修改默认拾取阈值为0.9 2.优化路径组循环判定 3.增加校验逻辑,需要与终点距离30以内才视为完成路线 * Update main.js 1.优化加工速度 2.更正变量名 * Update 酸奶油1.png --- repo/js/AutoHoeingOneDragon/main.js | 120 ++++++++++-------- repo/js/AutoHoeingOneDragon/manifest.json | 2 +- repo/js/AutoHoeingOneDragon/settings.json | 2 +- .../assets/RecognitionObject/酸奶油1.png | Bin 2887 -> 2473 bytes repo/js/采集cd管理/main.js | 87 ++++++++++--- repo/js/采集cd管理/manifest.json | 2 +- 6 files changed, 139 insertions(+), 74 deletions(-) diff --git a/repo/js/AutoHoeingOneDragon/main.js b/repo/js/AutoHoeingOneDragon/main.js index 0f1cf8a3e..92cd8734f 100644 --- a/repo/js/AutoHoeingOneDragon/main.js +++ b/repo/js/AutoHoeingOneDragon/main.js @@ -1,4 +1,4 @@ -//当前js版本1.13.1 +//当前js版本1.14.0 let timeMoveUp; let timeMoveDown; @@ -56,6 +56,12 @@ let state; const accountName = settings.accountName || "默认账户"; let pathings; let localeWorks; + +const priorityTags = (settings.priorityTags || "").split(",").map(tag => tag.trim()).filter(tag => tag.length > 0); +const excludeTags = (settings.excludeTags || "").split(",").map(tag => tag.trim()).filter(tag => tag.length > 0); + +let runningFailCount = 0; + (async function () { targetItems = await loadTargetItems(); //自定义配置处理 @@ -102,8 +108,6 @@ let localeWorks; const groupTags = groupSettings.map(str => str.split(',').filter(Boolean)); groupTags[0] = [...new Set(groupTags.flat())]; - const priorityTags = (settings.priorityTags || "").split(",").map(tag => tag.trim()).filter(tag => tag.length > 0); - const excludeTags = (settings.excludeTags || "").split(",").map(tag => tag.trim()).filter(tag => tag.length > 0); if (pickup_Mode != "模板匹配拾取,拾取狗粮和怪物材料" && pickup_Mode != "模板匹配拾取,只拾取狗粮") { excludeTags.push("沙暴"); log.warn("拾取模式不是模板匹配,无法处理沙暴路线,自动排除所有沙暴路线"); @@ -129,7 +133,7 @@ let localeWorks; } //预处理路线并建立对象 - pathings = await processPathings(); + pathings = await processPathings(groupTags); //按照用户配置标记路线 await markPathings(pathings, groupTags, priorityTags, excludeTags); @@ -177,6 +181,28 @@ let localeWorks; log.info('当前队伍:' + teamStr); switch (true) { + case targetEliteNum <= 350 && targetMonsterNum >= 100: + log.warn("目标怪物数量配置不合理,建议重新阅读 readme 相关部分"); + await sleep(5000); + log.warn("目标怪物数量配置不合理,建议重新阅读 readme 相关部分"); + await sleep(5000); + log.warn("目标怪物数量配置不合理,建议重新阅读 readme 相关部分"); + await sleep(5000); + log.warn("目标怪物数量配置不合理,建议重新阅读 readme 相关部分"); + await sleep(5000); + break; + + case width !== 1920 || height !== 1080: + log.warn("游戏窗口非 1920×1080,可能导致图像识别失败,如果执意使用可能造成拾取等行为异常,后果自负"); + await sleep(5000); + log.warn("游戏窗口非 1920×1080,可能导致图像识别失败,如果执意使用可能造成拾取等行为异常,后果自负"); + await sleep(5000); + log.warn("游戏窗口非 1920×1080,可能导致图像识别失败,如果执意使用可能造成拾取等行为异常,后果自负"); + await sleep(5000); + log.warn("游戏窗口非 1920×1080,可能导致图像识别失败,如果执意使用可能造成拾取等行为异常,后果自负"); + await sleep(5000); + break; + case ['钟离', '芙宁娜', '纳西妲', '雷电将军'].every(n => avatars.includes(n)): log.warn("四神队不适合锄地,建议重新阅读 readme 相关部分"); await sleep(10000); @@ -210,7 +236,7 @@ let localeWorks; })(); //预处理路线,建立对象 -async function processPathings() { +async function processPathings(groupTags) { // 读取怪物信息 const monsterInfoContent = await file.readText("assets/monsterInfo.json"); const monsterInfoObject = JSON.parse(monsterInfoContent); @@ -290,53 +316,22 @@ async function processPathings() { } } + const allTags = groupTags[0]; // 已经是 [...new Set(...)] 的结果 + // 2. 待匹配文本:路径名 + 描述 + const textToMatch = (pathing.fullPath + " " + (description || "")); + // 3. 反查补 tag + allTags.forEach(tag => { + if (textToMatch.includes(tag)) { + pathing.tags.push(tag); + } + }); + // 去除重复标签 pathing.tags = [...new Set(pathing.tags)]; // 处理 map_name 属性 pathing.map_name = parsedContent.info?.map_name || "Teyvat"; // 如果有 map_name,则使用其值,否则默认为 "Teyvat" } - //优先使用index中的数据 - // 更新 pathings 的函数,接受索引文件路径作为参数 - async function updatePathings(indexFilePath) { - try { - // 读取文件内容 - const fileContent = await file.readText(indexFilePath); - // 将文件内容解析为 JSON 格式 - const data = JSON.parse(fileContent); - - // 遍历解析后的 JSON 数据 - for (const item of data) { - // 检查 pathings 中是否存在某个对象的 fileName 属性与 item.fileName 相同 - const existingPathing = pathings.find(pathing => pathing.fileName === item.fileName); - - if (existingPathing) { - // 直接覆盖其他字段,但先检查是否存在有效值 - if (item.时间 !== undefined) existingPathing.t = item.时间; - if (item.精英摩拉 !== undefined) existingPathing.mora_e = item.精英摩拉; - if (item.小怪摩拉 !== undefined) existingPathing.mora_m = item.小怪摩拉; - if (item.小怪数量 !== undefined) existingPathing.m = item.小怪数量; - if (item.精英数量 !== undefined) existingPathing.e = item.精英数量; - - // 使用 Set 来存储 tags,避免重复项 - const tagsSet = new Set(existingPathing.tags); - for (const key in item) { - if (key !== "fileName" && key !== "时间" && key !== "精英摩拉" && key !== "小怪摩拉" && key !== "小怪数量" && key !== "精英数量") { - if (item[key] === 1) { - tagsSet.add(key); - } - } - } - existingPathing.tags = Array.from(tagsSet); - } - } - } catch (error) { - log.error("Error:", error); - } - } - //await updatePathings("assets/index1.json"); - //await updatePathings("assets/index2.json"); - for (const pathing of pathings) { if (!settings.disableSelfOptimization && pathing.records) { //如果用户没有禁用自动优化,则参考运行记录更改预期用时 @@ -1005,9 +1000,9 @@ async function loadTargetItems() { let itsThreshold; if (match) { const val = parseFloat(match[1]); - itsThreshold = (!isNaN(val) && val >= 0 && val <= 1) ? val : 0.85; + itsThreshold = (!isNaN(val) && val >= 0 && val <= 1) ? val : 0.9; } else { - itsThreshold = 0.85; + itsThreshold = 0.9; } it.roi.Threshold = itsThreshold; it.roi.InitTemplate(); @@ -1313,7 +1308,6 @@ async function copyPathingsByGroup(pathings) { async function processPathingsByGroup(pathings, accountName) { let lastX = 0; let lastY = 0; - let runningFailCount = 0; // 定义路径组名称到组号的映射(10 个) const groupMapping = { @@ -1432,27 +1426,47 @@ async function processPathingsByGroup(pathings, accountName) { } await fakeLog(`${pathing.fileName}`, false, false, 0); + let fileEndX = 0, fileEndY = 0; + try { + const raw = file.readTextSync(pathing.fullPath); + const json = JSON.parse(raw); + if (Array.isArray(json.positions)) { + for (let i = json.positions.length - 1; i >= 0; i--) { + const p = json.positions[i]; + if (p.type !== 'orientation' && + typeof p.x === 'number' && + typeof p.y === 'number') { + fileEndX = p.x; + fileEndY = p.y; + break; + } + } + } + } catch (e) { /* 读文件失败就留 0,0 继续走后面逻辑 */ } + try { await genshin.returnMainUi(); const miniMapPosition = await genshin.getPositionFromMap(pathing.map_name); - // 比较坐标 const diffX = Math.abs(lastX - miniMapPosition.X); const diffY = Math.abs(lastY - miniMapPosition.Y); + const endDiffX = Math.abs(fileEndX - miniMapPosition.X); + const endDiffY = Math.abs(fileEndY - miniMapPosition.Y); + lastX = miniMapPosition.X; lastY = miniMapPosition.Y; - if ((diffX + diffY) < 5) { + + if ((diffX + diffY) < 5 || (endDiffX + endDiffY) > 30) { runningFailCount++; } else { runningFailCount = 0; } - //log.info(`当前位于${pathing.map_name}地图的(${miniMapPosition.X},${miniMapPosition.Y},距离上次距离${(diffX + diffY)}`); } catch (error) { log.error(`获取坐标时发生错误:${error.message}`); runningFailCount++; } if (runningFailCount >= 1) { - log.error("出发点与终点过于接近,或坐标获取异常,不记录运行数据"); + log.error("出发点与终点过于接近,终点偏差大于30,或坐标获取异常,不记录运行数据"); continue; } diff --git a/repo/js/AutoHoeingOneDragon/manifest.json b/repo/js/AutoHoeingOneDragon/manifest.json index bc0be6f7f..00a32e9b9 100644 --- a/repo/js/AutoHoeingOneDragon/manifest.json +++ b/repo/js/AutoHoeingOneDragon/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "锄地一条龙", - "version": "1.13.1", + "version": "1.14.0", "description": "一站式解决自动化锄地,支持只拾取狗粮,请仔细阅读README.md后使用", "authors": [ { diff --git a/repo/js/AutoHoeingOneDragon/settings.json b/repo/js/AutoHoeingOneDragon/settings.json index 29f4df5b6..5961f772d 100644 --- a/repo/js/AutoHoeingOneDragon/settings.json +++ b/repo/js/AutoHoeingOneDragon/settings.json @@ -98,7 +98,7 @@ { "name": "tagsForGroup1", "type": "input-text", - "label": "允许使用的标签:\n水免,次数盾,高危,传奇,蕈兽,小怪,沙暴\n多个标签使用【中文逗号】分隔\n\n路径组一要【排除】的标签", + "label": "允许使用的标签:\n水免,次数盾,高危,传奇,蕈兽,小怪,沙暴]\n允许使用自定义标签,文件路径或描述包含时将会视为路线含有该标签\n多个标签使用【中文逗号】分隔\n\n路径组一要【排除】的标签", "default": "蕈兽,传奇" }, { diff --git a/repo/js/采集cd管理/assets/RecognitionObject/酸奶油1.png b/repo/js/采集cd管理/assets/RecognitionObject/酸奶油1.png index 840fe090b941328874f89c91f8255dfb64278c16..f16173f5694f9643a1de57b4d35b00cccd4ca00f 100644 GIT binary patch literal 2473 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 3000) { + let pathRes = isArrivedAtEndPoint(filePath); + + // >>> 仅当 >3s 才更新 CD 并立即写回整条记录(含 history) <<< + if (timeDiff > 3000 && pathRes) { /* 1) 如果runPickupLog中不含优先材料,则按其他材料查找,使用最晚刷新时间 */ let hasPriority = state.runPickupLog.some(name => priorityItemSet.has(name)); let hitMaterials; @@ -901,15 +912,14 @@ let underWater = false; await appendDailyPickup(state.runPickupLog); state.runPickupLog = []; - } } } - let runnedAnyPath = true; + let loopattempts = 0; // ==================== 路径组循环 ==================== - while (runnedAnyPath) { - runnedAnyPath = false; + while (loopattempts < 2) { + loopattempt++; if (await isTimeRestricted(settings.timeRule, 10)) break; for (let i = 1; i <= groupCount; i++) { if (await isTimeRestricted(settings.timeRule, 10)) break; @@ -1117,7 +1127,6 @@ let underWater = false; state.running = true; const pickupTask = recognizeAndInteract(); - runnedAnyPath = true; log.info(`当前进度:路径组${i} ${folder} ${fileName} 为第 ${groupFiles.indexOf(filePath) + 1}/${groupFiles.length} 个`); log.info(`当前路线分均效率为 ${(filePath._efficiency ?? 0).toFixed(2)}`); @@ -1146,8 +1155,10 @@ let underWater = false; state.running = false; await pickupTask; + let pathRes = isArrivedAtEndPoint(filePath.fullPath); + // >>> 仅当 >3s 才更新 CD 并立即写回整条记录(含 history) <<< - if (timeDiff > 3000) { + if (timeDiff > 3000 && pathRes) { let newTimestamp = new Date(startTime); switch (currentCdType) { @@ -1199,7 +1210,7 @@ let underWater = false; // 清空本次记录 state.runPickupLog = []; - log.info(`本任务执行大于3秒,cd信息已更新,下一次可用时间为 ${newTimestamp.toLocaleString()}`); + log.info(`本任务cd信息已更新,下一次可用时间为 ${newTimestamp.toLocaleString()}`); } } log.info(`路径组${groupNumber} 的所有任务运行完成`); @@ -1208,6 +1219,7 @@ let underWater = false; } } } + await sleep(1000); } } catch (error) { @@ -1433,9 +1445,9 @@ async function loadTargetItems() { /* ---------- 1. 解析小括号阈值 ---------- */ const match = it.fullPath.match(/[((](.*?)[))]/); const itsThreshold = (match => { - if (!match) return 0.85; + if (!match) return 0.9; const v = parseFloat(match[1]); - return !isNaN(v) && v >= 0 && v <= 1 ? v : 0.85; + return !isNaN(v) && v >= 0 && v <= 1 ? v : 0.9; })(match); it.roi.Threshold = itsThreshold; it.roi.InitTemplate(); @@ -1807,12 +1819,12 @@ async function ingredientProcessing() { "奶酪", "培根", "香肠" ]); if (targetFoods.has(Foods[i])) { - if (await clickPNG("全部领取", 10)) { + if (await clickPNG("全部领取", 3)) { await clickPNG("点击空白区域继续"); await findPNG("食材加工2"); await sleep(100); } - let res1 = await clickPNG(Foods[i] + "1", 10); + let res1 = await clickPNG(Foods[i] + "1", 5); if (res1) { log.info(`${Foods[i]}已找到`); @@ -1837,7 +1849,7 @@ async function ingredientProcessing() { click(item.x, item.y); await sleep(200); click(item.x, item.y); - if (await findPNG(Foods[i] + "2", 15)) { + if (await findPNG(Foods[i] + "2", 5)) { log.info(`${Foods[i]}已找到`); res1 = true; break; @@ -1942,7 +1954,7 @@ async function appendDailyPickup(pickupLog) { } } -async function clickPNG(png, maxAttempts = 60) { +async function clickPNG(png, maxAttempts = 20) { //log.info(`调试-点击目标${png},重试次数${maxAttempts}`); const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`)); pngRo.Threshold = 0.95; @@ -1950,7 +1962,7 @@ async function clickPNG(png, maxAttempts = 60) { return await findAndClick(pngRo, true, maxAttempts); } -async function findPNG(png, maxAttempts = 60) { +async function findPNG(png, maxAttempts = 20) { //log.info(`调试-识别目标${png},重试次数${maxAttempts}`); const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`)); pngRo.Threshold = 0.95; @@ -1963,9 +1975,48 @@ async function findAndClick(target, doClick = true, maxAttempts = 60) { const rg = captureGameRegion(); try { const res = rg.find(target); - if (res.isExist()) { await sleep(200); if (doClick) { res.click(); } return true; } + if (res.isExist()) { await sleep(checkInterval * 2 + 50); if (doClick) { res.click(); } return true; } } finally { rg.dispose(); } - if (i < maxAttempts - 1) await sleep(50); + if (i < maxAttempts - 1) await sleep(checkInterval); } return false; -} \ No newline at end of file +} + +/** + * 判断当前人物是否已到达指定路线的终点 + * @param {string} fullPath 路线文件完整路径(.json) + * @returns {boolean} true = 已到达;false = 未到达/读文件失败/取坐标失败 + */ +function isArrivedAtEndPoint(fullPath) { + try { + /* 1. 读路线文件,取终点坐标 */ + const raw = file.readTextSync(fullPath); + const json = JSON.parse(raw); + if (!Array.isArray(json.positions)) return false; + + let endX = 0, endY = 0; + for (let i = json.positions.length - 1; i >= 0; i--) { + const p = json.positions[i]; + if (p.type !== 'orientation' && + typeof p.x === 'number' && + typeof p.y === 'number') { + endX = p.x; + endY = p.y; + break; + } + } + if (endX === 0 && endY === 0) return false; // 没找到有效点 + + /* 2. 取当前人物坐标 */ + const mapName = (json.info?.map_name && json.info.map_name.trim()) ? json.info.map_name : 'Teyvat'; + const pos = genshin.getPositionFromMap(mapName); // 同步 API + const curX = pos.X; + const curY = pos.Y; + + /* 3. 曼哈顿距离 ≤30 视为到达 */ + return Math.abs(endX - curX) + Math.abs(endY - curY) <= 30; + } catch (e) { + /* 任何异常(读盘失败、解析失败、API 异常)都算“未到达” */ + return false; + } +} diff --git a/repo/js/采集cd管理/manifest.json b/repo/js/采集cd管理/manifest.json index fe9750bee..035de5aa0 100644 --- a/repo/js/采集cd管理/manifest.json +++ b/repo/js/采集cd管理/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "采集cd管理", - "version": "2.7.0", + "version": "2.8.0", "bgi_version": "0.44.8", "description": "仅面对会操作文件和读readme的用户,基于文件夹操作自动管理采集路线的cd,会按照路径组的顺序依次运行,直到指定的时间,并会按照给定的cd类型,自动跳过未刷新的路线", "saved_files": [