diff --git a/repo/js/AutoHoeingOneDragon/main.js b/repo/js/AutoHoeingOneDragon/main.js index 864836111..baafc72e4 100644 --- a/repo/js/AutoHoeingOneDragon/main.js +++ b/repo/js/AutoHoeingOneDragon/main.js @@ -43,16 +43,23 @@ const scrollRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/ //全局通用变量声明 let gameRegion; let targetItems; -let doFurinaSwitch = false; -let lastRoll = new Date(); +let shouldSwitchFurina = false; +let lastRollTime = new Date(); let blacklist = []; let blacklistSet = new Set(); let state; let pathings; -let localeWorks; -let lastEatBuff = 0; +let localeTimeSupported; +let lastBuffTime = 0; let currentFood = ""; let monsterInfoObject; +const gameRegionManager = { + newGameRegion: null, + oldGameRegion: null, + lastCapture: new Date(), + isDisposing: false, + isCapturing: false +}; (async function () { //通用预处理 @@ -65,7 +72,7 @@ let monsterInfoObject; await switchPartyTask; } targetItems = await loadTargetItems(); - localeWorks = await checkLocaleTimeSupport(); + localeTimeSupported = await checkLocaleTimeSupport(); dispatcher.AddTrigger(new RealtimeTimer("AutoSkip")); await loadBlacklist(true); await rotateWarnIfAccountEmpty(); @@ -956,17 +963,17 @@ async function copyPathingsByGroup(pathings) { * - blacklistTask:背包满时OCR识别并拉黑多余物品 * - dumperTask(可选):接近战斗坐标时自动切人放E * 3. 全部子任务完成后返回,state.running 被置 false - * 依赖全局:settings、state、pathings、targetItems、dumpers、doFurinaSwitch、lastEatBuff 等 + * 依赖全局:settings、state、pathings、targetItems、dumpers、shouldSwitchFurina、lastBuffTime 等 */ async function runPath(fullPath, map_name, pm, pe) { //当需要切换芙宁娜形态时,执行一次强制黑芙 - if (doFurinaSwitch) { + if (shouldSwitchFurina) { log.info("上条路线识别到白芙,开始强制切换黑芙") - doFurinaSwitch = false; + shouldSwitchFurina = false; await pathingScript.runFile("assets/强制黑芙.json"); } if (settings.eatBuff) { - if (new Date() - lastEatBuff > 300 * 1000) { + if (new Date() - lastBuffTime > 300 * 1000) { // 1. 数据预处理:分割、去空、去重 let res = settings.eatBuff .split(',') @@ -1009,7 +1016,7 @@ async function runPath(fullPath, map_name, pm, pe) { await findAndClick("assets/使用.png"); } await genshin.returnMainUi(); - lastEatBuff = new Date(); + lastBuffTime = new Date(); } } @@ -1142,10 +1149,10 @@ async function runPath(fullPath, map_name, pm, pe) { } continue; } - if (!doFurinaSwitch) { + if (!shouldSwitchFurina) { if (await findAndClick(whiteFurinaRo, false, 2, 3)) { log.info("检测到白芙,本路线运行结束后切换芙宁娜形态"); - doFurinaSwitch = true; + shouldSwitchFurina = true; continue; } } @@ -1175,8 +1182,7 @@ async function runPath(fullPath, map_name, pm, pe) { let attempts = 0; while (attempts < maxAttempts && state.running) { try { - gameRegion.dispose(); - gameRegion = captureGameRegion(); + gameRegion = await getGameRegion(); const result = gameRegion.find(itemFullRo); if (result.isExist()) { return true; @@ -1304,18 +1310,16 @@ async function recognizeAndInteract() { let lastItemName = ""; let thisMoveUpTime = 0; let lastMoveDown = 0; - gameRegion = captureGameRegion(); let itemName; //主循环 while (state.running) { //log.info("调试-交互拾取进行中"); - gameRegion.dispose(); - gameRegion = captureGameRegion(); + gameRegion = await getGameRegion(); let centerYF = await findFIcon(); if (!centerYF) { - if (new Date() - lastRoll >= 200) { - lastRoll = new Date(); + if (new Date() - lastRollTime >= 200) { + lastRollTime = new Date(); if (await hasScroll()) { await keyMouseScript.runFile(`assets/滚轮下翻.json`); } @@ -1578,13 +1582,9 @@ async function dumper(pathFilePath, map_name) { const maxAttempts = 10; let attempts = 0; - let dodispose = false; while (attempts < maxAttempts && state.running) { try { - if (!gameRegion) { - gameRegion = captureGameRegion(); - dodispose = true; - } + gameRegion = await getGameRegion() let result = gameRegion.find(recognitionObject); if (result.isExist()) { return true; // 如果找到图标,返回 true @@ -1595,9 +1595,6 @@ async function dumper(pathFilePath, map_name) { } attempts++; // 增加尝试次数 await sleep(200); // 每次检测间隔 200 毫秒 - if (dodispose) { - gameRegion.dispose(); - } } return false; // 如果尝试次数达到上限或取消,返回 false } @@ -1811,7 +1808,7 @@ async function processPathingsByGroup(pathings, accountName) { } // 更新路径的 cdTime pathing.cdTime = newCDTime.toLocaleString(); - if (!localeWorks) pathing.cdTime = newCDTime.toISOString(); + if (!localeTimeSupported) pathing.cdTime = newCDTime.toISOString(); await updateRecords(pathings, accountName); } @@ -1824,7 +1821,7 @@ async function processPathingsByGroup(pathings, accountName) { * - 为每条路线赋予 cdTime(本地或UTC)与最近7次运行时长 * - 拾取历史仅保留最后20个不重复项 * 若记录文件缺失则初始化为7条-1 - * 依赖:file、accountName、localeWorks + * 依赖:file、accountName、localeTimeSupported */ async function initializeCdTime(pathings, accountName) { try { @@ -1845,7 +1842,7 @@ async function initializeCdTime(pathings, accountName) { ? new Date(entry.cdTime).toLocaleString() : new Date(0).toLocaleString(); - if (!localeWorks) pathing.cdTime = entry + if (!localeTimeSupported) pathing.cdTime = entry ? new Date(entry.cdTime).toISOString() : new Date(0).toISOString(); // 确保当前 records 是数组 @@ -1867,7 +1864,7 @@ async function initializeCdTime(pathings, accountName) { pathing.cdTime = new Date(0).toLocaleString(); pathing.records = new Array(7).fill(-1); }); - if (!localeWorks) pathings.forEach(pathing => { + if (!localeTimeSupported) pathings.forEach(pathing => { pathing.cdTime = new Date(0).toISOString(); pathing.records = new Array(7).fill(-1); }); @@ -1957,12 +1954,8 @@ async function switchPartyIfNeeded(partyName) { */ async function isMainUI(maxDuration = 10) { const start = Date.now(); - let dodispose = false; while (Date.now() - start < maxDuration) { - if (!gameRegion) { - gameRegion = captureGameRegion(); - dodispose = true; - } + gameRegion = await getGameRegion(); try { const result = gameRegion.find(mainUIRo); if (result.isExist()) return true; @@ -1971,10 +1964,6 @@ async function isMainUI(maxDuration = 10) { return false; // 一旦出现异常直接退出,不再重试 } await sleep(checkDelay); // 识别间隔 - if (dodispose) { - gameRegion.dispose(); - dodispose = false; // 已经释放,标记避免重复 dispose - } } /* 超时仍未识别到,返回失败 */ return false; @@ -1986,12 +1975,8 @@ async function isMainUI(maxDuration = 10) { */ async function hasScroll(maxDuration = 10) { const start = Date.now(); - let dodispose = false; while (Date.now() - start < maxDuration) { - if (!gameRegion) { - gameRegion = captureGameRegion(); - dodispose = true; - } + gameRegion = await getGameRegion(); try { const result = gameRegion.find(scrollRo); if (result.isExist()) return true; @@ -2000,10 +1985,6 @@ async function hasScroll(maxDuration = 10) { return false; // 一旦出现异常直接退出,不再重试 } await sleep(checkDelay); // 识别间隔 - if (dodispose) { - gameRegion.dispose(); - dodispose = false; // 已经释放,标记避免重复 dispose - } } /* 超时仍未识别到,返回失败 */ return false; @@ -2341,25 +2322,21 @@ async function findAndClick(target, let found = null; while (Date.now() - start <= timeout) { - const gameRegion = captureGameRegion(); - try { - // 依次尝试每一个 ro - for (const ro of ros) { - const res = gameRegion.find(ro); - if (!res.isEmpty()) { // 找到 - found = res; - if (doClick) { - await sleep(preClickDelay); - res.click(); - await sleep(postClickDelay); - } - break; // 成功即跳出 for + const gameRegion = await getGameRegion(); + // 依次尝试每一个 ro + for (const ro of ros) { + const res = gameRegion.find(ro); + if (!res.isEmpty()) { // 找到 + found = res; + if (doClick) { + await sleep(preClickDelay); + res.click(); + await sleep(postClickDelay); } + break; // 成功即跳出 for } - if (found) break; // 成功即跳出 while - } finally { - gameRegion.dispose(); } + if (found) break; // 成功即跳出 while await sleep(interval); // 没找到时等待 } @@ -2370,4 +2347,65 @@ async function findAndClick(target, log.error(`执行通用识图时出现错误:${error.message}`); return retType === 0 ? false : null; } +} + +/** + * 获取游戏区域截图,根据时间间隔决定是否重新捕获 + * + * @param {number} [minInterval=17] - 最小截图间隔(毫秒),默认17ms(约60fps) + * @param {boolean} [asyncDispose=false] - 是否异步释放旧截图,默认false + * @returns {Promise} 游戏区域截图对象 + * + * @description + * 使用 gameRegionManager 对象管理以下属性: + * - newGameRegion: 存储最新的游戏区域截图对象 + * - oldGameRegion: 存储上一个游戏区域截图对象,用于资源释放 + * - lastCapture: 上一次捕获游戏区域的时间戳 + * - isDisposing: 标记是否正在释放旧截图,用于安全锁 + * - isCapturing: 标记是否正在执行截图操作,用于全局锁 + */ +async function getGameRegion(minInterval = 17, asyncDispose = false) { + async function disposeOldGameRegion() { + if (gameRegionManager.oldGameRegion) { + gameRegionManager.isDisposing = true; + try { + gameRegionManager.oldGameRegion.dispose(); + } catch (error) { + log.error(`释放旧游戏区域截图失败: ${error.message}`); + } finally { + gameRegionManager.isDisposing = false; + gameRegionManager.oldGameRegion = gameRegionManager.newGameRegion; + } + } else { + gameRegionManager.oldGameRegion = gameRegionManager.newGameRegion; + } + } + + // 等待其他任务完成截图 + while (gameRegionManager.isCapturing) { + await sleep(1); + } + + gameRegionManager.isCapturing = true; + try { + if (new Date() - gameRegionManager.lastCapture >= minInterval || !gameRegionManager.newGameRegion) { + while (gameRegionManager.isDisposing) { + await sleep(1); + } + gameRegionManager.lastCapture = new Date(); + gameRegionManager.newGameRegion = captureGameRegion(); + + // 根据参数决定是否等待释放完成 + if (asyncDispose) { + disposeOldGameRegion(); + } else { + await disposeOldGameRegion(); + } + } + } catch (error) { + log.error(`获取游戏区域截图失败: ${error.message}`); + } finally { + gameRegionManager.isCapturing = false; + return gameRegionManager.newGameRegion; + } } \ No newline at end of file diff --git a/repo/js/AutoHoeingOneDragon/manifest.json b/repo/js/AutoHoeingOneDragon/manifest.json index 9b9d0f767..f838e9069 100644 --- a/repo/js/AutoHoeingOneDragon/manifest.json +++ b/repo/js/AutoHoeingOneDragon/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "锄地一条龙", - "version": "2.6.13", + "version": "2.7.0", "description": "一站式解决自动化锄地,支持只拾取狗粮,请仔细阅读README.md后使用", "authors": [ { diff --git a/repo/js/AutoHoeingOneDragon/pathing/0-传奇/G030挪德卡莱虚海望十六倍曼陀草传奇.json b/repo/js/AutoHoeingOneDragon/pathing/0-传奇/G030挪德卡莱虚海望十六倍曼陀草传奇.json index 20bf0d74c..f0c014b4e 100644 --- a/repo/js/AutoHoeingOneDragon/pathing/0-传奇/G030挪德卡莱虚海望十六倍曼陀草传奇.json +++ b/repo/js/AutoHoeingOneDragon/pathing/0-传奇/G030挪德卡莱虚海望十六倍曼陀草传奇.json @@ -62,15 +62,6 @@ "type": "path", "x": 9666.83203125, "y": 5347.07421875 - }, - { - "action": "", - "action_params": "", - "id": 6, - "move_mode": "walk", - "type": "teleport", - "x": 9364.5771484375, - "y": 1427.001953125 } ] } \ No newline at end of file