From e5386ad2d814ea4580ab429dbe26dab13bf10f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8F=90=E7=93=A6=E7=89=B9=E9=92=93=E9=B1=BC=E7=8E=B3?= =?UTF-8?q?=E5=B8=88?= Date: Mon, 26 Jan 2026 20:50:08 +0800 Subject: [PATCH] =?UTF-8?q?JS=E8=84=9A=E6=9C=AC=EF=BC=9AAutoFishingTeyvat?= =?UTF-8?q?=E3=80=81AutoFishingTeyvat-Bait=E3=80=90=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E3=80=91=20(#2791)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * fix * fix --- repo/js/AutoFishingTeyvat-Bait/README.md | 14 +- repo/js/AutoFishingTeyvat-Bait/main.js | 15 +- repo/js/AutoFishingTeyvat-Bait/manifest.json | 2 +- repo/js/AutoFishingTeyvat/main.js | 222 +++++-------------- repo/js/AutoFishingTeyvat/manifest.json | 2 +- 5 files changed, 81 insertions(+), 174 deletions(-) diff --git a/repo/js/AutoFishingTeyvat-Bait/README.md b/repo/js/AutoFishingTeyvat-Bait/README.md index c179e1aa0..12cb7d99e 100644 --- a/repo/js/AutoFishingTeyvat-Bait/README.md +++ b/repo/js/AutoFishingTeyvat-Bait/README.md @@ -5,20 +5,28 @@ ## 核心功能 ~~1. 自动收集和制作合成鱼饵所需的材料~~ + 2. 自动合成设定的鱼饵,可通过背包识别达到指定数量 + 3. 可选择合成台位置 + 4. 可自行配置鱼饵原材料余量相关的设置 + ~~5. 可通过NPC购买原料(可选)~~ ## 注意事项 **该脚本处于测试阶段,可能出现OCR误差导致的问题** 1. 请确保所选的鱼饵配方已经学习(如果勾选```其他功能```中的```优化OCR(建议启用)```) 2. 请确保鱼饵的原材料数量充足 -~~2. 自动获取的原料有限,在单次原材料CD周期内,通过地图追踪来收集原料合成的饵料数量建议**小于500**~~ -~~3. 小麦目前只能通过购买获取(暂不支持通过调查点获取)~~ -~~4. 如果选择了购买原料,需要保证对应的商人可用(确保已经进行过前置对话,可以直接进入商店)~~ + +~~3. 自动获取的原料有限,在单次原材料CD周期内,通过地图追踪来收集原料合成的饵料数量建议**小于500**~~ + +~~4. 小麦目前只能通过购买获取(暂不支持通过调查点获取)~~ + +~~5. 如果选择了购买原料,需要保证对应的商人可用(确保已经进行过前置对话,可以直接进入商店)~~ ## 其它 脚本反馈群(推荐):BetterGI v7群(1029539994) + 脚本反馈邮箱:hijiwos@hotmail.com \ No newline at end of file diff --git a/repo/js/AutoFishingTeyvat-Bait/main.js b/repo/js/AutoFishingTeyvat-Bait/main.js index 51f73b897..ca25e1694 100644 --- a/repo/js/AutoFishingTeyvat-Bait/main.js +++ b/repo/js/AutoFishingTeyvat-Bait/main.js @@ -1,4 +1,4 @@ -(async function () { // 鱼饵合成上限[]、鱼饵原料数不为2时可能出错[]、NPC的CD记录[] +(async function () { // 鱼饵合成上限[]、鱼饵原料数不为2时可能出错[]、NPC的CD记录[],OCR仍有识别错误的可能性,例如1111识别成11 const bait_list = ["果酿饵", "赤糜饵", "蠕虫假饵", "飞蝇假饵", "甘露饵", "酸桔饵", "维护机关频闪诱饵", "澄晶果粒饵", "温火饵", "槲梭饵", "清白饵"] const material_msg = { @@ -100,7 +100,7 @@ "培根": {"material": {"兽肉": 2, "盐": 2}, "time": 15}, "香肠": {"material": {"兽肉": 3}, "time": 20} } - const accelerator_msg = { + const accelerator_msg = { // s "铁块": 20, "白铁块": 40, "水晶块": 60, @@ -146,7 +146,6 @@ return false; } } - } /** @@ -206,7 +205,7 @@ while (true) { let gameRegion = captureGameRegion(); let barUpSite = gameRegion.Find(barUpRo); - if (barUpSite) { + if (barUpSite.isExist()) { if (barUpSite.y >= 125) { click(1276, 125); await sleep(200); @@ -376,6 +375,7 @@ * @param target 目标字符串 * @param candidates 字符串数组 * @returns {null} + * @see levenshteinDistance */ async function findClosestMatch(target, candidates) { let closest = null; @@ -484,7 +484,7 @@ click(k === 0 ? 1080: 1216, 874); // 点击原料1、2 await sleep(500); let ocr_area = await Ocr(881, 763, 158, 267, true); // 中间 "当前拥有xxx" 部分区域 - if (ocr_area.length !== 0) { + if (ocr_area) { let refer_y; for (let i = 0; i < ocr_area.length; i++) { if (ocr_area[i].text.includes("当前拥有")) { @@ -829,10 +829,11 @@ * @param type 类型 * @param area 国家 * @returns {Promise} 是否成功进入 + * @see enter_store 对话并进入NPC商店,需要确保与NPC对话的F图标存在 */ async function go_and_interact(type, area = "蒙德") { // 返回主界面 - genshin.returnMainUi(); + await genshin.returnMainUi(); if (type === "合成台") { await sleep(500); @@ -845,7 +846,7 @@ await sleep(500); if (path_json["info"]["description"].includes("GCM")) { // 等待到返回主界面 - genshin.returnMainUi(); + await genshin.returnMainUi(); await sleep(500); await keyMouseScript.runFile(`assets/npc/${area}-${type}-GCM.json`); await sleep(500); diff --git a/repo/js/AutoFishingTeyvat-Bait/manifest.json b/repo/js/AutoFishingTeyvat-Bait/manifest.json index 3f22fd976..b1717e5b1 100644 --- a/repo/js/AutoFishingTeyvat-Bait/manifest.json +++ b/repo/js/AutoFishingTeyvat-Bait/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "提瓦特自动饵料机[测试版]", - "version": "1.0.0", + "version": "1.0.1", "bgi_version": "0.55.0", "description": "全自动合成鱼饵(支持自动获取原料)", "authors": [ diff --git a/repo/js/AutoFishingTeyvat/main.js b/repo/js/AutoFishingTeyvat/main.js index ba99616c9..fcd531612 100644 --- a/repo/js/AutoFishingTeyvat/main.js +++ b/repo/js/AutoFishingTeyvat/main.js @@ -239,6 +239,7 @@ /** * 计算垂钓点再次可用的时间戳 * @param {String} status - Daytime或Nighttime + * @param {String} current_cd * @returns {number} 返回垂钓点再次可用的时间戳 * @description * 当前采用的CD计算为基于当前冷却时间对象中的 status 属性,计算并返回三天后(从当天 0 点开始计算)的时间戳。 @@ -826,142 +827,54 @@ const base_other_path = "assets/pathing_others/"; const image_path = "assets/peculiar_pinion.png"; const image_world_path = "assets/peculiar_pinion_world.png"; + let imageExitRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Exit.png")); if (tsurumi_method === "1") { keyPress("B"); - await sleep(2000); + while (!(captureGameRegion().Find(imageExitRo).isExist())) { // [DEBUG] 可能陷入死循环? + await sleep(500); + log.debug("等待直到进入背包界面"); + } + await sleep(500); click(1055, 48); await sleep(1000); let imageRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(image_path), 0, 95, 1278, 883); imageRo.threshold = 0.9; - // // 记录原有快捷更换的4个小道具及装备状态 - // click(positions["quick_change_state"][0], positions["quick_change_state"][1]); - // await sleep(500); - // let ori_gadget_region = captureGameRegion(); - // let ori_gadget = {}; - // let equipped = false; - // - // for (let i = 1; i <=4; i++) { - // const currentBottomRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/bottom_ico.png"), positions[`bottom${i}_pos`][0], positions[`bottom${i}_pos`][1], positions[`bottom${i}_pos`][2], positions[`bottom${i}_pos`][3]); - // const currentEquipRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/current_ico.png"), positions[`bottom${i}_pos`][0], positions[`bottom${i}_pos`][1], positions[`bottom${i}_pos`][2], positions[`bottom${i}_pos`][3]); - // if (!(ori_gadget_region.Find(currentBottomRo).isExist())) { - // ori_gadget[i] = ori_gadget_region.DeriveCrop(positions[`upper${i}_pos`][0], positions[`upper${i}_pos`][1], positions[`upper${i}_pos`][2], positions[`upper${i}_pos`][3]); - // if (ori_gadget_region.Find(currentEquipRo).isExist()) { - // equipped = i; - // } - // - // } else { - // ori_gadget[i] = false; - // } - // } - // await sleep(100); - // click(positions["return_btn"][0], positions["return_btn"][1]); - // await sleep(200); - // 在本页面中寻找奇特的羽毛[DEBUG]下滑使用AEscoffier_chef内的scroll_pages_main修改后实现) let page_state = true; - // while (page_state) { + moveMouseTo(1555, 860); // 移走鼠标,防止干扰识别 + let gadget_region = captureGameRegion(); + let gadget = gadget_region.Find(imageRo); + gadget_region.dispose(); + + // 如果当前页面存在奇特的羽毛 + if (gadget.isExist()) { + gadget.Click(); + await sleep(500); moveMouseTo(1555, 860); // 移走鼠标,防止干扰识别 - let gadget_region = captureGameRegion(); - let gadget = gadget_region.Find(imageRo); - gadget_region.dispose(); - - // 如果当前页面存在奇特的羽毛 - if (gadget.isExist()) { - gadget.Click(); - await sleep(500); - moveMouseTo(1555, 860); // 移走鼠标,防止干扰识别 - let ocrResult = await Ocr(1626, 990, 150, 52); - // 防止卸下奇特的羽毛 - if (ocrResult && ocrResult.text.includes("装备")) { - click(1685, 1018); - } else { - click(1843, 48); - } - await sleep(2500); - // 使用小道具激活垂钓点 - keyPress("Z"); - await sleep(1000); - - // // 恢复原有小道具布局 - // keyPress("B"); - // await sleep(2000); - // click(1055, 48); - // await sleep(1000); - // click(positions["quick_change_state"][0], positions["quick_change_state"][1]); - // // 清除并还原小道具快捷栏 - // for (let i = 1; i <=4; i++) { - // if (ori_gadget[i]) { - // await sleep(200); - // click(positions[`bottom${i}`][0], positions[`bottom${i}`][1]); - // await sleep(200); - // const tempRo = RecognitionObject.TemplateMatch(ori_gadget[i], 0, 95, 1278, 883); - // while (true) { - // const tempRegion = captureGameRegion(); - // let gadget = tempRegion.Find(tempRo); - // tempRegion.dispose(); - // if (gadget.isExist()) { - // gadget.Click(); - // break; - // } else { - // if (!(scroll_pages_main("down", 1))) { - // log.warn(`未找到快捷更换栏原有的${i}号位小道具,已留空...`); - // break; - // } - // } - // } - // } - // } - // await sleep(100); - // click(positions["confirm_btn"][0], positions["confirm_btn"][1]); - // await sleep(200); - // // 装备原先装备的小道具[DEBUG]如果原先未装备小道具或者装备的小道具不位于快捷栏位则装备状态无法还原 - // if (equipped) { - // while (true) { - // const oriEquippedRo = RecognitionObject.TemplateMatch(ori_gadget[equipped], 0, 95, 1278, 883); - // let gameRegion = captureGameRegion(); - // let match_result = gameRegion.Find(oriEquippedRo); - // gameRegion.dispose(); - // if (match_result.isExist()) { - // match_result.Click(); - // await sleep(200); - // let gameRegion = captureGameRegion(); - // let ocr_result = gameRegion.Find(ocrRo); - // gameRegion.dispose(); - // if (ocr_result.isExist() && ocr_result.text === "装备") { - // click(1685, 1018); - // } else { - // click(1843, 48); - // } - // await sleep(500); - // break; - // } else { - // let page_state = scroll_pages_main("down", 1); - // if (page_state === false) { - // log.warn("未找到原先装备的小道具..."); - // await sleep(500); - // click(1843, 48); - // await sleep(500); - // break; - // } - // } - // } - // } - // click(1843, 48); // 关闭背包界面 - // await sleep(1000); - - await pathingScript.runFile(base_other_path + file_name + ".json"); - // break; - } else { - page_state = scroll_pages_main("down", 1); - if (page_state === false) { // [DEBUG]未拥有奇特的羽毛的情况暂未测试(不确定滑到底部未找到是否能触发) - log.warn("未找到小道具:奇特的羽毛,该点位已跳过..."); - } - return false; + let ocrResult = await Ocr(1626, 990, 150, 52); + // 防止卸下奇特的羽毛 + if (ocrResult && ocrResult.text.includes("装备")) { + click(1685, 1018); } - // } + // 返回主界面 + await genshin.returnMainUi(); + await sleep(500); + // 使用小道具激活垂钓点 + keyPress("Z"); + await sleep(1000); + + await pathingScript.runFile(base_other_path + file_name + ".json"); + + } else { + page_state = scroll_pages_main("down", 1); + if (page_state === false) { // [DEBUG]未拥有奇特的羽毛的情况暂未测试(不确定滑到底部未找到是否能触发) + log.warn("未找到小道具:奇特的羽毛,该点位已跳过..."); + } + return false; + } } else { await sleep(1000); keyDown("Z"); @@ -1086,7 +999,7 @@ const is_time_kill = kill_hour !== "无" && kill_minute !== "无"; // 判断是否启用 let time_target = new Date(); - // 获取当前用户UID + // 获取当前用户UID,四种格式,单人未识别:default_user,单人识别,{uid纯数字},多人未识别:default_bgiMultiUser,多人识别:bgiMultiUser_{uid纯数字} let uid = "default_user"; if (fishing_cd && !is_con) { const singleRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/single.png")); @@ -1096,26 +1009,16 @@ genshin.returnMainUi(); await sleep(1000); keyPress("G"); - await sleep(1500); + while (!(captureGameRegion().Find(imageExitRo).isExist())) { // [DEBUG] 可能陷入死循环? + await sleep(500); + log.debug("等待直到进入教程界面"); + } let ocrUid = await Ocr(1679, 1048, 200, 28); - if (ocrUid && ocrUid.text !== "") uid = ocrUid.text; + if (ocrUid && ocrUid.text !== "") uid = ocrUid.text.replace(/\D/g, ''); await genshin.returnMainUi(); - // keyPress("F2"); // 按下F2打开多人模式界面 - // await sleep(1000); - // let ro2 = captureGameRegion(); - // let ocrText = ro2.Find(ocrRoText); // 当前页面OCR - // if (ocrText.isExist() && ocrText.text === "回到单人模式") { - // log.info("当前为多人模式,垂钓点CD统计已失效..."); - // fishing_cd = false; // 多人模式下关闭CD记录功能 - // } - // ro2.dispose(); - // - // await sleep(500); - // keyPress("Escape"); - let mainUiCapture = captureGameRegion(); if (mainUiCapture.Find(singleRo).isExist()) { // 单人模式 log.info(`当前为单人模式,CD统计已启用\n记录标识: ${uid}`); @@ -1153,7 +1056,6 @@ await genshin.returnMainUi; log.info("当前为多人模式且并非房主,垂钓点CD统计将记录1P的CD(不影响单人模式的CD记录)"); - // fishing_cd = false; // 多人模式下关闭CD统计功能 } mainUiCapture.dispose(); } @@ -1197,31 +1099,27 @@ } // 路径详细信息 const path_msg = get_pathing_msg(path_filter[i]); - // try { - let current_msg = `${path_msg["area"]}-${path_msg["detail"]}` - log.info(`当前钓鱼点: ${current_msg}(进度: ${i + 1}/${path_filter.length})`); - // For ABGI only - log.debug(`当前进度:${current_msg}(进度: ${i + 1}/${path_filter.length})`); - if (path_continue === current_msg) { - is_continue = false; - } - // 从选择的点位继续 - if (path_continue !== "无(默认)" && !is_con && is_continue && path_filter.length === path_pathing.length) { - log.info("跳过..."); - continue; - } + let current_msg = `${path_msg["area"]}-${path_msg["detail"]}` + log.info(`当前垂钓点: ${current_msg}(进度: ${i + 1}/${path_filter.length})`); + // For ABGI only + log.debug(`当前进度:${current_msg}(进度: ${i + 1}/${path_filter.length})`); + if (path_continue === current_msg) { + is_continue = false; + } - const run_result = await run_file(path_msg, time_out_throw, time_out_whole, is_con, developer_log, block_gcm, block_fight, block_tsurumi, tsurumi_method, auto_skip, fishing_cd, uid, is_time_kill, time_target, kill_hour, kill_minute); + // 从选择的点位继续 + if (path_continue !== "无(默认)" && !is_con && is_continue && path_filter.length === path_pathing.length) { + log.info("跳过..."); + continue; + } - // 新增:检查 run_file 是否因为到达终止时间而返回特殊标记 - if (run_result === "time_kill") { - return null; // 直接退出整个任务 - } - // } catch (error) { - // const file_name = `${path_msg["area"]}-${path_msg["type"]}-${path_msg["detail"]}`; - // log.info(`路径: ${file_name} 执行时出错,已跳过...\n错误信息: ${error}`) - // } + const run_result = await run_file(path_msg, time_out_throw, time_out_whole, is_con, developer_log, block_gcm, block_fight, block_tsurumi, tsurumi_method, auto_skip, fishing_cd, uid, is_time_kill, time_target, kill_hour, kill_minute); + + // 新增:检查 run_file 是否因为到达终止时间而返回特殊标记 + if (run_result === "time_kill") { + return null; // 直接退出整个任务 + } } } diff --git a/repo/js/AutoFishingTeyvat/manifest.json b/repo/js/AutoFishingTeyvat/manifest.json index 8b9079718..953b9c810 100644 --- a/repo/js/AutoFishingTeyvat/manifest.json +++ b/repo/js/AutoFishingTeyvat/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "提瓦特自动钓鱼(全流程+自选)", - "version": "2.4.1", + "version": "2.4.2", "bgi_version": "0.55.0", "description": "支持自动追踪并垂钓bgi支持的全提瓦特垂钓点", "authors": [