From 64610ae0ebff985dc0dc8193d2e0889f3ffa700d Mon Sep 17 00:00:00 2001 From: mno <718135749@qq.com> Date: Tue, 20 May 2025 23:43:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E4=BA=9Bjs=E6=9B=B4=E6=96=B0=20(#890)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 一些js更新 * Update repo/js/自动小怪锄地规划/main.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update repo/js/自动精英锄地规划/main.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- repo/js/伪造日志测试/main.js | 114 +++++++++++++++ repo/js/伪造日志测试/manifest.json | 14 ++ repo/js/伪造日志测试/settings.json | 59 ++++++++ repo/js/消耗复活料理/main.js | 131 +++++++++++++---- repo/js/消耗复活料理/manifest.json | 6 +- repo/js/消耗复活料理/信仰之跃.json | 39 +++-- repo/js/自动小怪锄地规划/main.js | 161 ++++++++++++++++----- repo/js/自动小怪锄地规划/manifest.json | 2 +- repo/js/自动小怪锄地规划/settings.json | 8 +- repo/js/自动精英锄地规划/main.js | 193 +++++++++++++++++-------- repo/js/自动精英锄地规划/manifest.json | 2 +- 11 files changed, 588 insertions(+), 141 deletions(-) create mode 100644 repo/js/伪造日志测试/main.js create mode 100644 repo/js/伪造日志测试/manifest.json create mode 100644 repo/js/伪造日志测试/settings.json diff --git a/repo/js/伪造日志测试/main.js b/repo/js/伪造日志测试/main.js new file mode 100644 index 00000000..a9370b26 --- /dev/null +++ b/repo/js/伪造日志测试/main.js @@ -0,0 +1,114 @@ +// fakeLog 函数,使用方法:将本函数放在主函数前,调用时请务必使用await,否则可能出现v8白框报错 +//在js开头处伪造该js结束运行的日志信息,如 await fakeLog("js脚本", true, true, 0); +//在js结尾处伪造该js开始运行的日志信息,如 await fakeLog("js脚本", true, false, 2333); +//duration项目仅在伪造结束信息时有效,且无实际作用,可以任意填写,当你需要在日志中输出特定值时才需要,单位为毫秒 +//在调用地图追踪前伪造该地图追踪开始运行的日志信息,如 await fakeLog(`地图追踪.json`, false, true, 0); +//在调用地图追踪后伪造该地图追踪结束运行的日志信息,如 await fakeLog(`地图追踪.json`, false, false, 0); +//如此便可以在js运行过程中伪造地图追踪的日志信息,可以在日志分析等中查看 + +async function fakeLog(name, isJs, isStart, duration) { + await sleep(10); + const currentTime = Date.now(); + // 参数检查 + if (typeof name !== 'string') { + log.error("参数 'name' 必须是字符串类型!"); + return; + } + if (typeof isJs !== 'boolean') { + log.error("参数 'isJs' 必须是布尔型!"); + return; + } + if (typeof isStart !== 'boolean') { + log.error("参数 'isStart' 必须是布尔型!"); + return; + } + if (typeof currentTime !== 'number' || !Number.isInteger(currentTime)) { + log.error("参数 'currentTime' 必须是整数!"); + return; + } + if (typeof duration !== 'number' || !Number.isInteger(duration)) { + log.error("参数 'duration' 必须是整数!"); + return; + } + + // 将 currentTime 转换为 Date 对象并格式化为 HH:mm:ss.sss + const date = new Date(currentTime); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + const milliseconds = String(date.getMilliseconds()).padStart(3, '0'); + const formattedTime = `${hours}:${minutes}:${seconds}.${milliseconds}`; + + // 将 duration 转换为分钟和秒,并保留三位小数 + const durationInSeconds = duration / 1000; // 转换为秒 + const durationMinutes = Math.floor(durationInSeconds / 60); + const durationSeconds = (durationInSeconds % 60).toFixed(3); // 保留三位小数 + + // 使用四个独立的 if 语句处理四种情况 + if (isJs && isStart) { + // 处理 isJs = true 且 isStart = true 的情况 + const logMessage = `正在伪造js开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行JS脚本: "${name}"`; + log.info(logMessage); + } + if (isJs && !isStart) { + // 处理 isJs = true 且 isStart = false 的情况 + const logMessage = `正在伪造js结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } + if (!isJs && isStart) { + // 处理 isJs = false 且 isStart = true 的情况 + const logMessage = `正在伪造地图追踪开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行地图追踪任务: "${name}"`; + log.info(logMessage); + } + if (!isJs && !isStart) { + // 处理 isJs = false 且 isStart = false 的情况 + const logMessage = `正在伪造地图追踪结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } +} + +// 主函数,用于示例该函数的使用 +async function main() { + // 定义变量 + const name1 = "伪造日志测试"; + const name2 = "伪造地图追踪.json"; + + // 调用 fakeLog 函数,输出 JavaScript 的结尾日志,耗时 1.234 秒 + const duration1 = 1234; // 1.234 秒 + await fakeLog(name1, true, false, duration1); + + // 输出地图追踪开始的日志 + const duration2 = 0; // 地图追踪开始时,耗时为 0 + await fakeLog(name2, false, true, duration2); + + // 等待5秒 + await sleep(5000); + log.info('模拟地图追踪运行完成') + + // 调用 fakeLog 函数,输出地图追踪结束的日志,耗时 5.000 秒 + const duration3 = 5000; // 5.000 秒 + await fakeLog(name2, false, false, duration3); + + // 调用 fakeLog 函数,输出 JavaScript 开始的日志 + const duration4 = 0; // JS 开始时,耗时为 0 + await fakeLog(name1, true, true, duration4); +} + +// 调用主函数 +main(); diff --git a/repo/js/伪造日志测试/manifest.json b/repo/js/伪造日志测试/manifest.json new file mode 100644 index 00000000..225b806b --- /dev/null +++ b/repo/js/伪造日志测试/manifest.json @@ -0,0 +1,14 @@ +{ + "manifest_version": 1, + "name": "伪造日志测试", + "version": "1.0", + "bgi_version": "0.44.0", + "description": "", + "authors": [ + { + "name": "mno" + } + ], + "settings_ui": "settings.json", + "main": "main.js" +} diff --git a/repo/js/伪造日志测试/settings.json b/repo/js/伪造日志测试/settings.json new file mode 100644 index 00000000..9c126451 --- /dev/null +++ b/repo/js/伪造日志测试/settings.json @@ -0,0 +1,59 @@ +[ + { + "name": "operationType", + "type": "select", + "label": "操作模式(默认:生成路径组文件)", + "options": [ + "生成路径组文件", + "执行路径组文件1", + "执行路径组文件2", + "执行路径组文件3", + "输出地图追踪文件" + ] + }, + { + "name": "excludeTagsForPathGroup1", + "type": "input-text", + "label": "路径组1要排除的标签(传奇,水免,次数盾或高危)" + }, + { + "name": "selectTagsForPathGroup2", + "type": "input-text", + "label": "路径组2要选择的标签(传奇,水免,次数盾或高危)" + }, + { + "name": "selectTagsForPathGroup3", + "type": "input-text", + "label": "路径组3要选择的标签(传奇,水免,次数盾或高危)" + }, + { + "name": "disableAutoPickup", + "type": "checkbox", + "label": "是否禁用自动拾取(默认不禁用)" + }, + { + "name": "disableRouteCdCheck", + "type": "checkbox", + "label": "是否禁用路线CD检测(默认不禁用)" + }, + { + "name": "requiredMonsterCount", + "type": "input-text", + "label": "目标怪物数量(默认405,必须为0以上整数)" + }, + { + "name": "minSecPerMonster", + "type": "input-text", + "label": "最低秒均(秒均=摩拉/时间,默认0.1)" + }, + { + "name": "excludeTagsForAll", + "type": "input-text", + "label": "全局排除关键词(使用中文分号分隔)" + }, + { + "name": "accountName", + "type": "input-text", + "label": "账户名,用于区分不同的账户" + } +] diff --git a/repo/js/消耗复活料理/main.js b/repo/js/消耗复活料理/main.js index 0d43270b..0091d78c 100644 --- a/repo/js/消耗复活料理/main.js +++ b/repo/js/消耗复活料理/main.js @@ -1,11 +1,93 @@ +// fakeLog 函数,使用方法:将本函数放在主函数前,调用时请务必使用await,否则可能出现v8白框报错 +//在js开头处伪造该js结束运行的日志信息,如 await fakeLog("js脚本", true, true, 0); +//在js结尾处伪造该js开始运行的日志信息,如 await fakeLog("js脚本", true, false, 2333); +//duration项目仅在伪造结束信息时有效,且无实际作用,可以任意填写,当你需要在日志中输出特定值时才需要,单位为毫秒 +//在调用地图追踪前伪造该地图追踪开始运行的日志信息,如 await fakeLog(`地图追踪.json`, false, true, 0); +//在调用地图追踪后伪造该地图追踪结束运行的日志信息,如 await fakeLog(`地图追踪.json`, false, false, 0); +//如此便可以在js运行过程中伪造地图追踪的日志信息,可以在日志分析等中查看 + +async function fakeLog(name, isJs, isStart, duration) { + await sleep(10); + const currentTime = Date.now(); + // 参数检查 + if (typeof name !== 'string') { + log.error("参数 'name' 必须是字符串类型!"); + return; + } + if (typeof isJs !== 'boolean') { + log.error("参数 'isJs' 必须是布尔型!"); + return; + } + if (typeof isStart !== 'boolean') { + log.error("参数 'isStart' 必须是布尔型!"); + return; + } + if (typeof currentTime !== 'number' || !Number.isInteger(currentTime)) { + log.error("参数 'currentTime' 必须是整数!"); + return; + } + if (typeof duration !== 'number' || !Number.isInteger(duration)) { + log.error("参数 'duration' 必须是整数!"); + return; + } + + // 将 currentTime 转换为 Date 对象并格式化为 HH:mm:ss.sss + const date = new Date(currentTime); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + const milliseconds = String(date.getMilliseconds()).padStart(3, '0'); + const formattedTime = `${hours}:${minutes}:${seconds}.${milliseconds}`; + + // 将 duration 转换为分钟和秒,并保留三位小数 + const durationInSeconds = duration / 1000; // 转换为秒 + const durationMinutes = Math.floor(durationInSeconds / 60); + const durationSeconds = (durationInSeconds % 60).toFixed(3); // 保留三位小数 + + // 使用四个独立的 if 语句处理四种情况 + if (isJs && isStart) { + // 处理 isJs = true 且 isStart = true 的情况 + const logMessage = `正在伪造js开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行JS脚本: "${name}"`; + log.info(logMessage); + } + if (isJs && !isStart) { + // 处理 isJs = true 且 isStart = false 的情况 + const logMessage = `正在伪造js结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } + if (!isJs && isStart) { + // 处理 isJs = false 且 isStart = true 的情况 + const logMessage = `正在伪造地图追踪开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行地图追踪任务: "${name}"`; + log.info(logMessage); + } + if (!isJs && !isStart) { + // 处理 isJs = false 且 isStart = false 的情况 + const logMessage = `正在伪造地图追踪结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } +} + + (async function () { - // 定义六个运行时变量,初始值分别为 2000、1000、0、0、0、0 - let runtime1 = 2000; - let runtime2 = 1000; - let runtime3 = 0; - let runtime4 = 0; - let runtime5 = 0; - let runtime6 = 0; + + //伪造js结束的日志记录 + await fakeLog("消耗复活料理", true, false, 2333); // 从 settings 中获取最大循环次数,如果未配置则默认为 2000 const maxLoopCount = parseInt(settings.maxLoopCount || 2000, 10); @@ -35,24 +117,6 @@ const currentHour = now.getHours(); // 获取当前时间的小时数 const currentTime = now.toLocaleString(); // 获取完整的当前时间字符串 - // 更新 runtime 变量 - runtime6 = runtime5; - runtime5 = runtime4; - runtime4 = runtime3; - runtime3 = runtime2; - runtime2 = runtime1; - runtime1 = now.getTime(); - - // 检查时间差条件 - if ((runtime1 - runtime2) < 500 && - (runtime2 - runtime3) < 500 && - (runtime3 - runtime4) < 500 && - (runtime4 - runtime5) < 500 && - (runtime5 - runtime6) < 500) { - log.info(`连续五次时间差小于 500 毫秒,循环终止。`); - break; // 如果连续五次时间差小于 500 毫秒,退出循环 - } - // 如果当前时间的小时数与排除时间相同,则退出循环 if (currentHour === excludeHour) { log.info(`当前时间是 ${currentTime},与排除时间小时数相同,将退出循环`); @@ -62,7 +126,24 @@ // 记录当前时间 log.info(`正在执行循环第 ${i + 1} 次,总共 ${maxLoopCount} 次,当前时间: ${currentTime}`); + await fakeLog(`第${i + 1}次信仰之跃.json`, false, true, 0); + // 运行路径追踪任务 await pathingScript.runFile(pathFileName); + + await fakeLog(`第${i + 1}次信仰之跃.json`, false, false, 0); + + //捕获任务结束的信息,同时等待95秒用来卡时间 + try { + log.info('正在等待复活料理cd') + await sleep(95000); + } catch (error) { + log.error(`发生错误: ${error}`); + break; // 终止循环 + } } + + //伪造一个js开始的日志记录 + await fakeLog("消耗复活料理", true, true, 0); + })(); diff --git a/repo/js/消耗复活料理/manifest.json b/repo/js/消耗复活料理/manifest.json index 5b613895..6c554309 100644 --- a/repo/js/消耗复活料理/manifest.json +++ b/repo/js/消耗复活料理/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 1, - "name": "消耗复活料理@mno", - "version": "1.0", - "description": "通过信仰之跃消耗放在食品袋中的复活料理,注意,使用前请确保要消耗的复活料理在食品袋中并且装备食品袋小道具,目前存在一个已知的bug导致结束配置组时将花费过长的时间,建议直接关闭bgi程序来关闭本配置组", + "name": "消耗复活料理", + "version": "1.1", + "description": "通过信仰之跃消耗放在食品袋中的复活料理,注意,使用前请确保要消耗的复活料理在食品袋中并且装备食品袋小道具,并且不要开启行走位,生存位等配置,也不要开启循环使用小道具", "authors": [ { "name": "mno" diff --git a/repo/js/消耗复活料理/信仰之跃.json b/repo/js/消耗复活料理/信仰之跃.json index f8703147..0fe62108 100644 --- a/repo/js/消耗复活料理/信仰之跃.json +++ b/repo/js/消耗复活料理/信仰之跃.json @@ -13,29 +13,38 @@ "id": 1, "x": 508.03515625, "y": -630.49072265625, - "type": "teleport", - "move_mode": "walk", "action": "", - "action_params": "" - }, - { - "id": 2, - "x": 499.87890625, - "y": -686.18310546875, - "type": "path", - "move_mode": "fly", - "action": "stop_flying", - "action_params": "10000", + "move_mode": "walk", + "action_params": "", + "type": "teleport", "locked": false }, + { + "id": 2, + "x": 508.03515625, + "y": -630.49072265625, + "action": "combat_script", + "move_mode": "walk", + "action_params": "keypress(1)", + "type": "path" + }, { "id": 3, + "x": 499.87890625, + "y": -686.18310546875, + "action": "stop_flying", + "move_mode": "fly", + "action_params": "10000", + "type": "path" + }, + { + "id": 4, "x": 501.3095703125, "y": -683.6240234375, - "type": "path", - "move_mode": "walk", "action": "combat_script", - "action_params": "keypress(z),wait(5),keypress(1),wait(90)" + "move_mode": "walk", + "action_params": "keypress(z)", + "type": "path" } ] } \ No newline at end of file diff --git a/repo/js/自动小怪锄地规划/main.js b/repo/js/自动小怪锄地规划/main.js index 7b7dd8cd..f21cf6c7 100644 --- a/repo/js/自动小怪锄地规划/main.js +++ b/repo/js/自动小怪锄地规划/main.js @@ -1,3 +1,89 @@ +// fakeLog 函数,使用方法:将本函数放在主函数前,调用时请务必使用await,否则可能出现v8白框报错 +//在js开头处伪造该js结束运行的日志信息,如 await fakeLog("js脚本", true, true, 0); +//在js结尾处伪造该js开始运行的日志信息,如 await fakeLog("js脚本", true, false, 2333);(可以不加) +//duration项目仅在伪造结束信息时有效,且无实际作用,可以任意填写,当你需要在日志中输出特定值时才需要,单位为毫秒 +//在调用地图追踪前伪造该地图追踪开始运行的日志信息,如 await fakeLog(`地图追踪.json`, false, true, 0); +//在调用地图追踪后伪造该地图追踪结束运行的日志信息,如 await fakeLog(`地图追踪.json`, false, false, 0); +//如此便可以在js运行过程中伪造地图追踪的日志信息,可以在日志分析等中查看 + +async function fakeLog(name, isJs, isStart, duration) { + await sleep(10); + const currentTime = Date.now(); + // 参数检查 + if (typeof name !== 'string') { + log.error("参数 'name' 必须是字符串类型!"); + return; + } + if (typeof isJs !== 'boolean') { + log.error("参数 'isJs' 必须是布尔型!"); + return; + } + if (typeof isStart !== 'boolean') { + log.error("参数 'isStart' 必须是布尔型!"); + return; + } + if (typeof currentTime !== 'number' || !Number.isInteger(currentTime)) { + log.error("参数 'currentTime' 必须是整数!"); + return; + } + if (typeof duration !== 'number' || !Number.isInteger(duration)) { + log.error("参数 'duration' 必须是整数!"); + return; + } + + // 将 currentTime 转换为 Date 对象并格式化为 HH:mm:ss.sss + const date = new Date(currentTime); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + const milliseconds = String(date.getMilliseconds()).padStart(3, '0'); + const formattedTime = `${hours}:${minutes}:${seconds}.${milliseconds}`; + + // 将 duration 转换为分钟和秒,并保留三位小数 + const durationInSeconds = duration / 1000; // 转换为秒 + const durationMinutes = Math.floor(durationInSeconds / 60); + const durationSeconds = (durationInSeconds % 60).toFixed(3); // 保留三位小数 + + // 使用四个独立的 if 语句处理四种情况 + if (isJs && isStart) { + // 处理 isJs = true 且 isStart = true 的情况 + const logMessage = `正在伪造js开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行JS脚本: "${name}"`; + log.info(logMessage); + } + if (isJs && !isStart) { + // 处理 isJs = true 且 isStart = false 的情况 + const logMessage = `正在伪造js结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } + if (!isJs && isStart) { + // 处理 isJs = false 且 isStart = true 的情况 + const logMessage = `正在伪造地图追踪开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行地图追踪任务: "${name}"`; + log.info(logMessage); + } + if (!isJs && !isStart) { + // 处理 isJs = false 且 isStart = false 的情况 + const logMessage = `正在伪造地图追踪结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } +} + + (async function () { // 初始化所有用到的参数 const operationMode = settings.operationMode || "生成路径文件"; // 默认值为“生成路径文件” @@ -11,6 +97,11 @@ const pathingDir = 'pathing/'; // 初始化pathingDir参数 const enableCooldownCheck = !disableCooldownCheck; // 如果 disableCooldownCheck 未设置或为 false,则 enableCooldownCheck 为 true + // 初始化全局排除关键词配置 + let globalExclusionKeywords = settings.globalExclusionKeywords || "不跑"; // 默认为不跑 + + const exclusionKeywordsArray = globalExclusionKeywords.split(";").map(keyword => keyword.trim()).filter(Boolean); // 使用中文分号分隔,并去除空格和空字符串 + // 初始化用于计数的变量 let outputFolderName = accountName; // 初始化为空 let totalMonsterCount = 0; // 筛选出的怪物总数 @@ -19,15 +110,6 @@ let failCount = 0; // 失败复制的文件数量 let routeIndex = 0; // 当前筛选的路线序号 - // 定义六个运行时变量,初始值分别为 2000、1000、0、0、0、0 - let runtime1 = 2000; - let runtime2 = 1000; - let runtime3 = 0; - let runtime4 = 0; - let runtime5 = 0; - let runtime6 = 0; - - // 日志输出配置参数 log.info( `自动小怪锄地规划 - 配置信息:` + @@ -41,6 +123,9 @@ `账户名=${accountName}` ); + // 在日志中输出全局排除关键词配置信息 + log.info(`全局排除关键词=${globalExclusionKeywords ? exclusionKeywordsArray.join(";") : "无"}`); + // 检查是否所有配置都是默认状态 const isDefaultConfig = ( operationMode === "生成路径文件" && @@ -82,6 +167,8 @@ // 判断操作模式是否为“执行路径文件”,若是则执行路径文件 if (operationMode === "执行路径文件") { try { + //伪造js已经结束的记录 + await fakeLog("自动小怪锄地规划", true, false, 1); // 定义路径组文件的路径,使用 outputFolderName const pathGroupFilePath = `route/${outputFolderName}.txt`; @@ -90,45 +177,43 @@ for (let i = 0; i < savedRoutes.length; i++) { const routeWithTimestamp = savedRoutes[i].trim(); const [routeName, routeTimestamp] = routeWithTimestamp.split('::'); - log.info(`当前任务为第 ${i + 1}/${savedRoutes.length} 个`); + log.info(`当前进度:${routeName}为第 ${i + 1}/${savedRoutes.length} 个`); const now = new Date(); // 获取开始时间 const startTime = now.toISOString(); - // 更新 runtime 变量 - runtime6 = runtime5; - runtime5 = runtime4; - runtime4 = runtime3; - runtime3 = runtime2; - runtime2 = runtime1; - runtime1 = now.getTime(); - - // 检查时间差条件 - if ((runtime1 - runtime2) < 500 && - (runtime2 - runtime3) < 500 && - (runtime3 - runtime4) < 500 && - (runtime4 - runtime5) < 500 && - (runtime5 - runtime6) < 500) { - log.info(`连续五次时间差小于 500 毫秒,循环终止。`); - break; // 如果连续五次时间差小于 500 毫秒,退出循环 - } - if (enableCooldownCheck && startTime < routeTimestamp) { log.info(`当前路线 ${routeName} 未刷新,跳过任务`); - await sleep(500); + await sleep(10); continue; // 跳过当前循环 } log.info(`当前路线 ${routeName} 已刷新或未启用CD检测,执行任务`); // 拼接路径文件的完整路径 const pathingFilePath = `pathing/${routeName}.json`; + + //伪造地图追踪开始的日志记录 + await fakeLog(routeName + ".json", false, true, 0); // 开始时 duration 通常为 0 + // 执行路径文件 await pathingScript.runFile(pathingFilePath); - // 如果启用了CD检测,获取结束时间并判断时间差 + const endTime = new Date(); // 获取结束时间 + const timeDiff = endTime - now; // 计算时间差(单位:毫秒) + + //伪造地图追踪结束的日志记录 + await fakeLog(routeName + ".json", false, false, timeDiff); + + //尝试捕获任务取消的错误,捕获后终止循环 + try { + await sleep(10); + } catch (error) { + log.error(`发生错误: ${error}`); + return; // 终止循环 + } + + // 如果启用了CD检测 if (enableCooldownCheck) { - const endTime = new Date(); // 获取结束时间 - const timeDiff = endTime - now; // 计算时间差(单位:毫秒) - if (timeDiff > 10000) { // 如果时间差大于10秒(10000毫秒) + if (timeDiff > 3000) { // 如果时间差大于3秒(3000毫秒) // 计算新的时间戳,增加12小时 const newTimestamp = new Date(startTime).getTime() + 12 * 60 * 60 * 1000; const formattedNewTimestamp = new Date(newTimestamp).toISOString(); @@ -148,6 +233,10 @@ } catch (error) { log.error(`读取或写入路径组文件时出错: ${error}`); } + + //伪造一个js开始的记录(实际上没必要) + //await fakeLog("自动精英锄地规划", true, true, 0); + return; } // 筛选、排序并选取路线 @@ -173,13 +262,14 @@ for (const route of sortedPathingFiles) { routeIndex++; // 每次循环时递增 + const meetsKeywordCondition = exclusionKeywordsArray.every(keyword => !route.name.toLowerCase().includes(keyword)); const meetsWaterFreeCondition = !excludeWaterFree || !route.isWaterFree; const meetsHighRiskCondition = !excludeHighRisk || !route.isHighRisk; // 修改后的日志输出,增加当前路线的序号 - //log.debug(`筛选路线 ${routeIndex}(${route.name}):水免条件 ${meetsWaterFreeCondition},高危条件 ${meetsHighRiskCondition}`); + log.debug(`筛选路线 ${routeIndex}(${route.name}):关键词条件 ${meetsKeywordCondition},水免条件 ${meetsWaterFreeCondition},高危条件 ${meetsHighRiskCondition}`); - if (meetsWaterFreeCondition && meetsHighRiskCondition) { + if (meetsKeywordCondition && meetsWaterFreeCondition && meetsHighRiskCondition) { totalMonsterCount += route.monsterCount; route.selected = 1; selectedRoutes.push(route.name); @@ -187,6 +277,7 @@ } } + if (totalMonsterCount < requiredMonsterCount) { log.warn(`数量不足,最多可以包含 ${totalMonsterCount} 只怪物,不满足所需的 ${requiredMonsterCount} 只怪物`); } diff --git a/repo/js/自动小怪锄地规划/manifest.json b/repo/js/自动小怪锄地规划/manifest.json index cd6c43d6..f3b5f87b 100644 --- a/repo/js/自动小怪锄地规划/manifest.json +++ b/repo/js/自动小怪锄地规划/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "自动小怪锄地规划", - "version": "1.0", + "version": "1.1", "bgi_version": "0.44.0", "description": "该脚本支持根据用户配置生成路径组文件、运行路径组或输出地图追踪文件。用户可以通过自定义配置设置所需怪物数量、筛选条件(如是否排除水免路线或高危路线)以及效率计算权重。脚本会根据这些条件自动筛选出符合条件的路线,此外,支持刷新cd检测,启用后未刷新的路线在运行时将被跳过。注意,第一次使用时要先生成路径组文件后再执行路径组文件,之后的每次运行无需再次生成路径组文件,将根据自定义配置中的内容自动寻找对应的路径组文件,当你需要强制刷新cd或更改筛选条件时可以重新生成路径组文件", "authors": [ diff --git a/repo/js/自动小怪锄地规划/settings.json b/repo/js/自动小怪锄地规划/settings.json index 0e2629ba..4cb2816f 100644 --- a/repo/js/自动小怪锄地规划/settings.json +++ b/repo/js/自动小怪锄地规划/settings.json @@ -43,5 +43,11 @@ "name": "accountName", "type": "input-text", "label": "账户名,用于区分不同账号的信息" + }, + { + "name": "globalExclusionKeywords", + "type": "input-text", + "label": "全局排除关键词(用于在筛选路线时排除包含指定关键词的路线)\n使用中文分号;分隔,默认排除不跑", + "default": "不跑" } -] +] \ No newline at end of file diff --git a/repo/js/自动精英锄地规划/main.js b/repo/js/自动精英锄地规划/main.js index 664da0c5..13d52c4b 100644 --- a/repo/js/自动精英锄地规划/main.js +++ b/repo/js/自动精英锄地规划/main.js @@ -1,3 +1,86 @@ +// fakeLog 函数,使用方法:将本函数放在主函数前,调用时请务必使用await,否则可能出现v8白框报错 +//在js开头处伪造该js结束运行的日志信息,如 await fakeLog("js脚本", true, true, 0); +//在js结尾处伪造该js开始运行的日志信息,如 await fakeLog("js脚本", true, false, 2333); +//duration项目仅在伪造结束信息时有效,且无实际作用,可以任意填写,当你需要在日志中输出特定值时才需要,单位为毫秒 +//在调用地图追踪前伪造该地图追踪开始运行的日志信息,如 await fakeLog(`地图追踪.json`, false, true, 0); +//在调用地图追踪后伪造该地图追踪结束运行的日志信息,如 await fakeLog(`地图追踪.json`, false, false, 0); +//如此便可以在js运行过程中伪造地图追踪的日志信息,可以在日志分析等中查看 + +async function fakeLog(name, isJs, isStart, duration) { + await sleep(10); + const currentTime = Date.now(); + // 参数检查 + if (typeof name !== 'string') { + log.error("参数 'name' 必须是字符串类型!"); + return; + } + if (typeof isJs !== 'boolean') { + log.error("参数 'isJs' 必须是布尔型!"); + return; + } + if (typeof isStart !== 'boolean') { + log.error("参数 'isStart' 必须是布尔型!"); + return; + } +// Removed redundant type and integer checks for `currentTime`. + if (typeof duration !== 'number' || !Number.isInteger(duration)) { + log.error("参数 'duration' 必须是整数!"); + return; + } + + // 将 currentTime 转换为 Date 对象并格式化为 HH:mm:ss.sss + const date = new Date(currentTime); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + const milliseconds = String(date.getMilliseconds()).padStart(3, '0'); + const formattedTime = `${hours}:${minutes}:${seconds}.${milliseconds}`; + + // 将 duration 转换为分钟和秒,并保留三位小数 + const durationInSeconds = duration / 1000; // 转换为秒 + const durationMinutes = Math.floor(durationInSeconds / 60); + const durationSeconds = (durationInSeconds % 60).toFixed(3); // 保留三位小数 + + // 使用四个独立的 if 语句处理四种情况 + if (isJs && isStart) { + // 处理 isJs = true 且 isStart = true 的情况 + const logMessage = `正在伪造js开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行JS脚本: "${name}"`; + log.info(logMessage); + } + if (isJs && !isStart) { + // 处理 isJs = true 且 isStart = false 的情况 + const logMessage = `正在伪造js结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } + if (!isJs && isStart) { + // 处理 isJs = false 且 isStart = true 的情况 + const logMessage = `正在伪造地图追踪开始的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 开始执行地图追踪任务: "${name}"`; + log.info(logMessage); + } + if (!isJs && !isStart) { + // 处理 isJs = false 且 isStart = false 的情况 + const logMessage = `正在伪造地图追踪结束的日志记录\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}分${durationSeconds}秒\n\n` + + `[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` + + `------------------------------`; + log.info(logMessage); + } +} + + (async function () { // 初始化配置 const operationType = settings.operationType || "生成路径组文件"; // 操作模式 @@ -24,35 +107,22 @@ // 根据 disableRouteCdCheck 的值设置 enableRouteCdCheck const enableRouteCdCheck = !disableRouteCdCheck; // 如果 disableRouteCdCheck 为 true,则 enableRouteCdCheck 为 false,反之亦然 - // 新增校验:检查所有配置是否都是默认状态 - const defaultSettings = { - operationType: "生成路径组文件", - excludeTagsForPathGroup1: "", - selectTagsForPathGroup2: "", - selectTagsForPathGroup3: "", - disableAutoPickup: false, - disableRouteCdCheck: false, - requiredMonsterCount: 405, - minSecPerMonster: 0.1, - accountName: "一个账户名", - excludeTagsForAll: "" - }; - - const isAllDefault = Object.entries(defaultSettings).every(([key, defaultValue]) => { - return settings[key] === undefined || settings[key] === defaultValue; - }); - - if (isAllDefault) { - log.warn("所有配置项均为默认状态,请检查是否需要调整配置你没有修改自定义配置,请在配置组界面中右键本js以修改自定义配置。"); + //当用户所有自定义配置均为默认时警告用户 + if ( + operationType === "生成路径组文件" && + excludeTagsForPathGroup1 === "" && + selectTagsForPathGroup2 === "" && + selectTagsForPathGroup3 === "" && + disableAutoPickup === false && + disableRouteCdCheck === false && + requiredMonsterCount === 405 && + minSecPerMonster === 0.1 && + accountName === "一个账户名" && + excludeTagsForAll === "" + ) { + log.warn("所有配置项均为默认状态,请检查是否需要调整配置。你没有修改自定义配置,请在配置组界面中右键本js以修改自定义配置。"); } - // 定义六个运行时变量,初始值分别为 2000、1000、0、0、0、0 - let runtime1 = 2000; - let runtime2 = 1000; - let runtime3 = 0; - let runtime4 = 0; - let runtime5 = 0; - let runtime6 = 0; // 初始化文件路径(直接内置生成) const indexPath = 'index.txt'; @@ -94,6 +164,9 @@ log.warn("自动拾取已禁用"); } + //伪造js结束的记录 + await fakeLog("自动精英锄地规划", true, false, 1); + // 根据 executePathGroupMode 获取路径组编号 const pathGroupNumber = executePathGroupMode; @@ -116,63 +189,60 @@ const now = new Date(); const startTime = now.toISOString(); // 获取开始时间 - // 更新 runtime 变量 - runtime6 = runtime5; - runtime5 = runtime4; - runtime4 = runtime3; - runtime3 = runtime2; - runtime2 = runtime1; - runtime1 = now.getTime(); - - // 检查时间差条件 - if ((runtime1 - runtime2) < 500 && - (runtime2 - runtime3) < 500 && - (runtime3 - runtime4) < 500 && - (runtime4 - runtime5) < 500 && - (runtime5 - runtime6) < 500) { - log.info(`连续五次时间差小于 500 毫秒,循环终止。`); - break; // 如果连续五次时间差小于 500 毫秒,退出循环 - } - // 如果启用了路线CD检测,检查当前时间是否不早于附加时间戳 if (enableRouteCdCheck) { const pathCDDate = new Date(pathCD); // 将附加时间戳转换为Date对象 if (now < pathCDDate) { log.info(`当前路线 ${pathName} 为第 ${i + 1}/${pathLines.length} 个,当前路线未刷新,放弃该路径`); - await sleep(500); + await sleep(10); continue; // 放弃该路径 } } log.info(`当前路线 ${pathName} 为第 ${i + 1}/${pathLines.length} 个,当前路线已刷新或未启用cd检测,执行路径`); + //伪造地图追踪开始的日志记录 + await fakeLog(pathName + ".json", false, true, 0); // 开始时 duration 通常为 0 + // 执行路径文件 await pathingScript.runFile(pathFilePath); + //捕获任务取消的错误并跳出循环 + try { + await sleep(10); + } catch (error) { + log.error(`发生错误: ${error}`); + break; // 终止循环 + } + // 获取结束时间 const endTime = new Date(); const endTimeISO = endTime.toISOString(); // 获取结束时间 - // 检查执行时间是否超过10秒 + // 检查执行时间是否超过3秒 const executionTime = endTime.getTime() - now.getTime(); - // 如果启用了CD检测,且结束时间与开始时间相差超过10秒,则更新附加时间戳为开始时间后的第一个凌晨四点 - if (enableRouteCdCheck && executionTime > 10000) { - // 计算开始时间后的第一个晚上八点 - const nextEveningEight = new Date(startTime); - nextEveningEight.setHours(4, 0, 0, 0); // 设置时间为凌晨四点0分0秒0毫秒 - if (nextEveningEight <= new Date(startTime)) { - // 如果设置的时间小于等于开始时间,说明需要取下一个晚上八点 - nextEveningEight.setHours(4 + 24, 0, 0, 0); // 设置时间为下一个晚上八点0分0秒0毫秒 + //伪造地图追踪结束的记录 + await fakeLog(pathName + ".json", false, false, executionTime); + + + // 如果启用了CD检测,且结束时间与开始时间相差超过3秒,则更新附加时间戳为开始时间后的第一个凌晨四点 + if (enableRouteCdCheck && executionTime > 3000) { + // 计算开始时间后的第一个凌晨四点 + const nextFourClock = new Date(startTime); + nextFourClock.setHours(4, 0, 0, 0); // 设置时间为凌晨四点 + if (nextFourClock <= new Date(startTime)) { + // 如果设置的时间小于等于开始时间,说明需要取下一个凌晨四点 + nextFourClock.setHours(4 + 24, 0, 0, 0); // 设置时间为下一个凌晨四点 } // 转换为北京时间(UTC+8) - const nextEveningEightBeijing = new Date(nextEveningEight.getTime() + 8 * 3600 * 1000); - const nextEveningEightBeijingFormatted = `${nextEveningEightBeijing.getFullYear()}-${String(nextEveningEightBeijing.getMonth() + 1).padStart(2, '0')}-${String(nextEveningEightBeijing.getDate()).padStart(2, '0')} ${String(nextEveningEightBeijing.getHours()).padStart(2, '0')}:${String(nextEveningEightBeijing.getMinutes()).padStart(2, '0')}:${String(nextEveningEightBeijing.getSeconds()).padStart(2, '0')}`; + const nextFourClockBeijing = new Date(nextFourClock.getTime()); + const nextFourClockFormatted = `${nextFourClockBeijing.getFullYear()}-${String(nextFourClockBeijing.getMonth() + 1).padStart(2, '0')}-${String(nextFourClockBeijing.getDate()).padStart(2, '0')} ${String(nextFourClockBeijing.getHours()).padStart(2, '0')}:${String(nextFourClockBeijing.getMinutes()).padStart(2, '0')}:${String(nextFourClockBeijing.getSeconds()).padStart(2, '0')}`; // 更新路径组文件中的附加时间戳 - pathLines[i] = `${pathName}::${nextEveningEight.toISOString()}`; - log.info(`当前路线 ${pathName} 执行完成,下一次可用时间更新为:${nextEveningEightBeijingFormatted}`); + pathLines[i] = `${pathName}::${nextFourClock.toISOString()}`; + log.info(`当前路线 ${pathName} 执行完成,可用时间更新为:${nextFourClockFormatted}`); // 将更新后的内容写回路径组文件 const updatedPathGroupContent = pathLines.join('\n'); @@ -183,9 +253,12 @@ } } catch (error) { log.error(`读取路径组文件失败:${error}`); - process.exit(1); // 退出程序 + return; } + //伪造一个js开始的记录 + await fakeLog("自动精英锄地规划", true, true, 0); + // 执行完成后退出程序 return; } diff --git a/repo/js/自动精英锄地规划/manifest.json b/repo/js/自动精英锄地规划/manifest.json index 7c43958c..54df22c7 100644 --- a/repo/js/自动精英锄地规划/manifest.json +++ b/repo/js/自动精英锄地规划/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "自动精英锄地规划", - "version": "1.0", + "version": "1.1", "bgi_version": "0.44.0", "description": "脚本名称:自动精英锄地规划\n该脚本支持根据用户配置生成路径组文件、运行路径组或执行路径文件。用户可以通过配置文件设置所需怪物数量、筛选条件(如是否包含传奇路线、水免路线、次数盾路线、高危路线)以及最低秒均值。脚本还支持禁用自动拾取功能和启用路线CD检测。脚本会根据这些条件筛选出符合条件的路线,并生成路径组文件或直接运行路径文件,直到满足所需怪物数量。", "authors": [