From 46fee29a1637cc484db1f46738057833c19bb08f Mon Sep 17 00:00:00 2001 From: JJMdzh Date: Wed, 4 Jun 2025 01:41:55 +0800 Subject: [PATCH] =?UTF-8?q?js=EF=BC=8C=E8=83=8C=E5=8C=85v2.28=20=E6=9D=90?= =?UTF-8?q?=E6=96=99=E6=9B=B4=E5=8F=98=E6=97=B6=E5=88=9D=E5=A7=8B=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E6=9B=B4=E6=96=B0=EF=BC=9B=E6=96=B0=E5=A2=9E=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E8=AF=86=E5=88=AB=20(#969)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add files via upload * Add files via upload * Add files via upload --- repo/js/背包材料统计/README.md | 3 +- .../assets/imageClick/树脂/Picture/image1.png | Bin 0 -> 18029 bytes .../assets/imageClick/树脂/icon/Comfirm.png | Bin 0 -> 1261 bytes repo/js/背包材料统计/main.js | 416 +++++++++++++----- repo/js/背包材料统计/manifest.json | 2 +- 5 files changed, 311 insertions(+), 110 deletions(-) create mode 100644 repo/js/背包材料统计/assets/imageClick/树脂/Picture/image1.png create mode 100644 repo/js/背包材料统计/assets/imageClick/树脂/icon/Comfirm.png diff --git a/repo/js/背包材料统计/README.md b/repo/js/背包材料统计/README.md index 7b8a5a1b..67f0a497 100644 --- a/repo/js/背包材料统计/README.md +++ b/repo/js/背包材料统计/README.md @@ -76,4 +76,5 @@ + v2.24 修复不能空路径使用背包统计功能等bug + v2.25 当前、后位材料识别(加速扫描),新增只扫描路径材料名选项(内存占用更小) + v2.26 修复读取材料时间错误等bug,新增路径材料时间成本计算 -+ v2.27 修复计算材料数错误、目标数量临界值等bug \ No newline at end of file ++ v2.27 修复计算材料数错误、目标数量临界值、"3"识别成"三"等bug ++ v2.28 材料更变时初始数量更新;正常记录排除35秒以上0数量的路径记录(可能是卡路径,需手动根据0记录去甄别),新增材料名0后缀本地记录;新增背包弹窗识别 \ No newline at end of file diff --git a/repo/js/背包材料统计/assets/imageClick/树脂/Picture/image1.png b/repo/js/背包材料统计/assets/imageClick/树脂/Picture/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..85ecefe45cacacc36e61fbc577b4d0cace1f8a13 GIT binary patch literal 18029 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 UWh?l9V*tSHFRMR`F1Y>uKlQz1lmGw# literal 0 HcmV?d00001 diff --git a/repo/js/背包材料统计/assets/imageClick/树脂/icon/Comfirm.png b/repo/js/背包材料统计/assets/imageClick/树脂/icon/Comfirm.png new file mode 100644 index 0000000000000000000000000000000000000000..201445d06f23e0044a5d944714f767c31d982b3a GIT binary patch literal 1261 zcmV3^RTPH5wa+>C_V%`gLJQPttC3JhTd;yrARt6R zUPD8}Tel7jhS1s!@4aHEr~wM_$#&TM6>L8Y zxj_g7vMI0$T)HOg?1a-7pf(M&=L(rLw9FC?o>Y2nK;Vr*YAp;z@b1gP>=uC#zTB;B z+5){dpf(GEFGw*%je%5Ps7k|y9yo9k=FNbnW?_02Xac*AK*}2~Cj+ih7-I+%VewpH z=>tGPIelJv|63TyDcQ85s#t4>?b=$4s#0B{T)nPr{1gUy6g=h81<>9kL{>1yphb}z z0MGMKRdOLb^)QeE64-tSx-LU?raT!&Lrn%c&pG+vL46G@Zi9T}9P>PHxTgSN0v&Sz z3tV3sLVgmY3WPB%o$qWU1vvkwlMDz{Y6#OPR9uh7F-K_e!1}4I-mf#e)wXK^LS*@FRQ)j0Je4t%UYo6Zl|@yEzWRnze}uq zG?ZYO3Ya+!UUp)mhm5Dm>Kgj8K4Mr(tg=oat5y z5!7U1cBAn4LZP`Cr_ET|_7klC(5b;Q<@qpr6IaL;pkX?!e@0l+2D9!0yrSWxw7NJZ zKm=#c!QNkCNqy{xTdp3qKrz z?++5*O~;YG}I`nr6b3tdjB}A3|SF=(+@*T`t)&fnvs~V&jsQypF9) zp2!YeMN3!Dl;^H4{ur0BTQQ+>F5<#9R>&p;qjr+T^*_SKAx0IfO~#-7KOjj$Oe)Ra X+5Fmk<6x2400000NkvXXu0mjfM`bz| literal 0 HcmV?d00001 diff --git a/repo/js/背包材料统计/main.js b/repo/js/背包材料统计/main.js index 53d35a92..6937837d 100644 --- a/repo/js/背包材料统计/main.js +++ b/repo/js/背包材料统计/main.js @@ -578,13 +578,14 @@ async function MaterialPath(materialCategoryMap) { break; case 1: // 打开背包界面 - log.info("打开背包界面"); + // log.info("打开背包界面"); keyPress("B"); // 打开背包界面 await sleep(1000); + await imageClick() let backpackResult = await recognizeImage(BagpackRo, 2000); if (backpackResult.success) { - log.info("成功识别背包图标"); + // log.info("成功识别背包图标"); stage = 2; // 进入下一阶段 } else { log.warn("未识别到背包图标,重新尝试"); @@ -701,7 +702,7 @@ function pathExists(path) { } } // 递归读取目录下的所有文件路径,并排除特定后缀的文件 -function readAllFilePaths(dirPath, currentDepth = 0, maxDepth = 3, includeExtensions = ['.png', '.json', '.txt']) { +function readAllFilePaths(dirPath, currentDepth = 0, maxDepth = 3, includeExtensions = ['.png', '.json', '.txt'], includeDirs = false) { // log.info(`开始递归读取目录:${dirPath},当前深度:${currentDepth}`); if (!pathExists(dirPath)) { log.error(`目录 ${dirPath} 不存在`); @@ -717,10 +718,16 @@ function readAllFilePaths(dirPath, currentDepth = 0, maxDepth = 3, includeExtens const isDirectory = pathExists(entry); // 如果路径存在且返回的是数组,则认为是目录 // log.info(`处理条目:${entry},是否为目录:${isDirectory}`); - if (isDirectory && currentDepth < maxDepth) { - // log.info(`递归读取子目录:${entry}`); - filePaths.push(...readAllFilePaths(entry, currentDepth + 1, maxDepth, includeExtensions)); // 递归读取子目录 - } else if (!isDirectory) { + if (isDirectory) { + if (includeDirs) { + // log.info(`添加目录路径:${entry}`); + filePaths.push(entry); // 添加目录路径 + } + if (currentDepth < maxDepth) { + // log.info(`递归读取子目录:${entry}`); + filePaths.push(...readAllFilePaths(entry, currentDepth + 1, maxDepth, includeExtensions, includeDirs)); // 递归读取子目录 + } + } else { const fileExtension = entry.substring(entry.lastIndexOf('.')); if (includeExtensions.includes(fileExtension.toLowerCase())) { // log.info(`添加文件路径:${entry}`); @@ -843,37 +850,61 @@ function readMaterialCategories(materialDir) { // log.info(`完成材料分类信息读取,分类信息:${JSON.stringify(materialCategories, null, 2)}`); return materialCategories; } + // 获取当前时间(以小时为单位) function getCurrentTimeInHours() { const now = new Date(); return now.getHours() + now.getMinutes() / 60 + now.getSeconds() / 3600; } -// 记录运行时间到材料对应的文件中 + +// 辅助函数:写入内容到文件 +function writeContentToFile(filePath, content) { + try { + // 读取文件现有内容 + let existingContent = ''; + try { + existingContent = file.readTextSync(filePath); // 读取文件内容 + } catch (readError) { + // 如果文件不存在或读取失败,existingContent 保持为空字符串 + log.warn(`文件读取失败或文件不存在: ${filePath}`); + } + + // 将新的记录内容插入到最前面 + const updatedContent = content + existingContent; + + // 将更新后的内容写回文件 + const result = file.writeTextSync(filePath, updatedContent, false); // 覆盖写入 + if (result) { + log.info(`记录成功: ${filePath}`); + } else { + log.error(`记录失败: ${filePath}`); + } + } catch (error) { + log.error(`记录失败: ${error}`); + } +} + function recordRunTime(resourceName, pathName, startTime, endTime, runTime, recordDir, materialCountDifferences = {}) { - const recordPath = `${recordDir}/${resourceName}.txt`; // 记录文件路径,以材料名命名 - const content = `路径名: ${pathName}\n开始时间: ${startTime}\n结束时间: ${endTime}\n运行时间: ${runTime}秒\n数量变化: ${JSON.stringify(materialCountDifferences)}\n\n`; + const recordPath = `${recordDir}/${resourceName}.txt`; // 正常记录文件路径 + const normalContent = `路径名: ${pathName}\n开始时间: ${startTime}\n结束时间: ${endTime}\n运行时间: ${runTime}秒\n数量变化: ${JSON.stringify(materialCountDifferences)}\n\n`; try { // 只有当运行时间大于或等于3秒时,才记录运行时间 if (runTime >= 3) { - // 读取文件现有内容 - let existingContent = ''; - try { - existingContent = file.readTextSync(recordPath); // 读取文件内容 - } catch (readError) { - // 如果文件不存在或读取失败,existingContent 保持为空字符串 - log.warn(`文件读取失败或文件不存在: ${readError}`); + // 检查 materialCountDifferences 中是否存在材料数目为 0 的情况 + for (const [material, count] of Object.entries(materialCountDifferences)) { + if (count === 0) { + // 如果材料数目为 0,记录到单独的文件 + const zeroMaterialPath = `${recordDir}/${material}-0.txt`; // 材料数目为0的记录文件路径 + const zeroMaterialContent = `路径名: ${pathName}\n开始时间: ${startTime}\n结束时间: ${endTime}\n运行时间: ${runTime}秒\n数量变化: ${JSON.stringify(materialCountDifferences)}\n\n`; + writeContentToFile(zeroMaterialPath, zeroMaterialContent); // 写入材料数目为0的记录 + } } - // 将新的记录内容插入到最前面 - const updatedContent = content + existingContent; - - // 将更新后的内容写回文件 - const result = file.writeTextSync(recordPath, updatedContent, false); // 覆盖写入 - if (result) { - log.info(`记录运行时间成功: ${recordPath}`); - } else { - log.error(`记录运行时间失败: ${recordPath}`); + // 检查是否需要记录正常内容 + if (!(Object.values(materialCountDifferences).includes(0) && finalCumulativeDistance === 0)) { + // 写入正常记录的内容 + writeContentToFile(recordPath, normalContent); } } else { log.info(`运行时间小于3秒,请检查路径要求: ${recordPath}`); @@ -882,6 +913,7 @@ function recordRunTime(resourceName, pathName, startTime, endTime, runTime, reco log.error(`记录运行时间失败: ${error}`); } } + // 读取材料对应的文件,获取上次运行的结束时间 function getLastRunEndTime(resourceName, pathName, recordDir) { const recordPath = `${recordDir}/${resourceName}.txt`; // 记录文件路径,以材料名命名 @@ -1202,115 +1234,283 @@ function matchImageAndGetCategory(resourceName, imagesDir) { dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": false })); - // 遍历所有路径文件 - for (const { path: pathingFilePath, resourceName } of allPaths) { - const pathName = basename(pathingFilePath); // 假设路径文件名即为材料路径 - // log.info(`处理路径文件:${pathingFilePath},材料名:${resourceName},材料路径:${pathName}`); +// 假设 flattenedLowCountMaterials 是一个全局变量或在外部定义的变量 +let currentMaterialName = null; // 用于记录当前材料名 - // 查找材料对应的CD分类 - let categoryFound = false; - for (const [category, materials] of Object.entries(materialCategories)) { - for (const [refreshCDKey, materialList] of Object.entries(materials)) { - const refreshCD = JSON.parse(refreshCDKey); - if (materialList.includes(resourceName)) { - // 获取当前时间 - const currentTime = getCurrentTimeInHours(); +// 遍历所有路径文件 +for (const { path: pathingFilePath, resourceName } of allPaths) { + const pathName = basename(pathingFilePath); // 假设路径文件名即为材料路径 + // log.info(`处理路径文件:${pathingFilePath},材料名:${resourceName},材料路径:${pathName}`); - // 读取上次运行的结束时间 - const lastEndTime = getLastRunEndTime(resourceName, pathName, recordDir); + // 查找材料对应的CD分类 + let categoryFound = false; + for (const [category, materials] of Object.entries(materialCategories)) { + for (const [refreshCDKey, materialList] of Object.entries(materials)) { + const refreshCD = JSON.parse(refreshCDKey); + if (materialList.includes(resourceName)) { + // 获取当前时间 + const currentTime = getCurrentTimeInHours(); - // 计算效率 - const perTime = calculatePerTime(resourceName, pathName, recordDir); + // 读取上次运行的结束时间 + const lastEndTime = getLastRunEndTime(resourceName, pathName, recordDir); - log.info(`路径文件:${pathName}单个材料耗时:${perTime}秒`); - // 判断是否可以运行脚本 - if (canRunPathingFile(currentTime, lastEndTime, refreshCD, pathName) && (perTime === null || perTime <= timeCost)) { - log.info(`可调用路径文件:${pathName}`); + // 计算效率 + const perTime = calculatePerTime(resourceName, pathName, recordDir); - // 记录开始时间 - const startTime = new Date().toLocaleString(); + log.info(`路径文件:${pathName} 单个材料耗时:${perTime}秒`); + // 判断是否可以运行脚本 + if (canRunPathingFile(currentTime, lastEndTime, refreshCD, pathName) && (perTime === null || perTime <= timeCost)) { + log.info(`可调用路径文件:${pathName}`); - // 调用路径文件 - await pathingScript.runFile(pathingFilePath); - await sleep(500); + // 根据 materialCategoryMap 构建 resourceCategoryMap + const resourceCategoryMap = {}; + for (const [materialCategory, materialList] of Object.entries(materialCategoryMap)) { + if (materialList.includes(resourceName)) { + resourceCategoryMap[materialCategory] = [resourceName]; + break; + } + } - // 记录结束时间 - const endTime = new Date().toLocaleString(); + // 输出 resourceCategoryMap 以供调试 + log.info(`resourceCategoryMap: ${JSON.stringify(resourceCategoryMap, null, 2)}`); - // 计算运行时间 - const runTime = (new Date(endTime) - new Date(startTime)) / 1000; // 秒 + // 如果材料名发生变化,更新 flattenedLowCountMaterials + if (currentMaterialName !== resourceName) { + currentMaterialName = resourceName; // 更新当前材料名 + // 调用背包材料统计(获取当前材料数量) + const updatedLowCountMaterials = await MaterialPath(resourceCategoryMap); + // 展平数组并按数量从小到大排序 + flattenedLowCountMaterials = updatedLowCountMaterials + .flat() + .sort((a, b) => parseInt(a.count, 10) - parseInt(b.count, 10)); + log.info(`材料名变更,更新了 flattenedLowCountMaterials`); + } - // 根据 materialCategoryMap 构建 resourceCategoryMap - const resourceCategoryMap = {}; - for (const [materialCategory, materialList] of Object.entries(materialCategoryMap)) { - if (materialList.includes(resourceName)) { - resourceCategoryMap[materialCategory] = [resourceName]; - break; - } - } + // 记录开始时间 + const startTime = new Date().toLocaleString(); - // 输出 resourceCategoryMap 以供调试 - log.info(`resourceCategoryMap: ${JSON.stringify(resourceCategoryMap, null, 2)}`); + // 在路径执行前执行一次位移监测 + const initialPosition = genshin.getPositionFromMap(); + let initialCumulativeDistance = 0; - // 调用背包材料统计(获取调用路径文件后的材料数量) - const updatedLowCountMaterials = await MaterialPath(resourceCategoryMap); + // 调用路径文件 + await pathingScript.runFile(pathingFilePath); - // 展平数组并按数量从小到大排序 - const flattenedUpdatedMaterialCounts = updatedLowCountMaterials - .flat() - .sort((a, b) => parseInt(a.count, 10) - parseInt(b.count, 10)); + // 在路径执行后执行一次位移监测 + const finalPosition = genshin.getPositionFromMap(); + const finalCumulativeDistance = calculateDistance(initialPosition, finalPosition); - // 提取更新后的低数量材料的名称 - const updatedLowCountMaterialNames = flattenedUpdatedMaterialCounts.map(material => material.name); + // 记录结束时间 + const endTime = new Date().toLocaleString(); - // 创建一个映射,用于存储更新前后的数量差值 - const materialCountDifferences = {}; + // 计算运行时间 + const runTime = (new Date(endTime) - new Date(startTime)) / 1000; // 秒 - // 遍历更新后的材料数量,计算差值 - flattenedUpdatedMaterialCounts.forEach(updatedMaterial => { - const originalMaterial = flattenedLowCountMaterials.find(material => material.name === updatedMaterial.name); - if (originalMaterial) { - const originalCount = parseInt(originalMaterial.count, 10); - const updatedCount = parseInt(updatedMaterial.count, 10); - const difference = updatedCount - originalCount; - materialCountDifferences[updatedMaterial.name] = difference; - } - }); - // 更新 flattenedLowCountMaterials 为最新的材料数量 - flattenedLowCountMaterials = flattenedLowCountMaterials.map(material => { - // 找到对应的更新后的材料数量 - const updatedMaterial = flattenedUpdatedMaterialCounts.find(updated => updated.name === material.name); - if (updatedMaterial) { - return { ...material, count: updatedMaterial.count }; // 更新数量 - } - return material; - }); + // 调用背包材料统计(获取调用路径文件后的材料数量) + const updatedLowCountMaterials = await MaterialPath(resourceCategoryMap); - // 打印数量差值 - log.info(`数量变化: ${JSON.stringify(materialCountDifferences, null, 2)}`); + // 展平数组并按数量从小到大排序 + const flattenedUpdatedMaterialCounts = updatedLowCountMaterials + .flat() + .sort((a, b) => parseInt(a.count, 10) - parseInt(b.count, 10)); - // 记录运行时间到材料对应的文件中 - recordRunTime(resourceName, pathName, startTime, endTime, runTime, recordDir, materialCountDifferences); - log.info(`当前材料名: ${JSON.stringify(resourceName, null, 2)}`); + // 提取更新后的低数量材料的名称 + const updatedLowCountMaterialNames = flattenedUpdatedMaterialCounts.map(material => material.name); - categoryFound = true; + // 创建一个映射,用于存储更新前后的数量差值 + const materialCountDifferences = {}; - break; - } else { - if (perTime !== null && perTime > timeCost) { - log.info(`路径文件 ${pathName} 的单个材料耗时大于 ${timeCost} ,不执行`); - } else { - log.info(`路径文件 ${pathName} 未能执行!`); - } + // 遍历更新后的材料数量,计算差值 + flattenedUpdatedMaterialCounts.forEach(updatedMaterial => { + const originalMaterial = flattenedLowCountMaterials.find(material => material.name === updatedMaterial.name); + if (originalMaterial) { + const originalCount = parseInt(originalMaterial.count, 10); + const updatedCount = parseInt(updatedMaterial.count, 10); + const difference = updatedCount - originalCount; + materialCountDifferences[updatedMaterial.name] = difference; } + }); + + // 更新 flattenedLowCountMaterials 为最新的材料数量 + flattenedLowCountMaterials = flattenedLowCountMaterials.map(material => { + // 找到对应的更新后的材料数量 + const updatedMaterial = flattenedUpdatedMaterialCounts.find(updated => updated.name === material.name); + if (updatedMaterial) { + return { ...material, count: updatedMaterial.count }; // 更新数量 + } + return material; + }); + + // 打印数量差值 + log.info(`数量变化: ${JSON.stringify(materialCountDifferences, null, 2)}`); + + // 记录运行时间到材料对应的文件中 + recordRunTime(resourceName, pathName, startTime, endTime, runTime, recordDir, materialCountDifferences, finalCumulativeDistance); + log.info(`当前材料名: ${JSON.stringify(resourceName, null, 2)}`); + + categoryFound = true; + + break; + } else { + if (perTime !== null && perTime > timeCost) { + log.info(`路径文件 ${pathName} 的单个材料耗时大于 ${timeCost} ,不执行`); + } else { + log.info(`路径文件 ${pathName} 未能执行!`); } } - if (categoryFound) break; } } + if (categoryFound) break; + } +} } catch (error) { log.error(`操作失败: ${error}`); } })(); +// 辅助函数:计算两点之间的距离 +function calculateDistance(initialPosition, finalPosition) { + const deltaX = finalPosition.X - initialPosition.X; + const deltaY = finalPosition.Y - initialPosition.Y; + return Math.sqrt(deltaX * deltaX + deltaY * deltaY); +} +// 修改后的位移监测函数 +async function monitorDisplacement(monitoring, resolve) { + // 获取对象的实际初始位置 + let lastPosition = genshin.getPositionFromMap(); + let cumulativeDistance = 0; // 初始化累计位移量 + let lastUpdateTime = Date.now(); // 记录上一次位置更新的时间 + while (monitoring) { + const currentPosition = genshin.getPositionFromMap(); // 获取当前位置 + const currentTime = Date.now(); // 获取当前时间 + + // 计算位移量 + const deltaX = currentPosition.X - lastPosition.X; + const deltaY = currentPosition.Y - lastPosition.Y; + let distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + + // 如果位移量小于0.5,则视为0 + if (distance < 0.5) { + distance = 0; + } + + // 如果有位移,更新累计位移量和最后更新时间 + if (distance > 0) { + cumulativeDistance += distance; // 累计位移量 + lastUpdateTime = currentTime; // 更新最后更新时间 + } + + // 检测是否超过5秒没有位移 + if (currentTime - lastUpdateTime >= 5000) { + // 触发跳跃 + keyPress(VK_SPACE); + lastUpdateTime = currentTime; // 重置最后更新时间 + } + + // 输出位移信息和累计位移量 + log.info(`时间:${(currentTime - lastUpdateTime) / 1000}秒,位移信息: X=${currentPosition.X}, Y=${currentPosition.Y}, 当前位移量=${distance.toFixed(2)}, 累计位移量=${cumulativeDistance.toFixed(2)}`); + + // 更新最后位置 + lastPosition = currentPosition; + + // 等待1秒再次检查 + await sleep(1000); + } + + // 当监测结束时,返回累计位移量 + resolve(cumulativeDistance); +} + +// 识图点击主逻辑 +async function imageClick() { + + // 定义包含多个文件夹的根目录 + const rootDir = "assets/imageClick"; + + // 获取根目录下的所有子目录路径,深度为 1 + const subDirs = readAllFilePaths(rootDir, 0, 0, [], true); + + // 遍历子目录 + for (const subDir of subDirs) { + + // 从 subDir 中找到 icon 和 Picture 文件夹 + const entries = readAllFilePaths(subDir, 0, 1, [], true); // 获取当前子目录下的所有条目 + + // 筛选出 icon 和 Picture 文件夹 + const iconDir = entries.find(entry => entry.endsWith('\icon')); + const pictureDir = entries.find(entry => entry.endsWith('\Picture')); + + if (!iconDir) { + // log.warn(`未找到 icon 文件夹,跳过分类文件夹:${subDir}`); + continue; + } + + if (!pictureDir) { + // log.warn(`未找到 Picture 文件夹,跳过分类文件夹:${subDir}`); + continue; + } + + // 读取 icon 文件夹下的所有文件路径 + const iconFilePaths = readAllFilePaths(iconDir, 0, 0, ['.png', '.jpg', '.jpeg']); + // 读取 Picture 文件夹下的所有文件路径 + const pictureFilePaths = readAllFilePaths(pictureDir, 0, 0, ['.png', '.jpg', '.jpeg']); + + // 创建图标的 RecognitionObject + const iconRecognitionObjects = []; + for (const filePath of iconFilePaths) { + const mat = file.readImageMatSync(filePath); + if (mat.empty()) { + log.error(`加载图标失败:${filePath}`); + continue; // 跳过当前文件 + } + const recognitionObject = RecognitionObject.TemplateMatch(mat, 0, 0, 1920, 1080); + iconRecognitionObjects.push({ name: basename(filePath), ro: recognitionObject }); + } + + // 创建图库的 ImageRegion,以获取图标的X,Y,W,H + const pictureRegions = []; + for (const filePath of pictureFilePaths) { + const mat = file.readImageMatSync(filePath); + if (mat.empty()) { + log.error(`加载图库失败:${filePath}`); + continue; // 跳过当前文件 + } + pictureRegions.push({ name: basename(filePath), region: new ImageRegion(mat, 0, 0) }); + } + + // 在每张图片中查找图标的位置信息 + const foundRegions = []; + for (const picture of pictureRegions) { + for (const icon of iconRecognitionObjects) { + const foundRegion = picture.region.find(icon.ro); + if (foundRegion.isExist()) { + foundRegions.push({ + pictureName: picture.name, + iconName: icon.name, + region: foundRegion + }); + } + } + } + + // 在屏幕上查找并点击图标 + for (const foundRegion of foundRegions) { + const tolerance = 1; // 容错区间 + const iconMat = file.readImageMatSync(`${iconDir}/${foundRegion.iconName}`); + const recognitionObject = RecognitionObject.TemplateMatch(iconMat, foundRegion.region.x - tolerance, foundRegion.region.y - tolerance, foundRegion.region.width + 2 * tolerance, foundRegion.region.height + 2 * tolerance); + recognitionObject.threshold = 0.9; // 设置识别阈值为 0.9 + const result = captureGameRegion().find(recognitionObject); + if (result.isExist()) { + const x = Math.round(foundRegion.region.x + foundRegion.region.width / 2); + const y = Math.round(foundRegion.region.y + foundRegion.region.height / 2); + log.info(`即将点击图标:${foundRegion.iconName},位置: (${x}, ${y})`); + await click(x, y); // 假设 click 是一个可用的点击函数 + log.info(`点击 ${foundRegion.iconName}成功,位置: (${x}, ${y})`); + await sleep(500); // 等待一段时间 + } else { + log.warn(`未找到背包弹窗:${foundRegion.iconName}`); + } + } + } +} diff --git a/repo/js/背包材料统计/manifest.json b/repo/js/背包材料统计/manifest.json index a66ea083..f4b51536 100644 --- a/repo/js/背包材料统计/manifest.json +++ b/repo/js/背包材料统计/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "背包材料统计", - "version": "2.27", + "version": "2.28", "bgi_version": "0.44.8", "description": "默认四行为一页;模板匹配材料,OCR识别数量。\n数字太小可能无法识别,用?代替。\n目前支持采集材料的数量统计+路径CD管理。", "authors": [