From dbb82b55605877221d495199549c00d7e72364ce Mon Sep 17 00:00:00 2001 From: JJMdzh Date: Thu, 19 Jun 2025 14:14:14 +0800 Subject: [PATCH] =?UTF-8?q?js,=E7=8B=97=E7=B2=AEABE=E8=B7=AF=E7=BA=BF?= =?UTF-8?q?=EF=BC=8C=E6=96=AD=E7=82=B9=E7=BB=AD=E8=B7=91=20(#1023)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 狗粮ABE路线,断点续跑。需手动启用断点续跑 --- repo/js/AutoArtifacts_A_B_Extra/main.js | 463 +++++++++++------- repo/js/AutoArtifacts_A_B_Extra/settings.json | 9 + 2 files changed, 296 insertions(+), 176 deletions(-) diff --git a/repo/js/AutoArtifacts_A_B_Extra/main.js b/repo/js/AutoArtifacts_A_B_Extra/main.js index 8be4be78..1f1de9c2 100644 --- a/repo/js/AutoArtifacts_A_B_Extra/main.js +++ b/repo/js/AutoArtifacts_A_B_Extra/main.js @@ -1,81 +1,80 @@ -(async function () { - const folderA = 'assets/狗粮A线@Yang-z/'; - const folderB = 'assets/狗粮B线@Yang-z/'; - const folderE = 'assets/狗粮额外@Yang-z/'; +const folderA = 'assets/狗粮A线@Yang-z/'; +const folderB = 'assets/狗粮B线@Yang-z/'; +const folderE = 'assets/狗粮额外@Yang-z/'; - const pathingA = [ - "狗粮-蒙德-龙脊雪山-西-3个-f.json", - "狗粮-璃月-碧水源-盐中之地-3个-f.json", - "狗粮-璃月-珉林-东北-9个-f.json", - "狗粮-璃月-珉林-北-5个.json", - "狗粮-璃月-珉林-奥藏山南-2个/3个-f.json", - "狗粮-璃月-珉林-绝云间-3个-m.json", - "(恢复)狗粮-璃月-琼玑野.json", - "狗粮-璃月-琼玑野-绿华池-3个-f.json", - "狗粮-须弥-须弥城-4个.json", - "狗粮-须弥-二净甸-七天神像-4个/8个.json", - "狗粮-须弥-二净甸-觉王之殿南-6个/7个-f.json", - "(恢复)狗粮-须弥-失落的苗圃.json", - "狗粮-须弥-失落的苗圃-南-8个-f.json", - "狗粮-纳塔-万火之瓯-竞技场东-2个/4个-f.json", - "狗粮-纳塔-涌流地-流泉之众-4个.json", - "(恢复)狗粮-纳塔-涌流地.json", - "狗粮-纳塔-镜璧山-南-9个-f.json", - "狗粮-纳塔-镜璧山-七天神像下-3个-f.json", - "狗粮-纳塔-翘枝崖-北-6个-f.json", - "狗粮-纳塔-奥奇卡纳塔-七天神像-14个.json", - "狗粮-纳塔-奥奇卡纳塔-流灰之街-4个-f.json", - "狗粮-纳塔-奥奇卡纳塔-托佐兹之岛-6个-f.json", - "(恢复)狗粮-稻妻-神无冢.json", - "【收尾】狗粮-稻妻-神无冢-踏鞴砂①-6个/21个-f.json", - "【收尾】狗粮-稻妻-神无冢-踏鞴砂②-7个/21个-f.json", - "【收尾】狗粮-稻妻-神无冢-踏鞴砂③-8个/21个-f.json" - ]; // 98+21个 +const pathingA = [ + "狗粮-蒙德-龙脊雪山-西-3个-f.json", + "狗粮-璃月-碧水源-盐中之地-3个-f.json", + "狗粮-璃月-珉林-东北-9个-f.json", + "狗粮-璃月-珉林-北-5个.json", + "狗粮-璃月-珉林-奥藏山南-2个/3个-f.json", + "狗粮-璃月-珉林-绝云间-3个-m.json", + "(恢复)狗粮-璃月-琼玑野.json", + "狗粮-璃月-琼玑野-绿华池-3个-f.json", + "狗粮-须弥-须弥城-4个.json", + "狗粮-须弥-二净甸-七天神像-4个/8个.json", + "狗粮-须弥-二净甸-觉王之殿南-6个/7个-f.json", + "(恢复)狗粮-须弥-失落的苗圃.json", + "狗粮-须弥-失落的苗圃-南-8个-f.json", + "狗粮-纳塔-万火之瓯-竞技场东-2个/4个-f.json", + "狗粮-纳塔-涌流地-流泉之众-4个.json", + "(恢复)狗粮-纳塔-涌流地.json", + "狗粮-纳塔-镜璧山-南-9个-f.json", + "狗粮-纳塔-镜璧山-七天神像下-3个-f.json", + "狗粮-纳塔-翘枝崖-北-6个-f.json", + "狗粮-纳塔-奥奇卡纳塔-七天神像-14个.json", + "狗粮-纳塔-奥奇卡纳塔-流灰之街-4个-f.json", + "狗粮-纳塔-奥奇卡纳塔-托佐兹之岛-6个-f.json", + "(恢复)狗粮-稻妻-神无冢.json", + "【收尾】狗粮-稻妻-神无冢-踏鞴砂①-6个/21个-f.json", + "【收尾】狗粮-稻妻-神无冢-踏鞴砂②-7个/21个-f.json", + "【收尾】狗粮-稻妻-神无冢-踏鞴砂③-8个/21个-f.json" +]; // 98+21个 - const pathingB = [ - "狗粮-枫丹-枫丹庭区-3个.json", - "狗粮-枫丹-白露区-秋分山东侧-2个-f~m.json", - "狗粮-枫丹-伊黎耶林区-欧庇克莱歌剧院东南-2个-f.json", - "(恢复)狗粮-枫丹-研究院区.json", - "狗粮-枫丹-研究院区-学术会堂-1个/2个-f.json", - "狗粮-枫丹-研究院区-中央实验室遗址-北侧屋内-4个.json", - "狗粮-枫丹-研究院区-新枫丹科学院-东南侧-8个-f.json", - "狗粮-枫丹-研究院区-西南偏南-6个-m-f.json", - "狗粮-枫丹-研究院区-西南偏西-4个-f.json", - "狗粮-枫丹-研究院区-西北-6个/7个.json", - "狗粮-枫丹-研究院区-中部塔内-9个.json", - "(恢复)狗粮-枫丹-黎翡区.json", - "狗粮-枫丹-黎翡区-七天神像-3个/5个.json", - "狗粮-枫丹-黎翡区-芒索斯山东-3个-f.json", - "狗粮-稻妻-神无冢-堇色之庭-4个.json", - "狗粮-稻妻-神无冢-九条阵屋-2个/3个-f.json", - "狗粮-稻妻-神无冢-东-5个/6个-f.json", - "(恢复)狗粮-稻妻-神无冢.json", - "狗粮-稻妻-海祇岛-东方小岛-2个-f.json", - "狗粮-稻妻-海祇岛-珊瑚宫东北-6个-f.json", - "狗粮-稻妻-海祇岛-望泷村西南-4个-f.json", - "狗粮-稻妻-清籁岛-浅濑神社-3个-f.json", - "狗粮-稻妻-清籁岛-越石村-8个-f.json", - "狗粮-稻妻-清籁岛-平海砦西-8个-f.json", - "狗粮-稻妻-鹤观-东偏中-2个-f.json", - "狗粮-稻妻-鹤观-南-2个-f.json", - "(恢复)狗粮-稻妻-清籁岛.json", - "【收尾】狗粮-稻妻-清籁岛-清籁丸-20个-f.json" - ]; // 97+20个 +const pathingB = [ + "狗粮-枫丹-枫丹庭区-3个.json", + "狗粮-枫丹-白露区-秋分山东侧-2个-f~m.json", + "狗粮-枫丹-伊黎耶林区-欧庇克莱歌剧院东南-2个-f.json", + "(恢复)狗粮-枫丹-研究院区.json", + "狗粮-枫丹-研究院区-学术会堂-1个/2个-f.json", + "狗粮-枫丹-研究院区-中央实验室遗址-北侧屋内-4个.json", + "狗粮-枫丹-研究院区-新枫丹科学院-东南侧-8个-f.json", + "狗粮-枫丹-研究院区-西南偏南-6个-m-f.json", + "狗粮-枫丹-研究院区-西南偏西-4个-f.json", + "狗粮-枫丹-研究院区-西北-6个/7个.json", + "狗粮-枫丹-研究院区-中部塔内-9个.json", + "(恢复)狗粮-枫丹-黎翡区.json", + "狗粮-枫丹-黎翡区-七天神像-3个/5个.json", + "狗粮-枫丹-黎翡区-芒索斯山东-3个-f.json", + "狗粮-稻妻-神无冢-堇色之庭-4个.json", + "狗粮-稻妻-神无冢-九条阵屋-2个/3个-f.json", + "狗粮-稻妻-神无冢-东-5个/6个-f.json", + "(恢复)狗粮-稻妻-神无冢.json", + "狗粮-稻妻-海祇岛-东方小岛-2个-f.json", + "狗粮-稻妻-海祇岛-珊瑚宫东北-6个-f.json", + "狗粮-稻妻-海祇岛-望泷村西南-4个-f.json", + "狗粮-稻妻-清籁岛-浅濑神社-3个-f.json", + "狗粮-稻妻-清籁岛-越石村-8个-f.json", + "狗粮-稻妻-清籁岛-平海砦西-8个-f.json", + "狗粮-稻妻-鹤观-东偏中-2个-f.json", + "狗粮-稻妻-鹤观-南-2个-f.json", + "(恢复)狗粮-稻妻-清籁岛.json", + "【收尾】狗粮-稻妻-清籁岛-清籁丸-20个-f.json" +]; // 97+20个 - const pathingE = [ - "【额外】狗粮-纳塔-鸡屁股+8个/9个-f.json", // 12小时刷新 - ]; // 7个 +const pathingE = [ + "【额外】狗粮-纳塔-鸡屁股+8个/9个-f.json", // 12小时刷新 +]; // 7个 - const pathingE_A = [ - "【额外】狗粮-须弥-水天丛林+7个-f.json", // 24小时刷新 - "【额外】狗粮-枫丹-研究院区-新枫丹科学院周边+3个-f.json", // 24小时刷新 - ]; // 10个 +const pathingE_A = [ + "【额外】狗粮-须弥-水天丛林+7个-f.json", // 24小时刷新 + "【额外】狗粮-枫丹-研究院区-新枫丹科学院周边+3个-f.json", // 24小时刷新 +]; // 10个 - const pathingE_B = [ - "【额外】狗粮-纳塔-灵谜纹+13个.json" // 24小时刷新 - ]; // 13个 +const pathingE_B = [ + "【额外】狗粮-纳塔-灵谜纹+13个.json" // 24小时刷新 +]; // 13个 // 每日拾取点位数及耗时 // A: (98 + 21) + (8 + 10) = 137 ~ 31 + 10 = 41 minutes @@ -91,35 +90,49 @@ let autoSalvage4 = settings.autoSalvage4 != undefined && settings.autoSalvage4 != '否' ? true : false; let autoSalvageSpan = settings.autoSalvageSpan != undefined && ~~settings.autoSalvageSpan > 0 ? ~~settings.autoSalvageSpan : 10; let activeRestore = settings.activeRestore != undefined && settings.activeRestore != '是' ? false : true; + const activeProgress = settings.activeProgress != undefined && settings.activeProgress != '否' ? true : false; log.debug(`path: ${path}; swapPath: ${swapPath}; extra: ${extra}; extraAB: ${extraAB}; autoSalvage: ${autoSalvage}; autoSalvage4: ${autoSalvage4}; autoSalvageSpan: ${autoSalvageSpan}; activeRestore: ${activeRestore};`); // await sleep(30000); - // 路线 - function determinePath() { - if (path != 'A' && path != 'B') { - const benchmark = new Date("2024-11-20T04:00:00"); - const now = new Date(); - const delta = now - benchmark; - const days = delta / (1000 * 60 * 60 * 24); - path = days % 2 < 1 ? 'A' : 'B'; +// 确定路径 +function determinePath() { + if (path != 'A' && path != 'B') { + const benchmark = new Date("2024-11-20T04:00:00"); + const now = new Date(); + const delta = now - benchmark; + const days = delta / (1000 * 60 * 60 * 24); + path = days % 2 < 1 ? 'A' : 'B'; - if (swapPath) path = path == 'A' ? 'B' : 'A'; - } + if (swapPath) path = path == 'A' ? 'B' : 'A'; } - // 初始化 - async function init(shouldRestore = true, shouldResizeMap = false) { - // close forced interaction just in case.. - dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": false })); - - // restore and alignment - if (shouldRestore) await genshin.tp("1468.0732421875", "1998.04443359375"); await sleep(3000); - - // resize map here (not necessary after bgi v0.41.0) - if (shouldResizeMap) await resizeMap(); + // 如果路径切换,清理与当前路径无关的任务记录 + if (progress.path !== path) { + progress.completedTasks = []; + progress.path = path; + saveProgress(); // 保存新的路径和清理后的任务记录 } +} + + +// 初始化函数 +async function init(shouldRestore = true, shouldResizeMap = false) { + // 关闭强制交互 + dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": false })); + + // 恢复和对齐 + if (shouldRestore) { + await genshin.tp("1468.0732421875", "1998.04443359375"); + await sleep(3000); + } + + // 调整地图缩放 (bgi[v0.41.0]后不需要) + if (shouldResizeMap) { + await resizeMap(); + } +} // 调整地图 async function resizeMap(level = 1) { @@ -166,110 +179,208 @@ await genshin.tp(data['positions'][0]['x'], data['positions'][0]['y']); } - // 分解圣遗物 - async function salvage() { - if (!autoSalvage) return; +// 分解圣遗物 +async function salvage() { + if (!autoSalvage) return; + await genshin.returnMainUi(); + keyPress("B"); + await sleep(2000); + click(670, 40); + await sleep(1000); // 圣遗物 + click(660, 1010); + await sleep(1000); // 分解 + click(300, 1020); + await sleep(1000); // 快速选择 - await genshin.returnMainUi(); - - keyPress("B"); await sleep(2000); - click(670, 40); await sleep(1000); // 圣遗物 - click(660, 1010); await sleep(1000); // 分解 - click(300, 1020); await sleep(1000); // 快速选择 - - // click(200, 140); await sleep(500); // 1 - // click(200, 220); await sleep(500); // 2 - // click(200, 300); await sleep(500); // 3 - if (!autoSalvage4) { click(200, 380); await sleep(500); } // 4 - - click(340, 1000); await sleep(1000); // 确认选择 - click(1720, 1015); await sleep(1500); // 分解 - click(1180, 750); await sleep(1000); // 进行分解 - - click(1840, 45); await sleep(1500); // 取消 - click(1840, 45); await sleep(1000); // 取消 - click(1840, 45); await sleep(1000); // 取消 + // 点击4星圣遗物 + if (!autoSalvage4) { + click(200, 380); + await sleep(500); } - // 单一脚本执行 - let count = 0; - async function runFile(filePath, times = 2) { - try { - --times; + click(340, 1000); + await sleep(1000); // 确认选择 + click(1720, 1015); + await sleep(1500); // 分解 + click(1320, 750); + await sleep(1000); // 进行分解 - // 如关闭主动去神像恢复,则依赖队伍配置持续恢复角色,及bgi的低血量被动恢复 - let isToRestore = filePath.search("(恢复)") != -1; - if (isToRestore && !activeRestore) return; + await genshin.returnMainUi(); +} - // 暂不支持关闭自动拾取 - // if (isToRestore) dispatcher.removeTimer(...); - // else... +// 进度文件路径 +const progressFile = "progress.json"; - // 分解圣遗物 - if (!isToRestore && count++ % autoSalvageSpan == 0) await salvage(); +// 初始化进度 +let progress = { + path: null, + completedTasks: [], + lastRunDate: null // 记录上次运行的日期 +}; - // 调整地图缩放 (bgi[v0.41.0]后不需要) - // let shouldResizeMap = filePath.search("-m") != -1; - // if (shouldResizeMap) await resizeMap(); +// 读取进度 +async function loadProgress() { + try { + const content = await file.readText(progressFile); + const loadedProgress = JSON.parse(content); - // 配置自动拾取,根据文件名指定信息,确定是否强制交互(快速拾取) - let forceInteraction = filePath.search("-f") != -1; // - if (!isToRestore) dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": forceInteraction })); - - //执行路径追踪脚本 - log.info(filePath); - await pathingScript.runFile(filePath); - - // 配置强制拾取为关闭状态 - dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": false })); - - // 地图缩放按键同某些地图标识重叠,导致识别失败(bgi[v0.43.0]后引入) - // // 完成路径后,放大地图,脚本中调用就近传送。仍可能被缩小回去。不可行 - // let shouldResizeMap_after = filePath.search("~m") != -1; - // if (shouldResizeMap_after) { - // await resizeMap(0); - // await tpNearby(filePath); - // } - // 完成路径后,拖拽地图,脚本中调用就近传送。可行 - let shouldDragMap_after = filePath.search("~m") != -1; - if (shouldDragMap_after) { - await dragMap(-50, 50); - await tpNearby(filePath); - } + // 检查日期是否一致 + const now = new Date(); + const today = now.toISOString().split('T')[0]; // 当前日期(YYYY-MM-DD) + const lastRunDate = loadedProgress.lastRunDate; + if (lastRunDate && lastRunDate === today) { + // 如果日期一致,加载进度 + progress.path = loadedProgress.path; + progress.completedTasks = Array.isArray(loadedProgress.completedTasks) ? loadedProgress.completedTasks : []; + } else { + // 如果日期不一致,重置进度 + progress.path = null; + progress.completedTasks = []; } - catch (error) { // bgi已捕获可预期异常,此处仅做兜底 - log.error(error.toString()); - await sleep(3000); - if (times > 0) await runFile(filePath, times); + + progress.lastRunDate = today; // 更新当前日期 + log.info("加载进度成功:", progress); + } catch (error) { + log.error("加载进度失败:", error); + } +} + +// 保存进度 +async function saveProgress() { + try { + progress.lastRunDate = new Date().toISOString().split('T')[0]; // 更新当前日期 + await file.writeText(progressFile, JSON.stringify(progress)); + log.info("进度已保存。"); + } catch (error) { + log.error("保存进度失败:", error); + } +} + +let count = 0; // 用于记录分解圣遗物的次数 + +async function runFile(filePath, times = 2) { + try { + // 检查任务是否已经完成 + if (progress.completedTasks.includes(filePath)) { + log.info(`任务已跳过: ${filePath}`); + return; + } + + // 记录任务开始时间 + const startTime = Date.now(); + log.info(`开始执行任务: ${filePath}`); + + // 检查是否是恢复任务 + let isToRestore = filePath.search("(恢复)") != -1; + if (isToRestore && !activeRestore) { + log.info(`跳过恢复任务: ${filePath}`); + return; + } + + // 分解圣遗物 + if (!isToRestore && count++ % autoSalvageSpan == 0) { + await salvage(); + } + + // 调整地图缩放 (bgi[v0.41.0]后不需要) + // let shouldResizeMap = filePath.search("-m") != -1; + // if (shouldResizeMap) await resizeMap(); + + // 配置自动拾取,根据文件名指定信息,确定是否强制交互(快速拾取) + let forceInteraction = filePath.search("-f") != -1; + if (!isToRestore) dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": forceInteraction })); + + // 执行任务 + await pathingScript.runFile(filePath); + await sleep(1000); + // 配置强制拾取为关闭状态 + dispatcher.addTimer(new RealtimeTimer("AutoPick", { "forceInteraction": false })); + // 记录任务结束时间 + const endTime = Date.now(); + const duration = endTime - startTime; // 任务运行时长(毫秒) + + // 判断任务是否成功完成 + if (duration < 5000) { // 假设任务运行时长小于5秒则认为任务被取消或异常终止 + log.info(`任务运行时长过短(${duration}ms),可能被取消或异常终止,不保存进度: ${filePath}`); + return; + } + + // 任务成功完成,更新进度 + progress.completedTasks.push(filePath); + await saveProgress(); + log.info(`任务成功完成并保存进度: ${filePath}`); + + // 地图缩放按键同某些地图标识重叠,导致识别失败(bgi[v0.43.0]后引入) + // // 完成路径后,放大地图,脚本中调用就近传送。仍可能被缩小回去。不可行 + // let shouldResizeMap_after = filePath.search("~m") != -1; + // if (shouldResizeMap_after) { + // await resizeMap(0); + // await tpNearby(filePath); + // } + // 完成路径后,拖拽地图,脚本中调用就近传送。可行 + let shouldDragMap_after = filePath.search("~m") != -1; + if (shouldDragMap_after) { + await dragMap(-50, 50); + await tpNearby(filePath); + } + + } catch (error) { + // 任务失败,记录错误但不保存进度 + log.error(`任务执行失败: ${filePath}`, error); + await sleep(3000); + if (times > 0) { + log.info(`任务失败,尝试重新执行: ${filePath}`); + await runFile(filePath, times - 1); + } else { + log.info(`任务失败,不再重试: ${filePath}`); } } +} - // 批量执行 - async function batch(folder, files) { - for (let file of files) { - const filePath = folder + file; - await runFile(filePath); +// 批量执行 +async function batch(folder, files) { + for (let file of files) { + const filePath = folder + file; + await runFile(filePath); + } +} + +// 主函数 +(async function () { + + // 如果 activeProgress 为否,则直接写入一个空对象到进度文件 + if (!activeProgress) { + // 写入空对象到进度文件 + const result = await file.writeText(progressFile, JSON.stringify({})); + if (result) { + log.info("进度文件已重置,重新开始任务。"); + } else { + log.error("进度文件重置失败。"); } + } else { + // 如果 activeProgress 为是,则正常加载进度 + await loadProgress(); } - - // main - setGameMetrics(1920, 1080, 1); + // 确定路径 determinePath(); - // A or B + // 初始化 await init(); - log.info(`开始执行${path}线路。`); - if (path == 'A') await batch(folderA, pathingA); - else await batch(folderB, pathingB); - // Extra + // 执行主线任务 + log.info(`开始执行${progress.path}线路。`); + if (progress.path == 'A') { + await batch(folderA, pathingA); + } else { + await batch(folderB, pathingB); + } + + // 执行额外任务 if (extra) { await init(); - log.info(`开始执行额外线路。`); - - // 12小时刷新的额外点位每天拾取 + log.info("开始执行额外线路。"); await batch(folderE, pathingE); // 24小时刷新的额外点位隔天拾取,避免空跑 @@ -278,7 +389,7 @@ } await init(); - log.info(`今日狗粮拾取任务完成。拾取路线:${path}${extra ? '+E' : ''}`); + log.info(`今日狗粮拾取任务完成。拾取路线:${progress.path}${extra ? '+E' : ''}`); await sleep(1000); +})(); -})(); \ No newline at end of file diff --git a/repo/js/AutoArtifacts_A_B_Extra/settings.json b/repo/js/AutoArtifacts_A_B_Extra/settings.json index ef0146b9..9580c731 100644 --- a/repo/js/AutoArtifacts_A_B_Extra/settings.json +++ b/repo/js/AutoArtifacts_A_B_Extra/settings.json @@ -18,6 +18,15 @@ "否" ] }, + { + "name": "activeProgress", + "type": "select", + "label": "启用断点续跑。多账号选否!(默认:否)", + "options": [ + "是", + "否" + ] + }, { "name": "extra",