自动锄地规划: 默认配置下的警告增加了五秒的警告,且在找不到文件时先尝试生成 (#902)

* 一些js更新

* js:修正逻辑,现在路径组文件不存在时会先尝试生成文件
This commit is contained in:
mno
2025-05-21 22:41:38 +08:00
committed by GitHub
parent ed1abf48a8
commit d09a760d24
4 changed files with 471 additions and 410 deletions

View File

@@ -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('脚本执行完成');
})();

View File

@@ -4,10 +4,11 @@
"type": "select",
"label": "操作模式(默认:生成路径文件)",
"options": [
"生成路径文件",
"强制刷新路径文件",
"执行路径文件",
"输出地图追踪文件"
]
],
"default": "执行路径文件"
},
{
"name": "excludeWaterFree",

View File

@@ -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);
}
}
}
}
)();

View File

@@ -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",