diff --git a/repo/js/AutoHoeingOneDragon/README.md b/repo/js/AutoHoeingOneDragon/README.md index 21a6c5b9..a1578dc2 100644 --- a/repo/js/AutoHoeingOneDragon/README.md +++ b/repo/js/AutoHoeingOneDragon/README.md @@ -35,9 +35,13 @@ - - 默认选择 **运行锄地路线** ,选择该模式会按照后续设置选择并运行相应路线 - - 选项 **输出地图追踪文件** ,会将选择的路线读取并分组输出到js文件夹下pathingOut文件夹 - - 选项 **强制刷新所有运行记录** ,用于清除js记录的运行历史 - - **选择执行第几个路径组:** 本js会分组运行地图追踪,分组方式详见后续选项,需要分组运行时请确保精英目标数量,小怪目标数量,各个路径组的标签等信息【完全相同】,复制配置组时未知原因无法正确复制配置,请不要使用 + - **选择执行第几个路径组:** 本js支持分组运行地图追踪,分组方式详见后续选项,需要分组运行时请确保精英目标数量,小怪目标数量,各个路径组的标签等信息【完全相同】,复制配置组时未知原因无法正确复制配置,请不要使用 - **本路径组使用配队名称:** 填写该路径组使用的配队名称,js会自动切换 - - **拾取模式:** 本js采用黑白名单结合的方式实现仅拾取部分物品(默认只拾取狗粮和晶蝶),如果你想要使用bgi默认的拾取以拾取绝大部分物品,请选择bgi拾取,如果不想拾取任何物品,请选择不拾取任何物品 + - **拾取模式:** + - - ocr拾取:使用ocr识别掉落物进行拾取,自定义拾取名单【仅在此模式下生效】 + - - 模板匹配拾取:测试中,速度最快,性能消耗最低,只拾取四种锄地会掉落的狗粮 + - - bgi原版拾取 + - - 不拾取 - **效率降序运行:**当你时间不足以刷完所有怪物且不确定时,建议通过开启该项和配置下一项来实现在指定时间前尽可能多刷效率高的路线并按时终止 - **输入不运行的时间或时间段的小时数** 当你需要让js在特定的时间终止运行时,按描述填写,js会在距离目标时间小于五分钟时终止运行并等待到目标时间 - **泥头车模式(实验性功能):** 接近战斗地点(距离5-30)时,提前让指定序号的角色开e,建议以下角色开启:芙宁娜,爱可菲,雷电将军。警告,可能会增加性能开销和降低稳定性。 @@ -50,12 +54,12 @@ - - 蕈兽 :表明路线含有蕈兽,蕈兽遇到雷火元素时会发生转化,转化后占据精英怪物的名额却只掉落少量摩拉,通常建议禁用 - - 小怪 :表明路线只含小怪,战斗强度低,且无需携带万叶来拾取可能掉落的狗粮,可以适当携带等级较低或不上场的角色来获取经验收益 - - 分组逻辑:不含路径组1排除标签和任何其他组标签的路径会进入路径组1,剩余路径若含有路径组x的标签之一,则会进入路径组x - - - 使用示例:路径组一填写蕈兽,禁用蕈兽路线,路径组二填写次数盾,水免,处理路径组一的配队难以处理的次数盾和水免怪物,路径组三填写小怪,队伍中放升级中角色获取经验 + - - 使用示例:路径组一填写蕈兽,禁用蕈兽路线,路径组二填写次数盾,水免,处理路径组一的配队难以处理的次数盾和水免怪物,路径组三填写小怪,队伍中放升级中角色获取经验,将本js添加到【多个配置组】中,根据路径组的具体情况配置每个配置组的设置 - **路线效率计算权重:** 影响js评估路线价值,计算公式如下,权重越大越看重总收益 - $$ 怪均^k \times 秒均 $$ - **自动优化:** js将根据运行记录调整每条路线的预期运行时间,具体逻辑为,至多6条记录,去除一个最大值、一个最小值后,每条记录占据20%的权重,剩余权重由默认数据填充。如果你不想要这个功能,请禁用。 - **目标数量:** 选取路线目标达到的精英怪数量,默认为400,同理小怪数量默认为2000 - - **优先关键词:**含有关键词的路线会被视为拥有最高效率,例如填写600来让所有600怪物优先考虑,填写骗骗花来优先考虑骗骗花 + - **优先关键词:** 含有关键词的路线会被视为拥有最高效率,例如填写600来让所有600怪物优先考虑,填写骗骗花来优先考虑骗骗花 - **排除关键词:** 含有关键词的路线会被排除,例如填写纳塔来排除所有纳塔路线,同样使用中文逗号分隔 ### 二、**锄地收益** @@ -74,6 +78,8 @@ --- ### 更新日志 +### 1.4.0(2025.08.12) +1.增加拾取模式,模板匹配拾取并设为默认项,之前的拾取模式改名为ocr拾取 ### 1.3.8(2025.08.11) 1.优化精英部分点位 ### 1.3.7(2025.08.10) diff --git a/repo/js/AutoHoeingOneDragon/assets/targetItems/战狂.png b/repo/js/AutoHoeingOneDragon/assets/targetItems/战狂.png new file mode 100644 index 00000000..0fb0a56e Binary files /dev/null and b/repo/js/AutoHoeingOneDragon/assets/targetItems/战狂.png differ diff --git a/repo/js/AutoHoeingOneDragon/assets/targetItems/教官.png b/repo/js/AutoHoeingOneDragon/assets/targetItems/教官.png new file mode 100644 index 00000000..4ad7988c Binary files /dev/null and b/repo/js/AutoHoeingOneDragon/assets/targetItems/教官.png differ diff --git a/repo/js/AutoHoeingOneDragon/assets/targetItems/流放.png b/repo/js/AutoHoeingOneDragon/assets/targetItems/流放.png new file mode 100644 index 00000000..5e410171 Binary files /dev/null and b/repo/js/AutoHoeingOneDragon/assets/targetItems/流放.png differ diff --git a/repo/js/AutoHoeingOneDragon/assets/targetItems/游医.png b/repo/js/AutoHoeingOneDragon/assets/targetItems/游医.png new file mode 100644 index 00000000..b659f9e9 Binary files /dev/null and b/repo/js/AutoHoeingOneDragon/assets/targetItems/游医.png differ diff --git a/repo/js/AutoHoeingOneDragon/assets/滚轮上翻.json b/repo/js/AutoHoeingOneDragon/assets/滚轮上翻.json index ec7f12fe..17324610 100644 --- a/repo/js/AutoHoeingOneDragon/assets/滚轮上翻.json +++ b/repo/js/AutoHoeingOneDragon/assets/滚轮上翻.json @@ -10,7 +10,7 @@ "type": 6, "mouseX": 0, "mouseY": 0, - "time": 49 + "time": 5 } ], "info": { diff --git a/repo/js/AutoHoeingOneDragon/assets/滚轮下翻.json b/repo/js/AutoHoeingOneDragon/assets/滚轮下翻.json index 522e7401..d7d0f03c 100644 --- a/repo/js/AutoHoeingOneDragon/assets/滚轮下翻.json +++ b/repo/js/AutoHoeingOneDragon/assets/滚轮下翻.json @@ -10,7 +10,7 @@ "type": 6, "mouseX": 0, "mouseY": 0, - "time": 49 + "time": 5 } ], "info": { diff --git a/repo/js/AutoHoeingOneDragon/main.js b/repo/js/AutoHoeingOneDragon/main.js index 123e9105..a6e98bc1 100644 --- a/repo/js/AutoHoeingOneDragon/main.js +++ b/repo/js/AutoHoeingOneDragon/main.js @@ -1,9 +1,9 @@ -//当前js版本 1.3.8 +//当前js版本 1.4.0 //拾取时上下滑动的时间 -const timeMoveUp = 500; -const timeMoveDown = 1000; -const pickupMode = settings.pickupMode || "js拾取,默认只拾取狗粮和晶蝶"; +let timeMoveUp = 500; +let timeMoveDown = 1000; +let pickupMode = settings.pickupMode || "模板匹配拾取,默认只拾取狗粮"; if (settings.activeDumperMode) { //处理泥头车信息 dumpers = settings.activeDumperMode.split(',').map(Number).filter(num => num === 1 || num === 2 || num === 3 || num === 4); } else { @@ -11,10 +11,13 @@ if (settings.activeDumperMode) { //处理泥头车信息 } trigger = (+settings.trigger || 50); let gameRegion; +let targetItemPath = "assets/targetItems"; +let targetItems; (async function () { //自定义配置处理 const operationMode = settings.operationMode || "运行锄地路线"; + if (pickupMode === "js拾取,默认只拾取狗粮和晶蝶") pickupMode = "模板匹配拾取,默认只拾取狗粮"; let k = settings.efficiencyIndex; // 空字符串、null、undefined 或非数字 → 0.5 @@ -53,6 +56,16 @@ let gameRegion; const whitelistKeywords = ocrPickupJson["白名单"]; const blacklistKeywords = ocrPickupJson["黑名单"]; + targetItems = await readFolder(targetItemPath, false); + //模板匹配对象处理 + if (settings.pickupMode === "模板匹配拾取,默认只拾取狗粮") { + for (const targetItem of targetItems) { + targetItem.template = file.ReadImageMatSync(targetItem.fullPath); + targetItem.itemName = targetItem.fileName.replace(/\.png$/, ''); + } + timeMoveUp = trigger * 8; + timeMoveDown = trigger * 8; + } if (!settings.accountName) { for (let i = 0; i < 120; i++) { // 原始文本 @@ -487,12 +500,13 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo async function isMainUI() { // 修改后的图像路径 const imagePath = "assets/MainUI.png"; - // 修改后的识别区域(左上角区域) const xMin = 0; const yMin = 0; const width = 150; // 识别区域宽度 const height = 150; // 识别区域高度 + let template = file.ReadImageMatSync(imagePath); + let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height); // 尝试次数设置为 3 次 const maxAttempts = 3; @@ -500,8 +514,7 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo let attempts = 0; while (attempts < maxAttempts && !state.cancelRequested) { try { - let template = file.ReadImageMatSync(imagePath); - let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height); + gameRegion = captureGameRegion(); let result = gameRegion.find(recognitionObject); gameRegion.dispose(); @@ -534,15 +547,14 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo const yMin = 200; const width = 1000; // 识别区域宽度 const height = 250; // 识别区域高度 - + let template = file.ReadImageMatSync(imagePath); + let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height); // 尝试次数设置为 10 次 const maxAttempts = 10; let attempts = 0; while (attempts < maxAttempts && !state.cancelRequested) { try { - let template = file.ReadImageMatSync(imagePath); - let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height); gameRegion = captureGameRegion(); let result = gameRegion.find(recognitionObject); gameRegion.dispose(); @@ -578,11 +590,10 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo } // 定义一个函数用于执行OCR识别和交互 - async function performOcrAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance) { + async function recoginzeAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance) { async function performOcr(whitelistKeywords, xRange, yRange) { try { // 在捕获的区域内进行OCR识别 - gameRegion = captureGameRegion(); let resList = gameRegion.findMulti(RecognitionObject.ocr( xRange.min, yRange.min, xRange.max - xRange.min, yRange.max - yRange.min @@ -614,14 +625,36 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo } } + async function performTemplateMatch(centerYF) { + try { + let result; + let itemName = null; + // 在捕获的区域内进行模板匹配识别 + for (const targetItem of targetItems) { + let recognitionObject = RecognitionObject.TemplateMatch(targetItem.template, 1220, centerYF - 35, 70, 70); + result = gameRegion.find(recognitionObject); + if (result.isExist()) { + itemName = targetItem.itemName; + //log.info(`调试-距离为${result.y + result.height / 2 - centerYF}`); + break; + } + } + gameRegion.dispose(); + return itemName; + } catch (error) { + log.error(`模板匹配时发生异常: ${error.message}`); + return []; + } + } + while (!state.completed && !state.cancelRequested) { // 尝试找到 F 图标并返回其坐标 async function findFIcon(imagePath, xMin, yMin, width, height, timeout = 500) { + let template = file.ReadImageMatSync(imagePath); + let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height); let startTime = Date.now(); while (Date.now() - startTime < timeout && !state.cancelRequested) { try { - let template = file.ReadImageMatSync(imagePath); - let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height); gameRegion = captureGameRegion(); let result = gameRegion.find(recognitionObject); if (result.isExist()) { @@ -655,39 +688,47 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo } continue; } - - // 获取 F 图标的中心点 Y 坐标 - let centerYF = fRes.y + fRes.height / 2; - - // 在当前屏幕范围内进行 OCR 识别 - let ocrResults = await performOcr(whitelistKeywords, textxRange, { min: fRes.y - texttolerance, max: fRes.y + fRes.height + texttolerance * 2 }); - - // 检查所有目标文本是否在当前页面中 let foundTarget = false; - for (let ocrResult of ocrResults) { - // 检查是否包含黑名单关键词 - let containsBlacklistKeyword = blacklistKeywords.some(blacklistKeyword => ocrResult.text.includes(blacklistKeyword)); - if (containsBlacklistKeyword) { - continue; - } + // 获取 F 图标的中心点 Y 坐标 + let centerYF = Math.round(fRes.y + fRes.height / 2); + if (settings.pickupMode === "ocr拾取,默认只拾取狗粮和晶蝶") { + // 在当前屏幕范围内进行 OCR 识别 + let ocrResults = await performOcr(whitelistKeywords, textxRange, { min: fRes.y - texttolerance, max: fRes.y + fRes.height + texttolerance * 2 }); - // 计算目标文本的中心Y坐标 - let centerYTargetText = ocrResult.y + ocrResult.height / 2; - if (Math.abs(centerYTargetText - centerYF) <= texttolerance) { - keyPress("F"); // 执行交互操作 - await sleep(trigger); // 操作后暂停 50 毫秒 - foundTarget = true; - - if ((new Date() - lastPickupTime) > 1000 || ocrResult.text != lastPickupItem) { - log.info(`交互或拾取:"${ocrResult.text}"`); - lastPickupTime = new Date(); - lastPickupItem = ocrResult.text; + // 检查所有目标文本是否在当前页面中 + for (let ocrResult of ocrResults) { + // 检查是否包含黑名单关键词 + let containsBlacklistKeyword = blacklistKeywords.some(blacklistKeyword => ocrResult.text.includes(blacklistKeyword)); + if (containsBlacklistKeyword) { + continue; + } + // 计算目标文本的中心Y坐标 + let centerYTargetText = ocrResult.y + ocrResult.height / 2; + if (Math.abs(centerYTargetText - centerYF) <= texttolerance) { + keyPress("F"); // 执行交互操作 + await sleep(2 * trigger); // 操作后暂停 2*trigger 毫秒 + foundTarget = true; + if ((new Date() - lastPickupTime) > 1000 || ocrResult.text != lastPickupItem) { + log.info(`交互或拾取:"${ocrResult.text}"`); + lastPickupTime = new Date(); + lastPickupItem = ocrResult.text; + } + break; } - - break; } - } + } else if (settings.pickupMode === "模板匹配拾取,默认只拾取狗粮") { + let start = new Date(); + let itemName = await performTemplateMatch(centerYF); + let end = new Date(); + //log.info(`调试-匹配用时${end - start}毫秒`) + if (itemName) { + keyPress("F"); // 执行交互操作 + log.info(`交互或拾取:"${itemName}"`); + await sleep(2 * trigger); // 操作后暂停 2*trigger 毫秒 + foundTarget = true; + } + } // 如果在当前页面中没有找到任何目标文本,则根据时间决定滚动方向 if (!foundTarget) { const currentTime = new Date().getTime(); // 获取当前时间(毫秒) @@ -710,6 +751,7 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo // 否则执行下翻 await keyMouseScript.runFile(`assets/滚轮上翻.json`); } + await sleep(Math.round(trigger / 5)); } if (state.cancelRequested) { @@ -832,8 +874,8 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo // 根据条件决定是否启动 OCR 检测和交互任务 let ocrTask = null; - if (pickupMode === "js拾取,默认只拾取狗粮和晶蝶") { - ocrTask = performOcrAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance); + if (pickupMode === "ocr拾取,默认只拾取狗粮和晶蝶" || pickupMode === "模板匹配拾取,默认只拾取狗粮") { + ocrTask = recoginzeAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance); } // 启动泥头车 diff --git a/repo/js/AutoHoeingOneDragon/settings.json b/repo/js/AutoHoeingOneDragon/settings.json index f94bccc4..0a6892a6 100644 --- a/repo/js/AutoHoeingOneDragon/settings.json +++ b/repo/js/AutoHoeingOneDragon/settings.json @@ -32,11 +32,12 @@ "type": "select", "label": "拾取模式", "options": [ - "js拾取,默认只拾取狗粮和晶蝶", + "模板匹配拾取,默认只拾取狗粮", + "ocr拾取,默认只拾取狗粮和晶蝶", "bgi原版拾取", "不拾取任何物品" ], - "default": "js拾取,默认只拾取狗粮和晶蝶" + "default": "模板匹配拾取,默认只拾取狗粮" }, { "name": "trigger", diff --git a/repo/js/ComputerBlower/assets/流放.png b/repo/js/ComputerBlower/assets/流放.png new file mode 100644 index 00000000..5e410171 Binary files /dev/null and b/repo/js/ComputerBlower/assets/流放.png differ diff --git a/repo/js/ComputerBlower/main.js b/repo/js/ComputerBlower/main.js index 35e28500..81c79c74 100644 --- a/repo/js/ComputerBlower/main.js +++ b/repo/js/ComputerBlower/main.js @@ -1,29 +1,79 @@ // 主函数 (async function () { + operationMode = settings.operationMode || "截图"; + const xRange = parseInt(+settings.xRange || 1920, 10); + const yRange = parseInt(+settings.yRange || 1920, 10); let startTime = Date.now(); const interval = +settings.interval || 1000; const timeout = +settings.timeout || 60; let lastCheck = startTime; let ocrcount = 0; let loopCount = 0; - let logCount = 0; - //let store = []; - while (Date.now() - startTime < timeout * 1000) { - loopCount++; - try { - let GameRegion = captureGameRegion(); - // store[loopCount] = GameRegion; - if (settings.dispose) GameRegion.dispose(); - ocrcount++; - } catch (error) { - log.error(`运行时发生异常: ${error.message}`); - break; - } - if (Date.now() - lastCheck >= interval) { - logCount++; - lastCheck = Date.now(); - log.info(`在第${logCount}个${interval}毫秒内执行了${ocrcount}次截图`); - ocrcount = 0; + const imagePath = "assets/流放.png"; + let template = file.ReadImageMatSync(imagePath); + if (operationMode === "截图") { + while (Date.now() - startTime < timeout * 1000) { + try { + let GameRegion = captureGameRegion(); + if (settings.dispose) GameRegion.dispose(); + ocrcount++; + if (Date.now() - lastCheck >= interval) { + loopCount++; + await sleep(1); + lastCheck = Date.now(); + log.info(`在第${loopCount}个${interval}毫秒内执行了${ocrcount}次截图`); + ocrcount = 0; + } + } catch (error) { + log.error(`运行时发生异常: ${error.message}`); + break; + } } } + + if (operationMode === "模板匹配") { + let GameRegion = captureGameRegion(); + while (Date.now() - startTime < timeout * 1000) { + try { + + let recognitionObject = RecognitionObject.TemplateMatch(template, 0, 0, xRange, yRange); + let result = GameRegion.find(recognitionObject); + ocrcount++; + if (Date.now() - lastCheck >= interval) { + loopCount++; + await sleep(1); + lastCheck = Date.now(); + log.info(`在第${loopCount}个${interval}毫秒内执行了${ocrcount}次模板匹配`); + ocrcount = 0; + } + } catch (error) { + log.error(`运行时发生异常: ${error.message}`); + break; + } + } + if (settings.dispose) GameRegion.dispose(); + } + if (operationMode === "ocr") { + let GameRegion = captureGameRegion(); + while (Date.now() - startTime < timeout * 1000) { + try { + let result = GameRegion.findMulti(RecognitionObject.ocr( + 0, 0, + xRange, yRange + )); + ocrcount++; + } catch (error) { + log.error(`运行时发生异常: ${error.message}`); + break; + } + if (Date.now() - lastCheck >= interval) { + loopCount++; + lastCheck = Date.now(); + await sleep(1); + log.info(`在第${loopCount}个${interval}毫秒内执行了${ocrcount}次OCR`); + ocrcount = 0; + } + } + if (settings.dispose) GameRegion.dispose(); + } })(); diff --git a/repo/js/ComputerBlower/manifest.json b/repo/js/ComputerBlower/manifest.json index a9939a6a..04df2649 100644 --- a/repo/js/ComputerBlower/manifest.json +++ b/repo/js/ComputerBlower/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, - "name": "截图性能测试", - "version": "0.1", + "name": "性能测试", + "version": "1.0", "tags": [], "bgi_version": "0.46.0", "description": "测测你的", diff --git a/repo/js/ComputerBlower/settings.json b/repo/js/ComputerBlower/settings.json index 2c25f3ec..ab5545cc 100644 --- a/repo/js/ComputerBlower/settings.json +++ b/repo/js/ComputerBlower/settings.json @@ -1,4 +1,15 @@ [ + { + "name": "operationMode", + "type": "select", + "label": "测试项目", + "options": [ + "截图", + "模板匹配", + "ocr" + ], + "default": "只截图" + }, { "name": "dispose", "type": "checkbox", @@ -15,5 +26,17 @@ "type": "input-text", "label": "间隔多久输出一次(毫秒)", "default": "1000" + }, + { + "name": "xRange", + "type": "input-text", + "label": "区域大小x", + "default": "1920" + }, + { + "name": "yRange", + "type": "input-text", + "label": "区域大小y", + "default": "1080" } ] \ No newline at end of file