From 4b53d2979560cbe663b2bca9b53e94dfeb797b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BA=81=E5=8A=A8=E7=9A=84=E6=B0=A8=E6=B0=94?= <131591012+zaodonganqi@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:12:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=84=9A=E6=9C=AC=E5=90=8D?= =?UTF-8?q?=E4=B8=8E=E5=BE=AA=E7=8E=AF=E6=AC=A1=E6=95=B0=20(#2455)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/images/华池岩岫.png | Bin .../assets/images/单人挑战.png | Bin .../assets/images/启动.png | Bin .../assets/images/地脉异常.png | Bin .../assets/images/开始挑战.png | Bin .../main.js | 468 +++++++++--------- .../manifest.json | 4 +- .../settings.json | 24 +- 8 files changed, 248 insertions(+), 248 deletions(-) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/assets/images/华池岩岫.png (100%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/assets/images/单人挑战.png (100%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/assets/images/启动.png (100%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/assets/images/地脉异常.png (100%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/assets/images/开始挑战.png (100%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/main.js (96%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/manifest.json (75%) rename repo/js/{纪行周常-15次秘境一条龙 => 纪行周常-10次秘境一条龙}/settings.json (68%) diff --git a/repo/js/纪行周常-15次秘境一条龙/assets/images/华池岩岫.png b/repo/js/纪行周常-10次秘境一条龙/assets/images/华池岩岫.png similarity index 100% rename from repo/js/纪行周常-15次秘境一条龙/assets/images/华池岩岫.png rename to repo/js/纪行周常-10次秘境一条龙/assets/images/华池岩岫.png diff --git a/repo/js/纪行周常-15次秘境一条龙/assets/images/单人挑战.png b/repo/js/纪行周常-10次秘境一条龙/assets/images/单人挑战.png similarity index 100% rename from repo/js/纪行周常-15次秘境一条龙/assets/images/单人挑战.png rename to repo/js/纪行周常-10次秘境一条龙/assets/images/单人挑战.png diff --git a/repo/js/纪行周常-15次秘境一条龙/assets/images/启动.png b/repo/js/纪行周常-10次秘境一条龙/assets/images/启动.png similarity index 100% rename from repo/js/纪行周常-15次秘境一条龙/assets/images/启动.png rename to repo/js/纪行周常-10次秘境一条龙/assets/images/启动.png diff --git a/repo/js/纪行周常-15次秘境一条龙/assets/images/地脉异常.png b/repo/js/纪行周常-10次秘境一条龙/assets/images/地脉异常.png similarity index 100% rename from repo/js/纪行周常-15次秘境一条龙/assets/images/地脉异常.png rename to repo/js/纪行周常-10次秘境一条龙/assets/images/地脉异常.png diff --git a/repo/js/纪行周常-15次秘境一条龙/assets/images/开始挑战.png b/repo/js/纪行周常-10次秘境一条龙/assets/images/开始挑战.png similarity index 100% rename from repo/js/纪行周常-15次秘境一条龙/assets/images/开始挑战.png rename to repo/js/纪行周常-10次秘境一条龙/assets/images/开始挑战.png diff --git a/repo/js/纪行周常-15次秘境一条龙/main.js b/repo/js/纪行周常-10次秘境一条龙/main.js similarity index 96% rename from repo/js/纪行周常-15次秘境一条龙/main.js rename to repo/js/纪行周常-10次秘境一条龙/main.js index 623af17f2..6a0384a8d 100644 --- a/repo/js/纪行周常-15次秘境一条龙/main.js +++ b/repo/js/纪行周常-10次秘境一条龙/main.js @@ -1,234 +1,234 @@ -(async function () { - // 1. 基础设置 - setGameMetrics(1920, 1080, 1); - - // 定义全局变量以便在 finally 中释放 - let mats = {}; - let fightOcrRo = null; // 用于战斗判断的OCR对象 - - try { - // --- 资源加载阶段 --- - log.info("正在加载图片资源..."); - - mats = { - enter: file.readImageMatSync("assets/images/华池岩岫.png"), - solo: file.readImageMatSync("assets/images/单人挑战.png"), - start: file.readImageMatSync("assets/images/开始挑战.png"), - leyline: file.readImageMatSync("assets/images/地脉异常.png"), - activate: file.readImageMatSync("assets/images/启动.png") - }; - - // 模版匹配对象 - const ro = { - enter: RecognitionObject.TemplateMatch(mats.enter), - solo: RecognitionObject.TemplateMatch(mats.solo), - start: RecognitionObject.TemplateMatch(mats.start), - leyline: RecognitionObject.TemplateMatch(mats.leyline), - activate: RecognitionObject.TemplateMatch(mats.activate) - }; - - // --- 照搬 123.js 的 OCR 对象逻辑 --- - // 识别全屏范围 - fightOcrRo = RecognitionObject.Ocr(0, 0, genshin.width, genshin.height); - - log.info("资源加载完成"); - - // 2. 准备工作 - await genshin.returnMainUi(); - if (settings.partyName) { - await genshin.switchParty(settings.partyName); - } - - // 3. 循环逻辑 - const maxAttempts = settings.loopTimes || 15; - let successCount = 0; - - for (let i = 0; i < maxAttempts; i++) { - log.info(`=== 开始第 ${i + 1}/${maxAttempts} 次循环 ===`); - - // a. 传送 - await genshin.tp("1436.2861328125", "1289.95556640625"); - await sleep(2500); - - // b. 寻找秘境入口 - log.info("寻找秘境入口..."); - keyDown("w"); - const foundEnter = await waitFindTemplate(ro.enter, 3000); - keyUp("w"); - - if (!foundEnter) { - log.warn("未找到秘境入口,重置位置"); - await genshin.returnMainUi(); - continue; - } - - log.info("找到入口"); - keyPress("f"); - await sleep(1500); - - // c. 点击单人挑战 - if (!await waitAndClickTemplate(ro.solo, 5000)) { - log.error("未找到'单人挑战',重试"); - continue; - } - await sleep(1000); - - // d. 点击开始挑战 - if (!await waitAndClickTemplate(ro.start, 5000)) { - log.error("未找到'开始挑战'"); - continue; - } - log.info("进入加载..."); - await sleep(5000); // 强制等待读条开始 - - // e. 确认进入副本并点击 (检测地脉异常) - // 123.js 原逻辑是找到就点,这里保持一致,作为判断进本的依据 - if (await waitAndClickTemplate(ro.leyline, 120000)) { - log.info("已确认进入副本"); - await sleep(1500); - } else { - log.error("进入副本超时"); - break; - } - - // f. 走向钥匙并启动 - log.info("走向启动钥匙..."); - keyDown("w"); - const foundActivate = await waitFindTemplate(ro.activate, 10000); - keyUp("w"); - - if (foundActivate) { - log.info("找到启动,开始战斗"); - keyPress("f"); - await sleep(1000); - - // g. === 自动战斗 (完全复刻 123.js 的逻辑) === - // 使用 SoloTask("AutoFight") + CancellationToken + 循环OCR检测 - const fightResult = await autoFightLike123js(fightOcrRo, 120000); - - if (fightResult) { - successCount++; - log.info(`战斗成功!当前完成 ${successCount} 次`); - await sleep(2000); - } else { - log.error("战斗失败,终止脚本"); - break; - } - - } else { - log.error("未找到启动钥匙"); - } - } - - await genshin.tp("1436.2861328125", "1289.95556640625"); - log.info(`脚本结束。成功完成 ${successCount}/${maxAttempts} 次挑战`); - - } catch (e) { - log.error("脚本运行出错: " + e.message); - } finally { - // --- 资源释放 (保持内存安全) --- - for (let key in mats) { - if (mats[key]) mats[key].Dispose(); - } - if (fightOcrRo && fightOcrRo.Dispose) { - fightOcrRo.Dispose(); - } - log.info("资源已释放"); - } - - // ================= 辅助函数 ================= - - /** - * 1. 启动 AutoFight 任务 - * 2. 循环截图 OCR - * 3. 识别关键字 ["挑战成功", "达成", "挑战达成"] - * 4. 识别成功后取消任务 - */ - async function autoFightLike123js(ocrRo, timeout) { - const cts = new CancellationTokenSource(); - // 启动后台战斗任务 - dispatcher.runTask(new SoloTask("AutoFight"), cts); - - const startTime = Date.now(); - let fightResult = false; - - log.info("战斗开始"); - - while (Date.now() - startTime < timeout) { - // 获取截图 (注意:这里增加了Dispose以防止内存溢出,逻辑与123.js一致) - let capture = captureGameRegion(); - try { - // 使用传入的 ocrRo 进行查找 - let result = capture.find(ocrRo); - let text = result.text; - - // 123.js 的判断关键字 - const keywords = ["挑战成功", "达成", "挑战达成"]; - let found = false; - - for (const keyword of keywords) { - if (text.includes(keyword)) { - found = true; - break; - } - } - - if (found) { - fightResult = true; - break; - } - } catch (err) { - log.error(`OCR识别出错: ${err}`); - } finally { - // 123.js 缺少这一步,这里加上以保证长时间挂机不崩 - capture.Dispose(); - } - - await sleep(1000); // 123.js 的间隔是 1000ms - } - - // 停止战斗 - cts.cancel(); - return fightResult; - } - - // 模版点击辅助函数 (内存安全版) - async function waitAndClickTemplate(ro, timeoutMs) { - const start = Date.now(); - while (Date.now() - start < timeoutMs) { - let capture = captureGameRegion(); - try { - let res = capture.find(ro); - if (!res.isEmpty()) { - res.click(); - // 123.js 的逻辑是点两下,这里保留双击逻辑以防万一 - await sleep(30); - res.click(); - return true; - } - } finally { - capture.Dispose(); - } - await sleep(1000); // 123.js 默认间隔较长,这里稍微对齐 - } - return false; - } - - // 模版查找辅助函数 (内存安全版) - async function waitFindTemplate(ro, timeoutMs, intervalMs = 200) { - const start = Date.now(); - while (Date.now() - start < timeoutMs) { - let capture = captureGameRegion(); - try { - let res = capture.find(ro); - if (!res.isEmpty()) return true; - } finally { - capture.Dispose(); - } - await sleep(intervalMs); - } - return false; - } - - -})(); +(async function () { + // 1. 基础设置 + setGameMetrics(1920, 1080, 1); + + // 定义全局变量以便在 finally 中释放 + let mats = {}; + let fightOcrRo = null; // 用于战斗判断的OCR对象 + + try { + // --- 资源加载阶段 --- + log.info("正在加载图片资源..."); + + mats = { + enter: file.readImageMatSync("assets/images/华池岩岫.png"), + solo: file.readImageMatSync("assets/images/单人挑战.png"), + start: file.readImageMatSync("assets/images/开始挑战.png"), + leyline: file.readImageMatSync("assets/images/地脉异常.png"), + activate: file.readImageMatSync("assets/images/启动.png") + }; + + // 模版匹配对象 + const ro = { + enter: RecognitionObject.TemplateMatch(mats.enter), + solo: RecognitionObject.TemplateMatch(mats.solo), + start: RecognitionObject.TemplateMatch(mats.start), + leyline: RecognitionObject.TemplateMatch(mats.leyline), + activate: RecognitionObject.TemplateMatch(mats.activate) + }; + + // --- 照搬 123.js 的 OCR 对象逻辑 --- + // 识别全屏范围 + fightOcrRo = RecognitionObject.Ocr(0, 0, genshin.width, genshin.height); + + log.info("资源加载完成"); + + // 2. 准备工作 + await genshin.returnMainUi(); + if (settings.partyName) { + await genshin.switchParty(settings.partyName); + } + + // 3. 循环逻辑 + const maxAttempts = settings.loopTimes || 10; + let successCount = 0; + + for (let i = 0; i < maxAttempts; i++) { + log.info(`=== 开始第 ${i + 1}/${maxAttempts} 次循环 ===`); + + // a. 传送 + await genshin.tp("1436.2861328125", "1289.95556640625"); + await sleep(2500); + + // b. 寻找秘境入口 + log.info("寻找秘境入口..."); + keyDown("w"); + const foundEnter = await waitFindTemplate(ro.enter, 3000); + keyUp("w"); + + if (!foundEnter) { + log.warn("未找到秘境入口,重置位置"); + await genshin.returnMainUi(); + continue; + } + + log.info("找到入口"); + keyPress("f"); + await sleep(1500); + + // c. 点击单人挑战 + if (!await waitAndClickTemplate(ro.solo, 5000)) { + log.error("未找到'单人挑战',重试"); + continue; + } + await sleep(1000); + + // d. 点击开始挑战 + if (!await waitAndClickTemplate(ro.start, 5000)) { + log.error("未找到'开始挑战'"); + continue; + } + log.info("进入加载..."); + await sleep(5000); // 强制等待读条开始 + + // e. 确认进入副本并点击 (检测地脉异常) + // 123.js 原逻辑是找到就点,这里保持一致,作为判断进本的依据 + if (await waitAndClickTemplate(ro.leyline, 120000)) { + log.info("已确认进入副本"); + await sleep(1500); + } else { + log.error("进入副本超时"); + break; + } + + // f. 走向钥匙并启动 + log.info("走向启动钥匙..."); + keyDown("w"); + const foundActivate = await waitFindTemplate(ro.activate, 10000); + keyUp("w"); + + if (foundActivate) { + log.info("找到启动,开始战斗"); + keyPress("f"); + await sleep(1000); + + // g. === 自动战斗 (完全复刻 123.js 的逻辑) === + // 使用 SoloTask("AutoFight") + CancellationToken + 循环OCR检测 + const fightResult = await autoFightLike123js(fightOcrRo, 120000); + + if (fightResult) { + successCount++; + log.info(`战斗成功!当前完成 ${successCount} 次`); + await sleep(2000); + } else { + log.error("战斗失败,终止脚本"); + break; + } + + } else { + log.error("未找到启动钥匙"); + } + } + + await genshin.tp("1436.2861328125", "1289.95556640625"); + log.info(`脚本结束。成功完成 ${successCount}/${maxAttempts} 次挑战`); + + } catch (e) { + log.error("脚本运行出错: " + e.message); + } finally { + // --- 资源释放 (保持内存安全) --- + for (let key in mats) { + if (mats[key]) mats[key].Dispose(); + } + if (fightOcrRo && fightOcrRo.Dispose) { + fightOcrRo.Dispose(); + } + log.info("资源已释放"); + } + + // ================= 辅助函数 ================= + + /** + * 1. 启动 AutoFight 任务 + * 2. 循环截图 OCR + * 3. 识别关键字 ["挑战成功", "达成", "挑战达成"] + * 4. 识别成功后取消任务 + */ + async function autoFightLike123js(ocrRo, timeout) { + const cts = new CancellationTokenSource(); + // 启动后台战斗任务 + dispatcher.runTask(new SoloTask("AutoFight"), cts); + + const startTime = Date.now(); + let fightResult = false; + + log.info("战斗开始"); + + while (Date.now() - startTime < timeout) { + // 获取截图 (注意:这里增加了Dispose以防止内存溢出,逻辑与123.js一致) + let capture = captureGameRegion(); + try { + // 使用传入的 ocrRo 进行查找 + let result = capture.find(ocrRo); + let text = result.text; + + // 123.js 的判断关键字 + const keywords = ["挑战成功", "达成", "挑战达成"]; + let found = false; + + for (const keyword of keywords) { + if (text.includes(keyword)) { + found = true; + break; + } + } + + if (found) { + fightResult = true; + break; + } + } catch (err) { + log.error(`OCR识别出错: ${err}`); + } finally { + // 123.js 缺少这一步,这里加上以保证长时间挂机不崩 + capture.Dispose(); + } + + await sleep(1000); // 123.js 的间隔是 1000ms + } + + // 停止战斗 + cts.cancel(); + return fightResult; + } + + // 模版点击辅助函数 (内存安全版) + async function waitAndClickTemplate(ro, timeoutMs) { + const start = Date.now(); + while (Date.now() - start < timeoutMs) { + let capture = captureGameRegion(); + try { + let res = capture.find(ro); + if (!res.isEmpty()) { + res.click(); + // 123.js 的逻辑是点两下,这里保留双击逻辑以防万一 + await sleep(30); + res.click(); + return true; + } + } finally { + capture.Dispose(); + } + await sleep(1000); // 123.js 默认间隔较长,这里稍微对齐 + } + return false; + } + + // 模版查找辅助函数 (内存安全版) + async function waitFindTemplate(ro, timeoutMs, intervalMs = 200) { + const start = Date.now(); + while (Date.now() - start < timeoutMs) { + let capture = captureGameRegion(); + try { + let res = capture.find(ro); + if (!res.isEmpty()) return true; + } finally { + capture.Dispose(); + } + await sleep(intervalMs); + } + return false; + } + + +})(); diff --git a/repo/js/纪行周常-15次秘境一条龙/manifest.json b/repo/js/纪行周常-10次秘境一条龙/manifest.json similarity index 75% rename from repo/js/纪行周常-15次秘境一条龙/manifest.json rename to repo/js/纪行周常-10次秘境一条龙/manifest.json index 00ceab1e7..d38703d22 100644 --- a/repo/js/纪行周常-15次秘境一条龙/manifest.json +++ b/repo/js/纪行周常-10次秘境一条龙/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, - "name": "纪行周常-15次秘境一条龙", - "version": "1.2", + "name": "纪行周常-10次秘境一条龙", + "version": "1.3", "description": "", "authors": [ { diff --git a/repo/js/纪行周常-15次秘境一条龙/settings.json b/repo/js/纪行周常-10次秘境一条龙/settings.json similarity index 68% rename from repo/js/纪行周常-15次秘境一条龙/settings.json rename to repo/js/纪行周常-10次秘境一条龙/settings.json index 17aee0cc9..18714e2d7 100644 --- a/repo/js/纪行周常-15次秘境一条龙/settings.json +++ b/repo/js/纪行周常-10次秘境一条龙/settings.json @@ -1,13 +1,13 @@ -[ - { - "name": "partyName", - "type": "input-text", - "label": "队伍名称(默认不切换)" - }, - { - "name": "loopTimes", - "type": "input-text", - "label": "刷取次数(默认15次)", - "default": "15" - } +[ + { + "name": "partyName", + "type": "input-text", + "label": "队伍名称(默认不切换)" + }, + { + "name": "loopTimes", + "type": "input-text", + "label": "刷取次数(默认10次)", + "default": "10" + } ] \ No newline at end of file