mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-11 08:53:42 +08:00
@@ -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 |
|
||||
@@ -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`);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
// 核心逻辑:外循环遍历所有一级弹窗
|
||||
|
||||
@@ -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)}`;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
|
||||
4点:丘丘人,丘丘萨满,丘丘人射手,丘丘暴徒,丘丘王,丘丘游侠,愚人众先遣队,萤术士,债务处理人,冬国仕女,愚人众风役人,愚人众特辖队,盗宝团,野伏众,海乱鬼,镀金旅团,黑蛇众,黯色空壳,部族龙形武士,遗迹机械,元能构装体,遗迹机兵,遗迹龙兽,发条机关,秘源机兵,巡陆艇,史莱姆,骗骗花,飘浮灵,蕈兽,浊水幻灵,原海异种,隙境原体,魔像禁卫,大灵显化身,熔岩游像,龙蜥,圣骸兽,玄文兽,纳塔龙众,炉壳山鼬,蕴光异兽,深渊法师,深渊使徒,兽境群狼,深邃拟覆叶,荒野狂猎,霜夜灵嗣,深黯钓客,地脉花,锄地
|
||||
4点:丘丘人,丘丘萨满,丘丘人射手,丘丘暴徒,丘丘王,丘丘游侠,愚人众先遣队,萤术士,债务处理人,冬国仕女,愚人众风役人,愚人众特辖队,盗宝团,野伏众,海乱鬼,镀金旅团,黑蛇众,黯色空壳,部族龙形武士,遗迹机械,元能构装体,遗迹机兵,遗迹龙兽,发条机关,秘源机兵,巡陆艇,史莱姆,骗骗花,飘浮灵,蕈兽,浊水幻灵,原海异种,隙境原体,魔像禁卫,大灵显化身,熔岩游像,龙蜥,圣骸兽,玄文兽,纳塔龙众,炉壳山鼬,蕴光异兽,深渊法师,深渊使徒,兽境群狼,深邃拟覆叶,荒野狂猎,霜夜灵嗣,深黯钓客,地脉花,锄地,飞萤
|
||||
|
||||
Reference in New Issue
Block a user