diff --git a/repo/js/自动小怪锄地规划/main.js b/repo/js/自动小怪锄地规划/main.js index f21cf6c7..2bbfd068 100644 --- a/repo/js/自动小怪锄地规划/main.js +++ b/repo/js/自动小怪锄地规划/main.js @@ -84,10 +84,16 @@ async function fakeLog(name, isJs, isStart, duration) { } +// 定义自定义函数 basename,用于获取文件名 +function basename(filePath) { + const lastSlashIndex = filePath.lastIndexOf('\\'); // 或者使用 '/',取决于你的路径分隔符 + return filePath.substring(lastSlashIndex + 1); +} + (async function () { // 初始化所有用到的参数 - const operationMode = settings.operationMode || "生成路径文件"; // 默认值为“生成路径文件” - const requiredMonsterCount = parseInt(settings.requiredMonsterCount || 1750, 10); // 默认值为1800 + const operationMode = settings.operationMode || "执行路径文件"; // 默认值为“执行路径文件” + const requiredMonsterCount = parseInt(settings.requiredMonsterCount || 1750, 10); // 默认值为1750 const excludeWaterFree = !!settings.excludeWaterFree; // 默认值为false(默认不排除) const excludeHighRisk = !!settings.excludeHighRisk; // 默认值为false(默认不排除) const weight = parseFloat(settings.weight || 2); // 默认值为2 @@ -100,7 +106,7 @@ async function fakeLog(name, isJs, isStart, duration) { // 初始化全局排除关键词配置 let globalExclusionKeywords = settings.globalExclusionKeywords || "不跑"; // 默认为不跑 - const exclusionKeywordsArray = globalExclusionKeywords.split(";").map(keyword => keyword.trim()).filter(Boolean); // 使用中文分号分隔,并去除空格和空字符串 + const exclusionKeywordsArray = globalExclusionKeywords.split(";").map(keyword => keyword.trim()); // 使用中文分号分隔,并去除空格 // 初始化用于计数的变量 let outputFolderName = accountName; // 初始化为空 @@ -126,31 +132,13 @@ async function fakeLog(name, isJs, isStart, duration) { // 在日志中输出全局排除关键词配置信息 log.info(`全局排除关键词=${globalExclusionKeywords ? exclusionKeywordsArray.join(";") : "无"}`); - // 检查是否所有配置都是默认状态 - const isDefaultConfig = ( - operationMode === "生成路径文件" && - requiredMonsterCount === 1750 && - !excludeWaterFree && - !excludeHighRisk && - weight === 2 && - !disableAutoPick && - enableCooldownCheck && - accountName === "一个账户名" - ); - - if (isDefaultConfig) { - log.warn(`你没有修改自定义配置,请在配置组界面中右键本js以修改自定义配置`); - } - - // 验证配置参数 if ( isNaN(requiredMonsterCount) || requiredMonsterCount < 0 || - requiredMonsterCount > 3000 || !Number.isInteger(requiredMonsterCount) ) { - log.warn(`怪物数量 ${requiredMonsterCount} 不符合要求,必须为0到3000之间的整数`); + log.warn(`怪物数量 ${requiredMonsterCount} 不符合要求,必须为0以上的整数`); return; } if (isNaN(weight) || weight < 0) { @@ -158,12 +146,139 @@ async function fakeLog(name, isJs, isStart, duration) { return; } + // 检查是否所有配置都是默认状态 + const isDefaultConfig = ( + operationMode === "执行路径文件" && + requiredMonsterCount === 1750 && + !excludeWaterFree && + !excludeHighRisk && + weight === 2 && + !disableAutoPick && + enableCooldownCheck && + accountName === "一个账户名" && + globalExclusionKeywords === "不跑" + ); + + if (isDefaultConfig) { + log.warn(`你没有修改自定义配置,请在配置组界面中右键本js以修改自定义配置`); + await sleep(5000); + } + // 根据自定义配置,如果没有禁用自动拾取,则启用自动拾取 if (!disableAutoPick) { log.info("启用自动拾取的实时任务"); dispatcher.addTimer(new RealtimeTimer("AutoPick")); } + + const routeDir = 'route/'; // 文件夹路径 + + // 读取routeDir文件夹中的所有文件路径 + const filesInRouteDir = file.ReadPathSync(routeDir); + + // 检查路径组文件是否存在 + let doGenerate = true; + for (const filePath of filesInRouteDir) { + const fileName = basename(filePath); // 提取文件名 + if (fileName === `${outputFolderName}.txt`) { + doGenerate = false; + break; + } + } + + if (doGenerate) { + log.warn('路径组文件不存在,尝试重新生成'); + await sleep(5000); + } + + if (operationMode !== "执行路径文件" || doGenerate) { + // 筛选、排序并选取路线 + const indexPath = `index.txt`; + try { + const indexContent = await file.readText(indexPath); + const pathingFiles = indexContent.trim().split('\n').map(line => { + const parts = line.trim().split('\t'); + return { + name: parts[0], + monsterCount: parseFloat(parts[1]), + secPerMonster: parseFloat(parts[2]), + monsterPerSec: parseFloat(parts[3]), + isWaterFree: parseInt(parts[4], 10) === 1, + isHighRisk: parseInt(parts[5], 10) === 1, + efficiency: weight >= 5 ? parseFloat(parts[2]) : Math.pow(parseFloat(parts[2]), weight) * parseFloat(parts[3]), + selected: 0 + }; + }).filter(route => !isNaN(route.monsterCount) && route.monsterCount > 0 && Number.isInteger(route.monsterCount)); + + const sortedPathingFiles = [...pathingFiles]; + sortedPathingFiles.sort((a, b) => b.efficiency - a.efficiency || a.monsterCount - b.monsterCount); + + 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}):关键词条件 ${meetsKeywordCondition},水免条件 ${meetsWaterFreeCondition},高危条件 ${meetsHighRiskCondition}`); + + if (meetsKeywordCondition && meetsWaterFreeCondition && meetsHighRiskCondition) { + totalMonsterCount += route.monsterCount; + route.selected = 1; + selectedRoutes.push(route.name); + if (totalMonsterCount >= requiredMonsterCount) break; + } + } + + + if (totalMonsterCount < requiredMonsterCount) { + log.warn(`数量不足,最多可以包含 ${totalMonsterCount} 只怪物,不满足所需的 ${requiredMonsterCount} 只怪物`); + } + + // 根据操作模式执行相应的操作 + if (operationMode === "强制刷新路径文件" || doGenerate) { + // 使用 outputFolderName 作为路径组文件的名称,并添加 .txt 扩展名 + const pathGroupName = `${outputFolderName}.txt`; + const pathGroupFilePath = `route/${pathGroupName}`; + + + // 初始化CD信息的时间戳 + const initialCDTimestamp = "::2000-01-01T00:00:00.000Z"; + + // 按照 index.txt 中的顺序依次检验每个路线是否需要写入文件 + const resultContent = pathingFiles + .filter(route => selectedRoutes.includes(route.name)) + .map(route => `${route.name}${initialCDTimestamp}`) + .join('\n'); + + await file.writeText(pathGroupFilePath, resultContent); + log.info(`生成成功,共计 ${selectedRoutes.length} 条路线,路径组文件已保存到 ${pathGroupFilePath}`); + } else if (operationMode === "输出地图追踪文件") { + const pathingOutDir = `pathingout/${outputFolderName}/`; // 输出文件夹路径 + + // 将选中的地图追踪文件复制到对应的输出文件夹 + for (const routeName of selectedRoutes) { + const sourceFilePath = `${pathingDir}${routeName}.json`; + const targetFilePath = `${pathingOutDir}${routeName}.json`; + try { + const fileContent = await file.readText(sourceFilePath); + await file.writeText(targetFilePath, fileContent); + // log.debug(`文件 ${routeName}.json 已复制到 ${pathingOutDir}`); + successCount++; + } catch (error) { + log.warn(`复制文件 ${routeName}.json 时出错: ${error}`); + failCount++; + } + } + + log.info(`筛选完成,共计 ${selectedRoutes.length} 条路线。`); + log.info(`文件复制完成:成功 ${successCount} 个,失败 ${failCount} 个。`); + } + } catch (error) { + log.error(`读取路径文件索引文件 ${indexPath} 时出错: ${error}`); + } + } + // 判断操作模式是否为“执行路径文件”,若是则执行路径文件 if (operationMode === "执行路径文件") { try { @@ -235,95 +350,6 @@ async function fakeLog(name, isJs, isStart, duration) { } //伪造一个js开始的记录(实际上没必要) - //await fakeLog("自动精英锄地规划", true, true, 0); - return; + await fakeLog("自动精英锄地规划", true, true, 0); } - - // 筛选、排序并选取路线 - const indexPath = `index.txt`; - try { - const indexContent = await file.readText(indexPath); - const pathingFiles = indexContent.trim().split('\n').map(line => { - const parts = line.trim().split('\t'); - return { - name: parts[0], - monsterCount: parseFloat(parts[1]), - secPerMonster: parseFloat(parts[2]), - monsterPerSec: parseFloat(parts[3]), - isWaterFree: parseInt(parts[4], 10) === 1, - isHighRisk: parseInt(parts[5], 10) === 1, - efficiency: weight >= 5 ? parseFloat(parts[2]) : Math.pow(parseFloat(parts[2]), weight) * parseFloat(parts[3]), - selected: 0 - }; - }).filter(route => !isNaN(route.monsterCount) && route.monsterCount > 0 && Number.isInteger(route.monsterCount)); - - const sortedPathingFiles = [...pathingFiles]; - sortedPathingFiles.sort((a, b) => b.efficiency - a.efficiency || a.monsterCount - b.monsterCount); - - 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}):关键词条件 ${meetsKeywordCondition},水免条件 ${meetsWaterFreeCondition},高危条件 ${meetsHighRiskCondition}`); - - if (meetsKeywordCondition && meetsWaterFreeCondition && meetsHighRiskCondition) { - totalMonsterCount += route.monsterCount; - route.selected = 1; - selectedRoutes.push(route.name); - if (totalMonsterCount >= requiredMonsterCount) break; - } - } - - - if (totalMonsterCount < requiredMonsterCount) { - log.warn(`数量不足,最多可以包含 ${totalMonsterCount} 只怪物,不满足所需的 ${requiredMonsterCount} 只怪物`); - } - - // 根据操作模式执行相应的操作 - if (operationMode === "生成路径文件") { - // 使用 outputFolderName 作为路径组文件的名称,并添加 .txt 扩展名 - const pathGroupName = `${outputFolderName}.txt`; - const pathGroupFilePath = `route/${pathGroupName}`; - - - // 初始化CD信息的时间戳 - const initialCDTimestamp = "::2000-01-01T00:00:00.000Z"; - - // 按照 index.txt 中的顺序依次检验每个路线是否需要写入文件 - const resultContent = pathingFiles - .filter(route => selectedRoutes.includes(route.name)) - .map(route => `${route.name}${initialCDTimestamp}`) - .join('\n'); - - await file.writeText(pathGroupFilePath, resultContent); - log.info(`生成成功,共计 ${selectedRoutes.length} 条路线,路径组文件已保存到 ${pathGroupFilePath},请将js自定义配置中操作模式改为执行路径文件以执行`); - } else if (operationMode === "输出地图追踪文件") { - const pathingOutDir = `pathingout/${outputFolderName}/`; // 输出文件夹路径 - - // 将选中的地图追踪文件复制到对应的输出文件夹 - for (const routeName of selectedRoutes) { - const sourceFilePath = `${pathingDir}${routeName}.json`; - const targetFilePath = `${pathingOutDir}${routeName}.json`; - try { - const fileContent = await file.readText(sourceFilePath); - await file.writeText(targetFilePath, fileContent); - // log.debug(`文件 ${routeName}.json 已复制到 ${pathingOutDir}`); - successCount++; - } catch (error) { - log.warn(`复制文件 ${routeName}.json 时出错: ${error}`); - failCount++; - } - } - - log.info(`筛选完成,共计 ${selectedRoutes.length} 条路线。`); - log.info(`文件复制完成:成功 ${successCount} 个,失败 ${failCount} 个。`); - } - } catch (error) { - log.error(`读取路径文件索引文件 ${indexPath} 时出错: ${error}`); - } - - log.info('脚本执行完成'); })(); diff --git a/repo/js/自动小怪锄地规划/settings.json b/repo/js/自动小怪锄地规划/settings.json index 4cb2816f..3d30cd21 100644 --- a/repo/js/自动小怪锄地规划/settings.json +++ b/repo/js/自动小怪锄地规划/settings.json @@ -4,10 +4,11 @@ "type": "select", "label": "操作模式(默认:生成路径文件)", "options": [ - "生成路径文件", + "强制刷新路径文件", "执行路径文件", "输出地图追踪文件" - ] + ], + "default": "执行路径文件" }, { "name": "excludeWaterFree", diff --git a/repo/js/自动精英锄地规划/main.js b/repo/js/自动精英锄地规划/main.js index 13d52c4b..a9f5faa5 100644 --- a/repo/js/自动精英锄地规划/main.js +++ b/repo/js/自动精英锄地规划/main.js @@ -22,7 +22,10 @@ async function fakeLog(name, isJs, isStart, duration) { log.error("参数 'isStart' 必须是布尔型!"); return; } -// Removed redundant type and integer checks for `currentTime`. + if (typeof currentTime !== 'number' || !Number.isInteger(currentTime)) { + log.error("参数 'currentTime' 必须是整数!"); + return; + } if (typeof duration !== 'number' || !Number.isInteger(duration)) { log.error("参数 'duration' 必须是整数!"); return; @@ -80,10 +83,15 @@ async function fakeLog(name, isJs, isStart, duration) { } } +// 定义自定义函数 basename,用于获取文件名 +function basename(filePath) { + const lastSlashIndex = filePath.lastIndexOf('\\'); // 或者使用 '/',取决于你的路径分隔符 + return filePath.substring(lastSlashIndex + 1); +} (async function () { // 初始化配置 - const operationType = settings.operationType || "生成路径组文件"; // 操作模式 + const operationType = settings.operationType || "执行路径组文件1"; // 操作模式 let excludeTagsForPathGroup1 = settings.excludeTagsForPathGroup1 || ""; // 路径组1排除标签 let selectTagsForPathGroup2 = settings.selectTagsForPathGroup2 || ""; // 路径组2选择标签 let selectTagsForPathGroup3 = settings.selectTagsForPathGroup3 || ""; // 路径组3选择标签 @@ -107,23 +115,6 @@ async function fakeLog(name, isJs, isStart, duration) { // 根据 disableRouteCdCheck 的值设置 enableRouteCdCheck const enableRouteCdCheck = !disableRouteCdCheck; // 如果 disableRouteCdCheck 为 true,则 enableRouteCdCheck 为 false,反之亦然 - //当用户所有自定义配置均为默认时警告用户 - if ( - operationType === "生成路径组文件" && - excludeTagsForPathGroup1 === "" && - selectTagsForPathGroup2 === "" && - selectTagsForPathGroup3 === "" && - disableAutoPickup === false && - disableRouteCdCheck === false && - requiredMonsterCount === 405 && - minSecPerMonster === 0.1 && - accountName === "一个账户名" && - excludeTagsForAll === "" - ) { - log.warn("所有配置项均为默认状态,请检查是否需要调整配置。你没有修改自定义配置,请在配置组界面中右键本js以修改自定义配置。"); - } - - // 初始化文件路径(直接内置生成) const indexPath = 'index.txt'; const pathingDir = 'pathing/'; @@ -143,7 +134,6 @@ async function fakeLog(name, isJs, isStart, duration) { // 初始化一个变量,用于判断是否是执行路径组文件的模式 let executePathGroupMode = 0; - // 分别检验是否是执行路径组文件1、执行路径组文件2、执行路径组文件3 if (operationType === "执行路径组文件1") { executePathGroupMode = 1; @@ -153,298 +143,340 @@ async function fakeLog(name, isJs, isStart, duration) { executePathGroupMode = 3; } - // 如果是执行路径组文件的模式 - if (executePathGroupMode > 0) { - // 检查是否禁用了自动拾取 - if (!disableAutoPickup) { - // 启用自动拾取 - dispatcher.addTimer(new RealtimeTimer("AutoPick")); - } else { - // 禁用自动拾取 - log.warn("自动拾取已禁用"); + //当用户所有自定义配置均为默认时警告用户 + if ( + operationType === "执行路径组文件1" && + excludeTagsForPathGroup1 === "" && + selectTagsForPathGroup2 === "" && + selectTagsForPathGroup3 === "" && + disableAutoPickup === false && + disableRouteCdCheck === false && + requiredMonsterCount === 405 && + minSecPerMonster === 0.1 && + accountName === "一个账户名" && + excludeTagsForAll === "不跑" + ) { + log.warn("所有配置项均为默认状态,你没有修改自定义配置,请在配置组界面中右键本js以修改自定义配置。"); + await sleep(5000); + } + + // 尝试判断路径组文件是否存在 + const pathGroupNumber = executePathGroupMode; + + // 构造路径组文件路径 + const pathGroupFilePath = `${routeDir}路径组${pathGroupNumber}-${outputFolderName}.txt`; + + // 读取routeDir文件夹中的所有文件路径 + const filesInRouteDir = await file.ReadPathSync(routeDir); + + // 检查路径组文件是否存在 + let doGenerate = true; + for (const filePath of filesInRouteDir) { + const fileName = basename(filePath); // 提取文件名 + if (fileName === `路径组${pathGroupNumber}-${outputFolderName}.txt`) { + doGenerate = false; + break; + } + } + + if (doGenerate) { + log.warn(`路径组文件不存在,尝试先生成路径组文件`); + } + + if (executePathGroupMode === 0) { + doGenerate = true; + log.info(`尝试生成路径组文件`); + } + + { + if (doGenerate) { + // 不为执行模式或路径组文件不存在,进行排序、筛选和选取路径 + let totalMonsterCount = 0; + try { + const indexContent = await file.readText(indexPath); + const pathingFiles = indexContent.trim().split('\n').slice(1).map(line => { + const data = line.trim().split('\t'); + if (data.length !== 11) { // 列数为11 + log.warn(`不符合预期格式的行:${line}`); + return null; + } + const keywords = data[0].trim(); // 新的第一列是关键词信息 + return { + keywords: keywords, + legendary: parseInt(data[1], 10) === 1, + waterFree: parseInt(data[2], 10) === 1, + timeshield: parseInt(data[3], 10) === 1, + highRisk: parseInt(data[4], 10) === 1, + monsterCount: parseFloat(data[5]), + secPerMonster: parseFloat(data[9]), + name: data[10].trim(), + group: 0 // 新增 group 参数,初始值为 0 + }; + }).filter(route => route !== null); + + // 筛选和排序路径 + const priority600Routes = pathingFiles + .filter(route => route.name.includes('600') && !excludeTagsForAllArray.some(tag => route.name.includes(tag) || route.keywords.includes(tag))) + .sort((a, b) => { + if (a.secPerMonster === b.secPerMonster) { + return a.monsterCount - b.monsterCount; // 次要排序依据:怪物数量升序 + } + return b.secPerMonster - a.secPerMonster; // 主要排序依据:秒均降序 + }); + + const priority400Routes = pathingFiles + .filter(route => route.name.includes('400') && !excludeTagsForAllArray.some(tag => route.name.includes(tag) || route.keywords.includes(tag))) + .sort((a, b) => { + if (a.secPerMonster === b.secPerMonster) { + return a.monsterCount - b.monsterCount; // 次要排序依据:怪物数量升序 + } + return b.secPerMonster - a.secPerMonster; // 主要排序依据:秒均降序 + }); + + const remainingRoutes = pathingFiles + .filter(route => !priority600Routes.includes(route) && !priority400Routes.includes(route) && !excludeTagsForAllArray.some(tag => route.name.includes(tag) || route.keywords.includes(tag))) + .sort((a, b) => { + if (a.secPerMonster === b.secPerMonster) { + return a.monsterCount - b.monsterCount; // 次要排序依据:怪物数量升序 + } + return b.secPerMonster - a.secPerMonster; // 主要排序依据:秒均降序 + }); + + // 合并所有路径 + const sortedRoutes = [...priority600Routes, ...priority400Routes, ...remainingRoutes]; + + // 分配路径到路径组 + const pathGroups = [[], [], []]; + for (const path of sortedRoutes) { + if (totalMonsterCount >= requiredMonsterCount) { + break; + } + + // 为每个路径组生成一个对应的字符串 + const excludeTags1 = excludeTagsForPathGroup1.split('.'); + const excludeTags1String = excludeTags1.map(tag => { + switch (tag) { + case "传奇": + return path.legendary ? '1' : '0'; + case "水免": + return path.waterFree ? '1' : '0'; + case "次数盾": + return path.timeshield ? '1' : '0'; + case "高危": + return path.highRisk ? '1' : '0'; + default: + return '0'; + } + }).join(''); + + const selectTags2 = selectTagsForPathGroup2.split('.'); + const selectTags2String = selectTags2.map(tag => { + switch (tag) { + case "传奇": + return path.legendary ? '1' : '0'; + case "水免": + return path.waterFree ? '1' : '0'; + case "次数盾": + return path.timeshield ? '1' : '0'; + case "高危": + return path.highRisk ? '1' : '0'; + default: + return '0'; + } + }).join(''); + + const selectTags3 = selectTagsForPathGroup3.split('.'); + const selectTags3String = selectTags3.map(tag => { + switch (tag) { + case "传奇": + return path.legendary ? '1' : '0'; + case "水免": + return path.waterFree ? '1' : '0'; + case "次数盾": + return path.timeshield ? '1' : '0'; + case "高危": + return path.highRisk ? '1' : '0'; + default: + return '0'; + } + }).join(''); + + // 检查路径是否符合路径组1的条件 + const excludeTags1Mask = excludeTags1.map(tag => tag === '1' ? '1' : '0').join(''); + if (excludeTags1String === excludeTags1Mask) { // 反转逻辑:如果路径包含任何排除标签,则入选路径组1 + path.group = 1; + pathGroups[0].push(path); + totalMonsterCount += path.monsterCount; + continue; + } + + // 检查路径是否符合路径组2的条件 + const selectTags2Mask = selectTags2.map(tag => tag === '1' ? '1' : '0').join(''); + if (selectTags2String !== selectTags2Mask) { // 反转逻辑:如果路径不包含任何选择的标签,则入选路径组2 + path.group = 2; + pathGroups[1].push(path); + totalMonsterCount += path.monsterCount; + continue; + } + + // 检查路径是否符合路径组3的条件 + const selectTags3Mask = selectTags3.map(tag => tag === '1' ? '1' : '0').join(''); + if (selectTags3String !== selectTags3Mask) { // 反转逻辑:如果路径不包含任何选择的标签,则入选路径组3 + path.group = 3; + pathGroups[2].push(path); + totalMonsterCount += path.monsterCount; + continue; + } + } + + // 再次根据 operationType 决定生成路径组文件还是输出地图追踪文件 + if (operationType === "强制刷新路径组文件" || executePathGroupMode > 0) { + // 生成路径组文件的逻辑 + for (let i = 0; i < 3; i++) { + const pathGroup = pathGroups[i]; + const pathGroupFilePath = `${routeDir}路径组${i + 1}-${outputFolderName}.txt`; + if (pathGroup.length > 0) { + // 按照 index.txt 中的顺序输出路径,并在每个路径名称后添加 "2000-01-01T00:00:00.000Z",以初始化cd信息 + const sortedPathNames = pathingFiles + .filter(path => pathGroup.some(groupPath => groupPath.name === path.name)) + .map(path => `${path.name}::2000-01-01T00:00:00.000Z`); + const pathGroupContent = sortedPathNames.join('\n'); + await file.writeText(pathGroupFilePath, pathGroupContent); + log.info(`生成并刷新路径组${i + 1}文件成功,路径数:${sortedPathNames.length}`); + } + } + log.info(`怪物总数${totalMonsterCount},请修改js自定义配置中的操作模式以执行文件`); + } else if (operationType === "输出地图追踪文件") { + // 输出地图追踪文件的逻辑 + for (let i = 0; i < 3; i++) { + const pathGroup = pathGroups[i]; + const outputFolder = `pathingout/${outputFolderName}/路径组${i + 1}`; + let successCount = 0; + let failCount = 0; + for (const path of pathGroup) { + const sourceFilePath = `${pathingDir}${path.name}.json`; + const targetFilePath = `${outputFolder}/${path.name}.json`; + try { + const fileContent = await file.readText(sourceFilePath); + await file.writeText(targetFilePath, fileContent); + successCount++; + } catch (error) { + log.warn(`复制 ${sourceFilePath} 到 ${targetFilePath} 失败:${error}`); + failCount++; + } + } + log.info(`路径组${i + 1}复制完成:成功 ${successCount} 个,失败 ${failCount} 个`); + } + log.info(`怪物总数${totalMonsterCount},请前往pathingout文件夹提取文件`); + } + } catch (error) { + log.error(`读取索引文件失败:${error}`); + } } - //伪造js结束的记录 - await fakeLog("自动精英锄地规划", true, false, 1); - - // 根据 executePathGroupMode 获取路径组编号 - const pathGroupNumber = executePathGroupMode; - - // 构造路径组文件路径 - const pathGroupFilePath = `${routeDir}路径组${pathGroupNumber}-${outputFolderName}.txt`; - - try { - // 读取路径组文件内容 - const pathGroupContent = await file.readText(pathGroupFilePath); - const pathLines = pathGroupContent.trim().split('\n'); // 定义 pathLines 变量 - - // 遍历路径名称列表,依次执行每个路径 - for (let i = 0; i < pathLines.length; i++) { - const pathLine = pathLines[i]; - // 解析路径名称和后面的 ISO 时间字符串 - const [pathName, pathCD] = pathLine.split('::').map(part => part.trim()); - const pathFilePath = `${pathingDir}${pathName}.json`; - - // 获取当前时间 - const now = new Date(); - const startTime = now.toISOString(); // 获取开始时间 - - // 如果启用了路线CD检测,检查当前时间是否不早于附加时间戳 - if (enableRouteCdCheck) { - const pathCDDate = new Date(pathCD); // 将附加时间戳转换为Date对象 - if (now < pathCDDate) { - log.info(`当前路线 ${pathName} 为第 ${i + 1}/${pathLines.length} 个,当前路线未刷新,放弃该路径`); - 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(); // 获取结束时间 - - // 检查执行时间是否超过3秒 - const executionTime = endTime.getTime() - now.getTime(); - - //伪造地图追踪结束的记录 - 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 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}::${nextFourClock.toISOString()}`; - log.info(`当前路线 ${pathName} 执行完成,可用时间更新为:${nextFourClockFormatted}`); - - // 将更新后的内容写回路径组文件 - const updatedPathGroupContent = pathLines.join('\n'); - await file.writeText(pathGroupFilePath, updatedPathGroupContent); + { + // 执行路径组文件的模式 + if (executePathGroupMode > 0) { + // 检查是否禁用了自动拾取 + if (!disableAutoPickup) { + // 启用自动拾取 + dispatcher.addTimer(new RealtimeTimer("AutoPick")); } else { - log.info(`当前路线 ${pathName} 执行完成,但不更新可用时间,因为执行时间不足10秒或未启用cd检测。`); + // 禁用自动拾取 + log.warn("自动拾取已禁用"); } - } - } catch (error) { - log.error(`读取路径组文件失败:${error}`); - return; - } - //伪造一个js开始的记录 - await fakeLog("自动精英锄地规划", true, true, 0); + //伪造js结束的记录 + await fakeLog("自动精英锄地规划", true, false, 1); - // 执行完成后退出程序 - return; - } + try { + // 读取路径组文件内容 + const pathGroupContent = await file.readText(pathGroupFilePath); + const pathLines = pathGroupContent.trim().split('\n'); // 定义 pathLines 变量 - // 否则:进行排序、筛选和选取路径 - let totalMonsterCount = 0; + // 遍历路径名称列表,依次执行每个路径 + for (let i = 0; i < pathLines.length; i++) { + const pathLine = pathLines[i]; + // 解析路径名称和后面的 ISO 时间字符串 + const [pathName, pathCD] = pathLine.split('::').map(part => part.trim()); + const pathFilePath = `${pathingDir}${pathName}.json`; - try { - const indexContent = await file.readText(indexPath); - const pathingFiles = indexContent.trim().split('\n').slice(1).map(line => { - const data = line.trim().split('\t'); - if (data.length !== 11) { // 假设列数为11 - log.warn(`不符合预期格式的行:${line}`); - return null; - } - const keywords = data[0].trim(); // 新的第一列是关键词信息 - return { - keywords: keywords, - legendary: parseInt(data[1], 10) === 1, - waterFree: parseInt(data[2], 10) === 1, - timeshield: parseInt(data[3], 10) === 1, - highRisk: parseInt(data[4], 10) === 1, - monsterCount: parseFloat(data[5]), - secPerMonster: parseFloat(data[9]), - name: data[10].trim(), - group: 0 // 新增 group 参数,初始值为 0 - }; - }).filter(route => route !== null); + // 获取当前时间 + const now = new Date(); + const startTime = now.toISOString(); // 获取开始时间 - // 筛选和排序路径 - const priority600Routes = pathingFiles - .filter(route => route.name.includes('600') && !excludeTagsForAllArray.some(tag => route.name.includes(tag) || route.keywords.includes(tag))) - .sort((a, b) => { - if (a.secPerMonster === b.secPerMonster) { - return a.monsterCount - b.monsterCount; // 次要排序依据:怪物数量升序 - } - return b.secPerMonster - a.secPerMonster; // 主要排序依据:秒均降序 - }); + // 如果启用了路线CD检测,检查当前时间是否不早于附加时间戳 + if (enableRouteCdCheck) { + const pathCDDate = new Date(pathCD); // 将附加时间戳转换为Date对象 + if (now < pathCDDate) { + log.info(`当前路线 ${pathName} 为第 ${i + 1}/${pathLines.length} 个,当前路线未刷新,放弃该路径`); + await sleep(10); + continue; // 放弃该路径 + } + } - const priority400Routes = pathingFiles - .filter(route => route.name.includes('400') && !excludeTagsForAllArray.some(tag => route.name.includes(tag) || route.keywords.includes(tag))) - .sort((a, b) => { - if (a.secPerMonster === b.secPerMonster) { - return a.monsterCount - b.monsterCount; // 次要排序依据:怪物数量升序 - } - return b.secPerMonster - a.secPerMonster; // 主要排序依据:秒均降序 - }); + log.info(`当前路线 ${pathName} 为第 ${i + 1}/${pathLines.length} 个,当前路线已刷新或未启用cd检测,执行路径`); - const remainingRoutes = pathingFiles - .filter(route => !priority600Routes.includes(route) && !priority400Routes.includes(route) && !excludeTagsForAllArray.some(tag => route.name.includes(tag) || route.keywords.includes(tag))) - .sort((a, b) => { - if (a.secPerMonster === b.secPerMonster) { - return a.monsterCount - b.monsterCount; // 次要排序依据:怪物数量升序 - } - return b.secPerMonster - a.secPerMonster; // 主要排序依据:秒均降序 - }); + //伪造地图追踪开始的日志记录 + await fakeLog(pathName + ".json", false, true, 0); // 开始时 duration 通常为 0 - // 合并所有路径 - const sortedRoutes = [...priority600Routes, ...priority400Routes, ...remainingRoutes]; + // 执行路径文件 + await pathingScript.runFile(pathFilePath); - // 分配路径到路径组 - const pathGroups = [[], [], []]; - for (const path of sortedRoutes) { - if (totalMonsterCount >= requiredMonsterCount) { - break; - } + //捕获任务取消的错误并跳出循环 + try { + await sleep(10); + } catch (error) { + log.error(`发生错误: ${error}`); + break; // 终止循环 + } - // 为每个路径组生成一个对应的字符串 - const excludeTags1 = excludeTagsForPathGroup1.split('.'); - const excludeTags1String = excludeTags1.map(tag => { - switch (tag) { - case "传奇": - return path.legendary ? '1' : '0'; - case "水免": - return path.waterFree ? '1' : '0'; - case "次数盾": - return path.timeshield ? '1' : '0'; - case "高危": - return path.highRisk ? '1' : '0'; - default: - return '0'; - } - }).join(''); + // 获取结束时间 + const endTime = new Date(); + const endTimeISO = endTime.toISOString(); // 获取结束时间 - const selectTags2 = selectTagsForPathGroup2.split('.'); - const selectTags2String = selectTags2.map(tag => { - switch (tag) { - case "传奇": - return path.legendary ? '1' : '0'; - case "水免": - return path.waterFree ? '1' : '0'; - case "次数盾": - return path.timeshield ? '1' : '0'; - case "高危": - return path.highRisk ? '1' : '0'; - default: - return '0'; - } - }).join(''); + // 检查执行时间是否超过3秒 + const executionTime = endTime.getTime() - now.getTime(); - const selectTags3 = selectTagsForPathGroup3.split('.'); - const selectTags3String = selectTags3.map(tag => { - switch (tag) { - case "传奇": - return path.legendary ? '1' : '0'; - case "水免": - return path.waterFree ? '1' : '0'; - case "次数盾": - return path.timeshield ? '1' : '0'; - case "高危": - return path.highRisk ? '1' : '0'; - default: - return '0'; - } - }).join(''); + //伪造地图追踪结束的记录 + await fakeLog(pathName + ".json", false, false, executionTime); - // 检查路径是否符合路径组1的条件 - const excludeTags1Mask = excludeTags1.map(tag => tag === '1' ? '1' : '0').join(''); - if (excludeTags1String === excludeTags1Mask) { // 反转逻辑:如果路径包含任何排除标签,则入选路径组1 - path.group = 1; - pathGroups[0].push(path); - totalMonsterCount += path.monsterCount; - continue; - } - // 检查路径是否符合路径组2的条件 - const selectTags2Mask = selectTags2.map(tag => tag === '1' ? '1' : '0').join(''); - if (selectTags2String !== selectTags2Mask) { // 反转逻辑:如果路径不包含任何选择的标签,则入选路径组2 - path.group = 2; - pathGroups[1].push(path); - totalMonsterCount += path.monsterCount; - continue; - } + // 如果启用了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); // 设置时间为下一个凌晨四点 + } - // 检查路径是否符合路径组3的条件 - const selectTags3Mask = selectTags3.map(tag => tag === '1' ? '1' : '0').join(''); - if (selectTags3String !== selectTags3Mask) { // 反转逻辑:如果路径不包含任何选择的标签,则入选路径组3 - path.group = 3; - pathGroups[2].push(path); - totalMonsterCount += path.monsterCount; - continue; - } - } + // 转换为北京时间(UTC+8) + 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')}`; - // 再次根据 operationType 决定生成路径组文件还是输出地图追踪文件 - if (operationType === "生成路径组文件") { - // 生成路径组文件的逻辑 - for (let i = 0; i < 3; i++) { - const pathGroup = pathGroups[i]; - const pathGroupFilePath = `${routeDir}路径组${i + 1}-${outputFolderName}.txt`; - if (pathGroup.length > 0) { - // 按照 index.txt 中的顺序输出路径,并在每个路径名称后添加 "2000-01-01T00:00:00.000Z",以初始化cd信息 - const sortedPathNames = pathingFiles - .filter(path => pathGroup.some(groupPath => groupPath.name === path.name)) - .map(path => `${path.name}::2000-01-01T00:00:00.000Z`); - const pathGroupContent = sortedPathNames.join('\n'); - await file.writeText(pathGroupFilePath, pathGroupContent); - log.info(`生成并刷新路径组${i + 1}文件成功,路径数:${sortedPathNames.length}`); - } - } - log.info(`怪物总数${totalMonsterCount},请修改js自定义配置中的操作模式以执行文件`); - } else if (operationType === "输出地图追踪文件") { - // 输出地图追踪文件的逻辑 - for (let i = 0; i < 3; i++) { - const pathGroup = pathGroups[i]; - const outputFolder = `pathingout/${outputFolderName}/路径组${i + 1}`; - let successCount = 0; - let failCount = 0; - for (const path of pathGroup) { - const sourceFilePath = `${pathingDir}${path.name}.json`; - const targetFilePath = `${outputFolder}/${path.name}.json`; - try { - const fileContent = await file.readText(sourceFilePath); - await file.writeText(targetFilePath, fileContent); - successCount++; - } catch (error) { - log.warn(`复制 ${sourceFilePath} 到 ${targetFilePath} 失败:${error}`); - failCount++; + // 更新路径组文件中的附加时间戳 + pathLines[i] = `${pathName}::${nextFourClock.toISOString()}`; + log.info(`当前路线 ${pathName} 执行完成,可用时间更新为:${nextFourClockFormatted}`); + + // 将更新后的内容写回路径组文件 + const updatedPathGroupContent = pathLines.join('\n'); + await file.writeText(pathGroupFilePath, updatedPathGroupContent); + } else { + log.info(`当前路线 ${pathName} 执行完成,但不更新可用时间,因为执行时间不足10秒或未启用cd检测。`); + } } + } catch (error) { + log.error(`读取路径组文件失败:${error}`); + return; } - log.info(`路径组${i + 1}复制完成:成功 ${successCount} 个,失败 ${failCount} 个`); - } - log.info(`怪物总数${totalMonsterCount},请前往pathingout文件夹提取文件`); - } - } catch (error) { - log.error(`读取索引文件失败:${error}`); - } -})(); + + //伪造一个js开始的记录 + await fakeLog("自动精英锄地规划", true, true, 0); + } + } + } +} +)(); diff --git a/repo/js/自动精英锄地规划/settings.json b/repo/js/自动精英锄地规划/settings.json index 9c126451..32fda2d0 100644 --- a/repo/js/自动精英锄地规划/settings.json +++ b/repo/js/自动精英锄地规划/settings.json @@ -2,14 +2,15 @@ { "name": "operationType", "type": "select", - "label": "操作模式(默认:生成路径组文件)", + "label": "操作模式(默认:执行路径组文件1)", "options": [ - "生成路径组文件", + "强制刷新路径组文件", "执行路径组文件1", "执行路径组文件2", "执行路径组文件3", "输出地图追踪文件" - ] + ], + "default":"执行路径组文件1" }, { "name": "excludeTagsForPathGroup1", @@ -49,7 +50,8 @@ { "name": "excludeTagsForAll", "type": "input-text", - "label": "全局排除关键词(使用中文分号分隔)" + "label": "全局排除关键词(使用中文分号分隔)", + "default": "不跑" }, { "name": "accountName",