js:自动小怪锄地路径规划,自动化规划和执行精英锄地,并支持配置自动拾取和路线刷新检测 地图追踪:小怪锄地2000和死亡笔记2400中2000部分相应更新 (#692)

This commit is contained in:
mno
2025-05-03 16:36:00 +08:00
committed by GitHub
parent c435d41e11
commit 51c0da9b68
239 changed files with 29299 additions and 535 deletions

View File

@@ -0,0 +1,201 @@
(async function () {
// 初始化所有用到的参数
const operationMode = settings.operationMode || "生成路径文件"; // 默认值为“生成路径文件”
const requiredMonsterCount = parseInt(settings.requiredMonsterCount || 1800, 10); // 默认值为1800
const excludeWaterFree = !!settings.excludeWaterFree; // 默认值为false默认不排除
const excludeHighRisk = !!settings.excludeHighRisk; // 默认值为false默认不排除
const weight = parseFloat(settings.weight || 2); // 默认值为2
const disableAutoPick = !!settings.disableAutoPick; // 默认值为false默认不禁用
const enableCooldownCheck = !!settings.enableCooldownCheck; // 默认值为false默认不启用
const pathingDir = 'pathing/'; // 初始化pathingDir参数
// 初始化用于计数的变量
let outputFolderName = ""; // 初始化为空
let totalMonsterCount = 0; // 筛选出的怪物总数
let selectedRoutes = []; // 筛选出的路线数组
let successCount = 0; // 成功复制的文件数量
let failCount = 0; // 失败复制的文件数量
let routeIndex = 0; // 当前筛选的路线序号
// 日志输出配置参数
log.info(
`自动小怪锄地规划 - 配置信息:` +
`操作模式=${operationMode}(默认:生成路径文件),` +
`怪物数量=${requiredMonsterCount}默认1800` +
`${excludeWaterFree ? '排除水免(默认:不排除)' : '包含水免(默认)'}` +
`${excludeHighRisk ? '排除高危(默认:不排除)' : '包含高危(默认)'}` +
`权重=${weight}默认2` +
`自动拾取=${disableAutoPick ? '禁用' : '启用'}`
);
// 验证配置参数
if (
isNaN(requiredMonsterCount) ||
requiredMonsterCount < 0 ||
requiredMonsterCount > 2000 ||
!Number.isInteger(requiredMonsterCount)
) {
log.warn(`怪物数量 ${requiredMonsterCount} 不符合要求必须为0到2000之间的整数`);
return;
}
if (isNaN(weight) || weight < 0) {
log.warn(`权重 ${weight} 不符合要求必须为0及以上的数`);
return;
}
// 文件夹/文件名称,则使用默认规则命名
outputFolderName = `${requiredMonsterCount}${excludeWaterFree ? '排除水免' : '包含水免'}${excludeHighRisk ? '排除高危' : '包含高危'}权重${weight}`;
// 根据自定义配置,如果没有禁用自动拾取,则启用自动拾取
if (!disableAutoPick) {
log.info("启用自动拾取的实时任务");
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
}
// 判断操作模式是否为“执行路径文件”
if (operationMode === "执行路径文件") {
const pathGroupName = `${requiredMonsterCount}${excludeWaterFree ? '排除水免' : '包含水免'}${excludeHighRisk ? '排除高危' : '包含高危'}权重${weight}.txt`;
const pathGroupFilePath = `route/${pathGroupName}`;
try {
const savedRoutesContent = await file.readText(pathGroupFilePath);
const savedRoutes = savedRoutesContent.trim().split('\n');
for (let i = 0; i < savedRoutes.length; i++) {
// 分离路线名称和时间戳
const routeWithTimestamp = savedRoutes[i].trim();
const [routeName, routeTimestamp] = routeWithTimestamp.split('::');
log.info(`当前任务为第 ${i + 1}/${savedRoutes.length}`);
// 获取开始时间
const startTime = new Date();
// 比较当前时间戳与路线的时间戳
if (enableCooldownCheck) {
const routeDate = new Date(routeTimestamp);
if (startTime <= routeDate) {
log.info(`当前路线未刷新,跳过路线 ${routeName}`); // 修改后的日志输出
continue; // 跳过当前路线
}
}
const pathingFilePath = `${pathingDir}${routeName}.json`;
try {
await pathingScript.runFile(pathingFilePath);
// 获取结束时间
const endTime = new Date();
// 比较开始时间与结束时间
const timeDiff = endTime.getTime() - startTime.getTime(); // 时间差(毫秒)
if (enableCooldownCheck && timeDiff > 10000) { // 时间差大于10秒
// 将路径组文件中对应的时间戳改为开始时间后12小时0分0秒
const newTimestamp = new Date(startTime.getTime() + 12 * 60 * 60 * 1000).toISOString();
const nextAvailableTime = new Date(newTimestamp).toLocaleString(); // 转换为本地时间格式
// 更新路径组文件中的时间戳
const updatedRoutes = savedRoutes.map(route => {
const [name, timestamp] = route.split('::');
if (name === routeName) {
return `${name}::${newTimestamp}`;
}
return route;
}).join('\n');
await file.writeText(pathGroupFilePath, updatedRoutes);
log.info(`本路线执行大于10秒cd信息已更新下一次可用时间为 ${nextAvailableTime}`);
}
} catch (error) {
log.error(`路径文件 ${pathingFilePath} 不存在,跳过该路径`);
}
}
log.info('所有路径运行完成');
} catch (error) {
log.error(`读取路径组文件 ${pathGroupFilePath} 时出错: ${error}`);
}
log.info('脚本执行完成');
return; // 退出程序
}
// 筛选、排序并选取路线
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 meetsWaterFreeCondition = !excludeWaterFree || !route.isWaterFree;
const meetsHighRiskCondition = !excludeHighRisk || !route.isHighRisk;
// 修改后的日志输出,增加当前路线的序号
//log.debug(`筛选路线 ${routeIndex}${route.name}):水免条件 ${meetsWaterFreeCondition},高危条件 ${meetsHighRiskCondition}`);
if (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 === "生成路径文件") {
const pathGroupName = `${requiredMonsterCount}${excludeWaterFree ? '排除水免' : '包含水免'}${excludeHighRisk ? '排除高危' : '包含高危'}权重${weight}.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}`);
}
log.info('脚本执行完成');
})();