修复终止翻页逻辑,测算模式调整,压缩log (#3058)

修复终止翻页逻辑,测算模式调整,压缩log
This commit is contained in:
吉吉喵
2026-04-02 12:39:56 +08:00
committed by GitHub
parent a250685bb6
commit 0e545bdd3f
10 changed files with 126 additions and 85 deletions

View File

@@ -1,4 +1,4 @@
# 背包材料统计 v2.62
# 背包材料统计 v2.68
作者:吉吉喵
<!-- 新增:全局图片样式,控制连续图片同行显示 -->
@@ -208,21 +208,21 @@ A记录文件夹位于 `BetterGI\User\JsScript\背包材料统计\` 下,各
| v1.3 | 优化:加速材料寻找(新增前位材料识别) |
| v1.31 | 调整本地记录存储逻辑 |
| v1.32 | 新增后位材料识别功能 |
| v2.0 | 开发版:支持多组材料、多个分类;移除前/后位材料识别 |
| v2.0 | 开发版:支持多组材料、多个分类;移除前/后位材料识别 |
| v2.1 | 新增CD管理功能 |
| v2.2 | 优化路径顺序、材料数量判断逻辑 |
| v2.21 | 修改路径储存路径 |
| v2.22 | 精简日志输出内容 |
| v2.23 | 优化部分函数性能 |
| v2.24 | 修复“空路径无法使用背包统计”等bug |
| v2.25 | 恢复前/后位材料识别(加速扫描);新增“仅扫描路径材料”选项(降低内存占用) |
| v2.25 | 恢复前/后位材料识别(加速扫描);新增“仅扫描路径材料”选项(降低内存占用)|
| v2.26 | 修复材料时间读取错误;新增路径材料时间成本计算功能 |
| v2.27 | 修复“材料数计算错误”“目标数量临界值异常”“3识别成三”等bug |
| v2.28 | 材料变更时自动更新初始数量排除0位移/0数量路径记录新增材料名0后缀本地记录新增背包弹窗识别 |
| v2.29 | 新增排除提示;调整平均时间成本计算逻辑;过滤异常值记录 |
| v2.30 | 更改路径专注模式默认值;增加日志提示;移除调试日志 |
| v2.29 | 新增排除提示;调整平均时间成本计算逻辑;过滤异常值记录 |
| v2.30 | 更改路径专注模式默认值;增加日志提示;移除调试日志 |
| v2.40 | 优化背包识别时的内存占用;新增通知功能 |
| v2.41 | 修复“勾选分类的本地记录”bug新增“仅背包统计”选项补充记录损坏处理说明 |
| v2.41 | 修复“勾选分类的本地记录”bug新增“仅背包统计”选项补充记录损坏处理说明 |
| v2.42 | 新增“无路径间扫描”“noRecord模式”适合成熟路径新增怪物材料CD文件 |
| v2.50 | 新增独立名单拾取、弹窗模块;支持怪物名识别 |
| v2.51 | 自定义设置新增“拖动距离/拖动点”新增月卡弹窗识别路径材料超量自动上黑名单修复怪物0收获记录 |
@@ -240,4 +240,5 @@ A记录文件夹位于 `BetterGI\User\JsScript\背包材料统计\` 下,各
| v2.64 | 移除位移检测模块 |
| v2.65 | 修复测算模式、0记录检测码等bug优化汇总日志调整默认目标数量至1000 |
| v2.66 | 修复翻页兜底逻辑增加材料数量模板匹配材料数量OCR失败后截图保存【扫描额外的分类】联动超量材料 |
| v2.67 | 修复怪物材料映射斜杠逻辑更新OCR错字映射表优先级材料按自定义顺序修复怪物材料过滤bug |
| v2.67 | 修复怪物材料映射斜杠逻辑更新OCR错字映射表优先级材料按自定义顺序修复怪物材料过滤bug |
| v2.68 | 修复终止翻页逻辑测算模式调整压缩log |

View File

@@ -39,13 +39,13 @@ function readtargetTextCategories(targetTextDir) {
let availablePickCategories = [];
try {
availablePickCategories = targetTextFilePaths.map(filePath => basename(filePath).replace('.txt', ''));
log.info(`可用识别名单:${availablePickCategories.join(', ')}`);
if (debugLog) log.info(`可用识别名单:${availablePickCategories.join(', ')}`);
} catch (e) {
log.error(`扫描识别名单目录失败: ${e.message}`);
}
if (pickTextNames.length === 0) {
log.info("未指定识别名单,将加载所有文件");
if (debugLog) log.info("未指定识别名单,将加载所有文件");
} else {
const invalidCategories = pickTextNames.filter(name => !availablePickCategories.includes(name));
if (invalidCategories.length > 0) {
@@ -54,7 +54,7 @@ function readtargetTextCategories(targetTextDir) {
}
}
log.info(`筛选名单状态:${pickTextNames.length === 0 ? '未指定(空),将加载所有文件' : '指定了:' + pickTextNames.join(',')}`);
if (debugLog) log.info(`筛选名单状态:${pickTextNames.length === 0 ? '未指定(空),将加载所有文件' : '指定了:' + pickTextNames.join(',')}`);
for (const filePath of targetTextFilePaths) {
if (state.cancelRequested) break;
@@ -76,7 +76,7 @@ function readtargetTextCategories(targetTextDir) {
materialCategories[sourceCategory] = parseCategoryContent(content);
}
log.info(`完成读取,加载的分类:${Object.keys(materialCategories).join(',')}`);
if (debugLog) log.info(`完成读取,加载的分类:${Object.keys(materialCategories).join(',')}`);
return materialCategories;
}
@@ -196,7 +196,9 @@ async function alignAndInteractTarget(targetTextsOrFunc, fDialogueRo, textxRange
for (const res of ocrResults) {
const centerY = res.y + res.height / 2;
const yDiff = Math.abs(centerY - fCenterY);
log.debug(`未匹配: "${res.text}" Y中心: ${centerY.toFixed(1)}, F图标Y中心: ${fCenterY.toFixed(1)}, 差值: ${yDiff.toFixed(1)}, 容忍度: ${texttolerance}`);
const logText = `未匹配: "${res.text}" Y中心: ${centerY.toFixed(1)}, F图标Y中心: ${fCenterY.toFixed(1)}, 差值: ${yDiff.toFixed(1)}, 容忍度: ${texttolerance}`;
log.debug(logText);
writeFile("user/OCR未匹配记录.txt", logText);
}
}
await keyMouseScript.runFile(`assets/滚轮下翻.json`);

View File

@@ -116,7 +116,7 @@ function safeReadTextSync(filePath, defaultValue = "") {
try {
// 第一步:校验文件是否存在
if (!fileExists(filePath)) {
log.debug(`${CONSTANTS.LOG_MODULES.RECORD}文件不存在,跳过读取: ${filePath}`);
// log.debug(`${CONSTANTS.LOG_MODULES.RECORD}文件不存在,跳过读取: ${filePath}`);
return defaultValue;
}
// 第二步:读取文件(捕获读取异常)
@@ -226,7 +226,7 @@ function matchImageAndGetCategory(resourceName, imagesDir) {
const processedName = (MATERIAL_ALIAS[resourceName] || resourceName).toLowerCase();
if (!imageMapCache.has(imagesDir)) {
log.debug(`${CONSTANTS.LOG_MODULES.MATERIAL}初始化图像分类缓存:${imagesDir}`);
// log.debug(`${CONSTANTS.LOG_MODULES.MATERIAL}初始化图像分类缓存:${imagesDir}`);
imageMapCache.set(imagesDir, createImageCategoryMap(imagesDir));
}

View File

@@ -264,11 +264,11 @@ async function imageClickBackgroundTask() {
// 打印资源检测结果
log.info("\n==================== 现有弹窗加载结果 ====================");
log.info("1. 一级弹窗(共" + firstLevelDirs.length + "个):");
firstLevelDirs.forEach((res, idx) => log.info(` ${idx+1}. 【${res.dirName}`));
const firstLevelNames = firstLevelDirs.map(res => res.dirName).join('、');
log.info("1. 一级弹窗(共" + firstLevelDirs.length + "个):" + firstLevelNames);
const secondLevelResources = preloadedResources.filter(res => !res.isFirstLevel);
log.info("\n2. 二级弹窗(共" + secondLevelResources.length + "个):");
secondLevelResources.forEach((res, idx) => log.info(` ${idx+1}. 【${res.dirName}`));
const secondLevelNames = secondLevelResources.map(res => res.dirName).join('、');
log.info("2. 二级弹窗(共" + secondLevelResources.length + "个):" + secondLevelNames);
log.info("=============================================================\n");
// 核心逻辑:外循环遍历所有一级弹窗

View File

@@ -366,7 +366,7 @@ async function processMonsterPathEntry(entry, context) {
if (startTime) {
const endTime = new Date().toLocaleString();
runTime = (new Date(endTime) - new Date(startTime)) / 1000;
await handlePathError(error, pathingFilePath, pathName, monsterName, startTime, endTime, runTime, shouldRunAsNoRecord, false);
await handlePathError(error, pathingFilePath, pathName, monsterName, startTime, endTime, runTime, shouldRunAsNoRecord, state.cancelRequested);
}
throw error;
}
@@ -589,7 +589,8 @@ async function processAllPaths(allPaths, CDCategories, materialCategoryMap, time
noRecordDir,
isFood,
pathRecordCache,
pathingFilePath
pathingFilePath,
true
);
const isTimeCostOk = perTime === null || isTimeCostQualified(
@@ -655,17 +656,6 @@ async function processAllPaths(allPaths, CDCategories, materialCategoryMap, time
}
}
log.info(`${CONSTANTS.LOG_MODULES.PATH}\n===== 测算模式分析结果 =====`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}时间成本:${timeCost}%`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}总路径数:${totalPaths}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}未通过CD未刷新${failedCD}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}未通过0记录超限${failedFrequency}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}未达标(时间成本不合格):${failedTimeCost}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}直通达标(记录不足):${insufficientRecords}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}达标路径数:${totalQualifiedPaths}条(同时通过三个校验)`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}达标占比:${totalPaths > 0 ? ((totalQualifiedPaths / totalPaths) * 100).toFixed(1) : 0}%`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}预计耗时:${formatTime(totalEstimatedTime)}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}\n各材料平均时间成本及达标情况:`);
for (const [resourceKey, data] of Object.entries(resourceAnalysis)) {
const avgThresholdPerTime = data.thresholdPerTimeCount > 0 ? (data.thresholdPerTimeSum / data.thresholdPerTimeCount).toFixed(4) : '无记录';
@@ -675,7 +665,6 @@ async function processAllPaths(allPaths, CDCategories, materialCategoryMap, time
const avgThresholdPercentile = thresholdPercentileTimes.length > 0
? (thresholdPercentileTimes.reduce((sum, t) => sum + t, 0) / thresholdPercentileTimes.length).toFixed(4)
: '无达标';
const qualifiedRatio = data.thresholdPerTimeCount > 0 ? ((data.qualified / data.thresholdPerTimeCount) * 100).toFixed(1) : '0.0';
const totalEstimatedTime = formatTime(data.estimatedTimeSum);
const avgQualifiedPerTime = data.qualified > 0 ? (data.qualifiedPerTimeSum / data.qualified).toFixed(4) : '无达标';
@@ -687,15 +676,21 @@ async function processAllPaths(allPaths, CDCategories, materialCategoryMap, time
} else if (isMonster) {
unit = '秒/中位材料';
}
const totalPassedPaths = data.qualified;
const totalPathsForMaterial = data.total;
const directPassPaths = totalPassedPaths;
const displayRatio = `${totalPassedPaths}/${totalPathsForMaterial}`;
log.info(`${CONSTANTS.LOG_MODULES.PATH} --------------------------------------`);
log.info(`${CONSTANTS.LOG_MODULES.PATH} ${resourceKey}:`);
log.info(`${CONSTANTS.LOG_MODULES.PATH} 达标平均:${avgQualifiedPerTime}${unit}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH} 所有记录平均排除0记录超限${avgThresholdPerTime}${unit}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH} 设置的${timeCost}%分位阈值:${avgThresholdPercentile}${unit}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH} 达标:${qualifiedRatio}% (${data.qualified}/${data.thresholdPerTimeCount}),总耗时:${totalEstimatedTime}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH} 达标:${displayRatio},总耗时:${totalEstimatedTime}`);
}
log.info(`${CONSTANTS.LOG_MODULES.PATH}=============================\n`);
const qualifiedRatio = totalPaths > 0 ? ((totalQualifiedPaths / totalPaths) * 100).toFixed(1) : 0;
log.info(`${CONSTANTS.LOG_MODULES.PATH}===== 测算模式分析结果 =====\n时间成本:${timeCost}%,总路径:${totalPaths}\nCD冷却中:${failedCD}0记录超限:${failedFrequency}cost不达标:${failedTimeCost}\n达标:${totalQualifiedPaths}(${qualifiedRatio}%),预计耗时:${formatTime(totalEstimatedTime)}\n`);
if (notify) {
const estimateMsg = `【测算模式】分析完成\n总路径数:${totalPaths}\n达标路径数:${totalQualifiedPaths}\n达标占比:${totalPaths > 0 ? ((totalQualifiedPaths / totalPaths) * 100).toFixed(1) : 0}%\n预计耗时:${formatTime(totalEstimatedTime)}`;

View File

@@ -138,7 +138,7 @@ function checkPathNameFrequency(resourceName, pathName, recordDir, isFood = fals
if (line.startsWith('路径名: ')) {
currentPathName = line.split('路径名: ')[1];
} else if (line.startsWith('内容检测码: ')) {
recordContentCode = line.split('内容检测码: ')[1];
recordContentCode = line.split('内容检测码: ')[1].trim();
} else if (line === '' && currentPathName && recordContentCode) {
if (hasValidContentCode) {
if (recordContentCode === currentContentCode) {
@@ -266,11 +266,11 @@ function getLastRunEndTime(resourceName, pathName, recordDir, noRecordDir, pathi
blockLines.forEach(line => {
if (line.startsWith('路径名: ')) {
blockPathName = line.split('路径名: ')[1];
blockPathName = line.split('路径名: ')[1].trim();
} else if (line.startsWith('内容检测码: ')) {
blockContentCode = line.split('内容检测码: ')[1] || '00000000';
blockContentCode = line.split('内容检测码: ')[1].trim() || '00000000';
} else if (line.startsWith('结束时间: ')) {
blockEndTime = line.split('结束时间: ')[1];
blockEndTime = line.split('结束时间: ')[1].trim();
}
});
@@ -308,7 +308,7 @@ function getLastRunEndTime(resourceName, pathName, recordDir, noRecordDir, pathi
* @param {Object} cache - 缓存对象(单次路径处理周期内有效)
* @returns {Array<Object>} 结构化记录列表含runTime、quantityChange
*/
function getHistoricalPathRecords(resourceKey, pathName, recordDir, noRecordDir, isFood = false, cache = {}, pathingFilePath) {
function getHistoricalPathRecords(resourceKey, pathName, recordDir, noRecordDir, isFood = false, cache = {}, pathingFilePath, filterExcessMaterials = false) {
const contentCode = pathingFilePath ? generatePathContentCode(pathingFilePath) : null;
const hasValidContentCode = contentCode && contentCode !== "00000000";
@@ -353,14 +353,14 @@ function getHistoricalPathRecords(resourceKey, pathName, recordDir, noRecordDir,
blockLines.forEach(line => {
if (line.startsWith('路径名: ')) {
const recordPathName = line.split('路径名: ')[1];
const recordPathName = line.split('路径名: ')[1].trim();
const cleanRecordPathName = recordPathName.replace(/_[0-9a-fA-F]{8}\.json$/, '.json');
if (cleanRecordPathName === cleanPathName) {
isTargetPath = true;
}
}
if (line.startsWith('内容检测码: ')) {
recordContentCode = line.split('内容检测码: ')[1] || "00000000";
recordContentCode = line.split('内容检测码: ')[1].trim() || "00000000";
}
if (line.startsWith('运行时间: ')) {
runTime = parseInt(line.split('运行时间: ')[1].split('秒')[0], 10) || 0;
@@ -391,6 +391,35 @@ function getHistoricalPathRecords(resourceKey, pathName, recordDir, noRecordDir,
cache[cacheKey] = records;
if (debugLog) log.debug(`${CONSTANTS.LOG_MODULES.RECORD}读取记录并缓存:${cacheKey}${records.length}条)`);
if (filterExcessMaterials && excessMaterialNames.length > 0) {
const filteredRecords = records.filter(record => {
const { quantityChange } = record;
if (isFood) {
return true;
}
if (monsterToMaterials[resourceKey]) {
const monsterMaterials = monsterToMaterials[resourceKey];
const allExcess = monsterMaterials.every(mat => excessMaterialNames.includes(mat));
return !allExcess;
}
if (quantityChange[resourceKey] !== undefined) {
return !excessMaterialNames.includes(resourceKey);
}
return true;
});
if (debugLog && filteredRecords.length !== records.length) {
log.debug(`${CONSTANTS.LOG_MODULES.RECORD}过滤超量材料记录:${records.length}条 -> ${filteredRecords.length}`);
}
return filteredRecords;
}
return records;
}

View File

@@ -7,9 +7,8 @@ function updateSettingsOptions() {
log.info("开始更新settings.json...");
try {
var settingsContent = file.readTextSync(SETTINGS_FILE);
log.info("settings.json内容长度: " + settingsContent.length);
var settings = JSON.parse(settingsContent);
log.info("settings.json解析成功配置项数量: " + settings.length);
if (debugLog) log.info("settings.json解析成功配置项数量: " + settings.length);
var hasChanges = false;
@@ -27,7 +26,6 @@ function updateSettingsOptions() {
return basename(dirPath);
})
.sort();
log.info("扫描到弹窗目录数量: " + popupDirs.length);
var cdCategories = readAllFilePaths("materialsCD", 0, 1, ['.txt'])
.map(function(filePath) {
@@ -56,9 +54,7 @@ function updateSettingsOptions() {
}
}
if (popupSetting) {
log.info("找到PopupNames配置项");
var existingOptions = popupSetting.options || [];
log.info("现有options数量: " + existingOptions.length);
var existingSet = {};
for (var k = 0; k < existingOptions.length; k++) {
@@ -83,23 +79,20 @@ function updateSettingsOptions() {
}
}
log.info("新增options数量: " + newOptions.length);
log.info("删除options数量: " + removedOptions.length);
if (newOptions.length > 0 || removedOptions.length > 0) {
popupSetting.options = popupDirs;
hasChanges = true;
if (newOptions.length > 0) {
log.info("PopupNames新增选项: " + newOptions.join(', '));
log.info("PopupNames新增: " + newOptions.join(''));
}
if (removedOptions.length > 0) {
log.info("PopupNames删除选项: " + removedOptions.join(', '));
log.info("PopupNames删除: " + removedOptions.join(''));
}
} else {
log.info("PopupNames无新增选项");
if (debugLog) log.info("PopupNames(现有" + existingOptions.length + "个)无需更新");
}
} else {
log.info("未找到PopupNames配置项");
log.warn("未找到PopupNames配置项");
}
if (cdSetting) {

View File

@@ -36,6 +36,12 @@ const CONSTANTS = {
// 引入外部脚本(源码不变)
// ==============================================
eval(file.readTextSync("lib/file.js"));
// 提前读取 settings.json 以便定义 debugLog
var settingsContent = file.readTextSync("settings.json");
var settings = JSON.parse(settingsContent);
var debugLog = settings.debugLog || false;
eval(safeReadTextSync("lib/updateSettings.js"));
eval(safeReadTextSync("lib/ocr.js"));
eval(safeReadTextSync("lib/writeImage.js"));
@@ -70,7 +76,6 @@ const timeCost = Math.min(100, Math.max(1, Math.floor(Number(settings.TimeCost)
const notify = settings.notify || false;
const noRecord = settings.noRecord || false;
const noMonsterFilter = !settings.noMonsterFilter;
const debugLog = settings.debugLog || false;
const targetCount = Math.min(9999, Math.max(0, Math.floor(Number(settings.TargetCount) || 1000))); // 设定的目标数量
const exceedCount = Math.min(9999, Math.max(0, Math.floor(Number(settings.ExceedCount) || 9000))); // 设定的超量目标数量
const endTimeStr = settings.CurrentTime ? settings.CurrentTime : null;
@@ -87,7 +92,7 @@ let availableCDCategories = [];
try {
const cdFilePaths = readAllFilePaths(CONSTANTS.MATERIAL_CD_DIR, 0, 1, ['.txt']);
availableCDCategories = cdFilePaths.map(filePath => basename(filePath).replace('.txt', ''));
log.info(`${CONSTANTS.LOG_MODULES.INIT}可用CD分类${availableCDCategories.join(', ')}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.INIT}可用CD分类${availableCDCategories.join(', ')}`);
} catch (e) {
log.error(`${CONSTANTS.LOG_MODULES.INIT}扫描CD目录失败: ${e.message}`);
}
@@ -100,7 +105,7 @@ if (allowedCDCategories.length > 0) {
}
log.info(`${CONSTANTS.LOG_MODULES.INIT}已配置只处理以下CD分类${allowedCDCategories.join('、')}`);
} else {
log.info(`${CONSTANTS.LOG_MODULES.INIT}未配置CD分类过滤将处理所有分类`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.INIT}未配置CD分类过滤将处理所有分类`);
}
// ==============================================
@@ -463,8 +468,8 @@ function filterLowCountMaterials(pathingMaterialCounts, materialCategoryMap, onl
// onlyCategory模式下检查所有扫描到的材料而不仅仅是materialCategoryMap中的材料
const shouldCheckAll = onlyCategoryMode || allMaterials.length === 0;
log.info(`【材料基准】onlyCategoryMode=${onlyCategoryMode}, allMaterials长度=${allMaterials.length}, shouldCheckAll=${shouldCheckAll}, pathingMaterialCounts长度=${pathingMaterialCounts.length}`);
log.info(`【扫描结果】${pathingMaterialCounts.map(item => `${item.name}:${item.count}`).join(', ')}`);
if (debugLog) log.info(`【材料基准】onlyCategoryMode=${onlyCategoryMode}, allMaterials长度=${allMaterials.length}, shouldCheckAll=${shouldCheckAll}, pathingMaterialCounts长度=${pathingMaterialCounts.length}`);
if (debugLog) log.info(`【扫描结果】${pathingMaterialCounts.map(item => `${item.name}:${item.count}`).join(', ')}`);
// ========== 第一步:平行判断超量材料(原始数据,不经过低数量过滤) ==========
pathingMaterialCounts.forEach(item => {
@@ -486,7 +491,6 @@ function filterLowCountMaterials(pathingMaterialCounts, materialCategoryMap, onl
// 超量判断(平行逻辑:只要≥阈值就标记,和低数量无关)
if (processedCount >= EXCESS_THRESHOLD) {
tempExcess.push(item.name);
log.info(`${CONSTANTS.LOG_MODULES.MATERIAL}[超量标记] ${item.name} 原始:${item.count}${processedCount}${EXCESS_THRESHOLD}`);
}
});
@@ -512,7 +516,7 @@ function filterLowCountMaterials(pathingMaterialCounts, materialCategoryMap, onl
// ========== 第三步:更新全局超量名单(去重) ==========
excessMaterialNames = [...new Set(tempExcess)];
const realExcessCount = excessMaterialNames.filter(name => name !== "OCR启动").length;
log.info(`【超量材料更新】共${realExcessCount}种:${excessMaterialNames.filter(name => name !== "OCR启动").join("、")}`);
if (debugLog) log.info(`【超量材料更新】共${realExcessCount}种:${excessMaterialNames.filter(name => name !== "OCR启动").join("、")}`);
if (debugLog) log.info(`【低数量材料】筛选后共${filteredLowCountMaterials.length}种:${filteredLowCountMaterials.map(m => m.name).join("、")}`);
// 返回低数量材料(超量名单已独立生成)
@@ -610,11 +614,11 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
return { path, resourceName: materialName, monsterName };
}).filter(entry => (entry.resourceName || entry.monsterName) && entry.path.trim() !== "");
log.info(`${CONSTANTS.LOG_MODULES.PATH}[路径初始化] 共读取有效路径 ${pathEntries.length}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[路径初始化] 共读取有效路径 ${pathEntries.length}`);
// 测算模式:不执行背包扫描,直接返回所有路径
if (pathingMode.estimateMode) {
log.info(`${CONSTANTS.LOG_MODULES.PATH}[测算模式] 跳过背包扫描,直接进行路径分析`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}[测算模式] 将执行背包扫描以筛选低数量材料`);
}
// 分类路径(狗粮 > 怪物 > 普通材料)
@@ -622,13 +626,9 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
const monsterPaths = pathEntries.filter(entry => entry.monsterName && entry.monsterName !== '地脉花');
const normalPaths = pathEntries.filter(entry => entry.resourceName && !entry.monsterName && entry.resourceName !== '锄地');
log.info(`${CONSTANTS.LOG_MODULES.PATH}[路径分类] 狗粮:${foodPaths.length} 怪物:${monsterPaths.length} 普通:${normalPaths.length}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[路径分类] 狗粮:${foodPaths.length} 怪物:${monsterPaths.length} 普通:${normalPaths.length}`);
// 测算模式直接返回所有路径
if (pathingMode.estimateMode) {
const allPaths = [...monsterPaths, ...normalPaths, ...foodPaths];
return { allPaths, pathingMaterialCounts: [] };
}
// 测算模式不再直接返回所有路径,而是继续执行背包扫描以筛选低数量材料
// 怪物路径关联材料到分类(扫描用)- 仅includeBoth和onlyPathing模式
if (pathingMode.includeBoth || pathingMode.onlyPathing) {
@@ -663,7 +663,7 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
if (normalPaths.length > 0 || monsterPaths.length > 0 || pathingMode.onlyCategory) {
// 优化:一次扫描获取全量材料数量,同时服务于怪物和普通材料
log.info(`${CONSTANTS.LOG_MODULES.PATH}[材料扫描] 执行一次全量背包扫描(服务于怪物+普通路径)`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}[材料扫描] materialCategoryMap内容${JSON.stringify(materialCategoryMap)}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[材料扫描] materialCategoryMap内容${JSON.stringify(materialCategoryMap)}`);
const allMaterialCounts = await MaterialPath(materialCategoryMap);
pathingMaterialCounts = allMaterialCounts;
// log.info(`${CONSTANTS.LOG_MODULES.PATH}[材料扫描] 扫描返回数据:${JSON.stringify(allMaterialCounts)}`);
@@ -675,6 +675,16 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
const validMonsterMaterialNames = filteredMaterials.map(m => m.name);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.MONSTER}[怪物材料] 筛选后有效材料:${validMonsterMaterialNames.join('、')}`);
// includeBoth模式更新超量名单并保存到文件
if (pathingMode.includeBoth) {
const finalExcessList = excessMaterialNames.filter(name => name !== "OCR启动");
if (finalExcessList.length > 0) {
log.info(`${CONSTANTS.LOG_MODULES.PATH}[includeBoth模式] 更新超量名单,共${finalExcessList.length}种:${finalExcessList.join('、')}`);
}
const fullContent = finalExcessList.length > 0 ? `超量名单:${finalExcessList.join(',')}\n` : "";
file.writeTextSync(CONSTANTS.EXCESS_MATERIALS_PATH, fullContent, false);
}
// onlyCategory模式只扫描不处理路径
if (pathingMode.onlyCategory) {
// 先读取txt超量名单
@@ -684,10 +694,13 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
const scannedMaterials = allMaterialCounts.flat();
const updatedExcessMaterials = new Set(txtExcessMaterials);
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] txt超量名单长度:${txtExcessMaterials.length}, 内容:${txtExcessMaterials.join('、')}`);
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] updatedExcessMaterials初始长度:${updatedExcessMaterials.size}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] txt超量名单长度:${txtExcessMaterials.length}, 内容:${txtExcessMaterials.join('、')}`);
// log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] updatedExcessMaterials初始长度:${updatedExcessMaterials.size}`);
// 逐一检查txt超量名单中的每个材料
const keptMaterials = [];
const removedMaterials = [];
txtExcessMaterials.forEach(name => {
const found = scannedMaterials.find(m => m.name === name);
if (found) {
@@ -700,29 +713,37 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
}
// 用处理后的数量判断是否超量
if (rawCount >= exceedCount) {
log.info(`${CONSTANTS.LOG_MODULES.PATH}[比对] ${name} 原始:${originalCount} 处理后:${rawCount}${exceedCount} → 保留在超量名单`);
keptMaterials.push(name);
} else {
log.info(`${CONSTANTS.LOG_MODULES.PATH}[比对] ${name} 原始:${originalCount} 处理后:${rawCount} < ${exceedCount} → 从超量名单剔除`);
removedMaterials.push(name);
updatedExcessMaterials.delete(name);
}
} else {
// 没扫描到,保留在超量名单
log.info(`${CONSTANTS.LOG_MODULES.PATH}[比对] ${name} 未扫描到 → 保留在超量名单`);
keptMaterials.push(name);
}
});
const finalExcessList = Array.from(updatedExcessMaterials);
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] 更新后超量名单,共${finalExcessList.length}种:${finalExcessList.join('、')}`);
// 输出汇总日志
if (keptMaterials.length > 0) {
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] 保留在超量名单:${keptMaterials.join('、')}`);
}
if (removedMaterials.length > 0) {
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] 从超量名单剔除:${removedMaterials.join('、')}`);
}
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] 更新后超量名单,共${finalExcessList.length}`);
// 保存更新后的超量名单(直接覆盖,不合并)
const fullContent = finalExcessList.length > 0 ? `超量名单:${finalExcessList.join(',')}\n` : "";
file.writeTextSync(CONSTANTS.EXCESS_MATERIALS_PATH, fullContent, false);
log.info(`${CONSTANTS.LOG_MODULES.RECORD}超量名单已保存至 ${CONSTANTS.EXCESS_MATERIALS_PATH},共${finalExcessList.length}`);
// log.info(`${CONSTANTS.LOG_MODULES.RECORD}超量名单已保存至 ${CONSTANTS.EXCESS_MATERIALS_PATH},共${finalExcessList.length}种`);
// 过滤只保留超量名单中的材料
const filteredByExcess = scannedMaterials.filter(item => finalExcessList.includes(item.name));
pathingMaterialCounts = [filteredByExcess];
log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] 过滤后保留超量材料:${filteredByExcess.map(m => m.name).join('、') || '无'}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[onlyCategory模式] 过滤后保留超量材料:${filteredByExcess.map(m => m.name).join('、') || '无'}`);
return { allPaths: [], pathingMaterialCounts };
}
@@ -737,9 +758,9 @@ async function generateAllPaths(pathingDir, targetResourceNames, cdMaterialNames
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[普通材料] 筛选后保留路径 ${processedNormalPaths.length}`);
} else if (foodPaths.length > 0) {
// 只有狗粮路径时也需要初始化超量名单OCR启动需要
log.info(`${CONSTANTS.LOG_MODULES.PATH}[狗粮模式] 初始化超量名单`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.PATH}[狗粮模式] 初始化超量名单`);
excessMaterialNames = ["OCR启动"];
log.info(`【超量材料更新】共${excessMaterialNames.length}种:${excessMaterialNames.join("、")}`);
if (debugLog) log.info(`【超量材料更新】共${excessMaterialNames.length}种:${excessMaterialNames.join("、")}`);
}
// 按TargetresourceName顺序处理路径优先级1-3按目标顺序同类型内也按目标顺序
@@ -1015,7 +1036,7 @@ function loadExcessMaterialsList() {
}
const materials = match[1].split(',').map(name => name.trim()).filter(name => name);
log.info(`${CONSTANTS.LOG_MODULES.RECORD}读取超量名单成功,共${materials.length}种:${materials.join('、')}`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.RECORD}读取超量名单成功,共${materials.length}种:${materials.join('、')}`);
return materials;
} catch (error) {
log.error(`${CONSTANTS.LOG_MODULES.RECORD}读取超量名单失败:${error.message}`);
@@ -1145,7 +1166,7 @@ ${Object.entries(totalDifferences).map(([name, diff]) => ` ${name}: +${diff}个
// 并行任务:路径处理
const pathTask = (async () => {
log.info(`${CONSTANTS.LOG_MODULES.MAIN}开始路径处理流程`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.MAIN}开始路径处理流程`);
// 加载CD分类
const CDCategories = readMaterialCD();
@@ -1169,7 +1190,7 @@ ${Object.entries(totalDifferences).map(([name, diff]) => ` ${name}: +${diff}个
});
} else {
if (pathingMode.onlyPathing) {
log.warn(`${CONSTANTS.LOG_MODULES.MATERIAL}onlyPathing模式将自动扫描pathing材料的实际分类`);
if (debugLog) log.warn(`${CONSTANTS.LOG_MODULES.MATERIAL}onlyPathing模式将自动扫描pathing材料的实际分类`);
} else {
log.warn(`${CONSTANTS.LOG_MODULES.MATERIAL}未选择【材料分类】,采用【路径材料】专注模式`);
}
@@ -1338,7 +1359,7 @@ ${Object.entries(totalDifferences).map(([name, diff]) => ` ${name}: +${diff}个
const imageTask = pathingMode.estimateMode ? null : imageClickBackgroundTask();
const tasks = pathingMode.estimateMode ? [pathTask] : [ocrTask, pathTask, imageTask].filter(t => t !== null);
log.info(`${CONSTANTS.LOG_MODULES.MAIN}任务列表已创建,共${tasks.length}个任务`);
if (debugLog) log.info(`${CONSTANTS.LOG_MODULES.MAIN}任务列表已创建,共${tasks.length}个任务`);
try {
await Promise.allSettled(tasks);

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "背包统计采集系统",
"version": "2.67",
"version": "2.68",
"bgi_version": "0.55",
"description": "可统计背包养成道具、部分食物、素材的数量根据设定数量、根据材料刷新CD执行挖矿、采集、刷怪等的路径。优势\n+ 1. 自动判断材料CD不需要管材料CD有没有好\n+ 2. 可以随意添加路径,能自动排除低效、无效路径;\n+ 3. 有独立名单识别不会交互路边的npc或是神像可自定义识别名单具体方法看【问题解答】增减识别名单\n+ 4. 有实时的弹窗模块,提供了常见的几种:路边信件、过期物品、月卡、调查;\n+ 5. 可识别爆满的路径材料自动屏蔽更多详细内容查看readme.md;可在我的主页下载 路径重命名 工具JS给路径名批量添加检测码方便识别。",
"saved_files": [

View File

@@ -1,2 +1,2 @@
4点丘丘人丘丘萨满丘丘人射手丘丘暴徒丘丘王丘丘游侠愚人众先遣队萤术士债务处理人冬国仕女愚人众风役人愚人众特辖队盗宝团野伏众海乱鬼镀金旅团黑蛇众黯色空壳部族龙形武士遗迹机械元能构装体遗迹机兵遗迹龙兽发条机关秘源机兵巡陆艇史莱姆骗骗花飘浮灵蕈兽浊水幻灵原海异种隙境原体魔像禁卫大灵显化身熔岩游像龙蜥圣骸兽玄文兽纳塔龙众炉壳山鼬蕴光异兽深渊法师深渊使徒兽境群狼深邃拟覆叶荒野狂猎霜夜灵嗣深黯钓客地脉花锄地
4点丘丘人丘丘萨满丘丘人射手丘丘暴徒丘丘王丘丘游侠愚人众先遣队萤术士债务处理人冬国仕女愚人众风役人愚人众特辖队盗宝团野伏众海乱鬼镀金旅团黑蛇众黯色空壳部族龙形武士遗迹机械元能构装体遗迹机兵遗迹龙兽发条机关秘源机兵巡陆艇史莱姆骗骗花飘浮灵蕈兽浊水幻灵原海异种隙境原体魔像禁卫大灵显化身熔岩游像龙蜥圣骸兽玄文兽纳塔龙众炉壳山鼬蕴光异兽深渊法师深渊使徒兽境群狼深邃拟覆叶荒野狂猎霜夜灵嗣深黯钓客地脉花锄地,飞萤