@@ -40,29 +40,24 @@ const timeMoveDown = 1200;
}
//预处理路线并建立对象
log . info ( "开始预处理地图追踪文件" ) ;
pathings = await processPathings ( ) ;
log . info ( "开始合并index数据" ) ;
//优先使用index中的数据
await updatePathings ( "assets/index1.json" ) ;
await updatePathings ( "assets/index2.json" ) ;
//加载路线cd信息
await initializeCdTime ( pathings , accountName )
await initializeCdTime ( pathings , accountName ) ;
//按照用户配置标记可用路线
log . info ( "开始按照用户配置标记可用路线" ) ;
await markPathings ( pathings , group1Tags , group2Tags , group3Tags , group4Tags , excludeTags ) ;
//找出最优组合
log . info ( "开始寻找最优组合" ) ;
await findBestRouteGroups ( pathings , k , targetEliteNum , targetMonsterNum ) ;
//分配到不同路径组
log . info ( "开始分配到不同路径组" ) ;
groupCounts = await assignGroups ( pathings , group1Tags , group2Tags , group3Tags , group4Tags ) ;
/*
//分配结果输出
pathings.forEach((pathing, index) => {
log.info(`路径 ${index + 1}:`);
log.info(` fullPath: ${pathing.fullPath}`);
@@ -90,7 +85,7 @@ const timeMoveDown = 1200;
log . info ( "开始运行锄地路线" ) ;
await processPathingsByGroup ( pathings , targetTexts , blacklistKeywords , accountName ) ;
} else {
log . info ( "开始 强制刷新CD" ) ;
log . info ( "强制刷新所有路线 CD" ) ;
await initializeCdTime ( pathings , "" ) ;
await updateCdTimeRecord ( pathings , accountName ) ;
}
@@ -319,7 +314,7 @@ async function findBestRouteGroups(pathings, k, targetEliteNum, targetMonsterNum
const minutes = Math . floor ( ( totalTimeCombined % 3600 ) / 60 ) ;
const seconds = totalTimeCombined % 60 ;
log . info ( ` 总用时: ${ hours } 时 ${ minutes } 分 ${ seconds . toFixed ( 0 ) } 秒 ` ) ;
log . info ( ` 预计 总用时: ${ hours } 时 ${ minutes } 分 ${ seconds . toFixed ( 0 ) } 秒 ` ) ;
}
async function assignGroups ( pathings , group1Tags , group2Tags , group3Tags , group4Tags ) {
@@ -376,6 +371,8 @@ async function runPathWithOcr(pathFilePath, targetTexts, blacklistKeywords) {
} ;
let thisMoveUpTime = 0 ;
let lastMoveUp = 0 ;
let lastPickupTime = new Date ( ) ;
// 定义状态变量
let state = { completed : false , cancelRequested : false } ;
// 定义图像路径和目标文本列表
@@ -391,7 +388,6 @@ async function runPathWithOcr(pathFilePath, targetTexts, blacklistKeywords) {
log . error ( ` 执行路径文件时发生错误: ${ error . message } ` ) ;
state . cancelRequested = true ; // 修改状态变量
}
log . info ( ` 路径文件 ${ filePath } 执行完成 ` ) ;
state . completed = true ; // 修改状态变量
}
@@ -527,31 +523,14 @@ async function runPathWithOcr(pathFilePath, targetTexts, blacklistKeywords) {
// 检查是否包含黑名单关键词
let containsBlacklistKeyword = blacklistKeywords . some ( blacklistKeyword => ocrResult . text . includes ( blacklistKeyword ) ) ;
if ( containsBlacklistKeyword ) {
log . debug ( ` 包含黑名单,不拾取: ${ ocrResult . text } ` ) ;
continue ;
}
log . info ( ` 交互或拾取: " ${ ocrResult . text } " ` ) ;
// 获取当前时间并格式化为 HH:mm:ss.sss 格式
function formatTime ( date ) {
const hours = String ( date . getHours ( ) ) . padStart ( 2 , '0' ) ;
const minutes = String ( date . getMinutes ( ) ) . padStart ( 2 , '0' ) ;
const seconds = String ( date . getSeconds ( ) ) . padStart ( 2 , '0' ) ;
const milliseconds = String ( date . getMilliseconds ( ) ) . padStart ( 3 , '0' ) ;
return ` ${ hours } : ${ minutes } : ${ seconds } . ${ milliseconds } ` ;
if ( ( new Date ( ) - lastPickupTime ) > 200 ) {
log . info ( ` 交互或拾取: " ${ ocrResult . text } " ` ) ;
lastPickupTime = new Date ( ) ;
}
// 获取当前时间
const now = new Date ( ) ;
// 格式化当前时间
const formattedTime = formatTime ( now ) ;
// 输出日志
log . debug ( ` [ ${ formattedTime } ][INF] BetterGenshinImpact.GameTask.AutoPick.AutoPickTrigger \n 交互或拾取:" ${ ocrResult . text } " ` ) ;
// 计算目标文本的中心Y坐标
let centerYTargetText = ocrResult . y + ocrResult . height / 2 ;
if ( Math . abs ( centerYTargetText - centerYF ) <= texttolerance ) {
@@ -612,8 +591,6 @@ async function runPathWithOcr(pathFilePath, targetTexts, blacklistKeywords) {
// 定义 readFolder 函数
async function readFolder ( folderPath , onlyJson ) {
log . info ( ` 开始读取文件夹: ${ folderPath } ` ) ;
// 新增一个堆栈,初始时包含 folderPath
const folderStack = [ folderPath ] ;
@@ -735,6 +712,10 @@ async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords,
const seconds = totalEstimatedTime % 60 ;
log . info ( ` 预计用时: ${ hours } 时 ${ minutes } 分 ${ seconds . toFixed ( 0 ) } 秒 ` ) ;
const groupStartTime = new Date ( ) ;
let remainingEstimatedTime = totalEstimatedTime ;
let skippedTime = 0 ;
// 遍历 pathings 数组
for ( const pathing of pathings ) {
// 检查路径是否属于指定的组
@@ -743,7 +724,7 @@ async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords,
groupPathCount ++ ;
// 输出当前路径的序号信息
log . info ( ` 当前路径 ${ pathing . fileName } 是 第 ${ targetGroup } 组第 ${ groupPathCount } / ${ totalPathsInGroup } 条 ` ) ;
log . info ( ` 开始处理 第 ${ targetGroup } 组第 ${ groupPathCount } / ${ totalPathsInGroup } 个 ${ pathing . fileName } ` ) ;
// 获取当前时间
const now = new Date ( ) ;
@@ -752,9 +733,15 @@ async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords,
const cdTime = new Date ( pathing . cdTime ) ;
if ( cdTime > now ) {
log . info ( ` 该路线未刷新,跳过。 ` ) ;
skippedTime += pathing . t ;
remainingEstimatedTime -= pathing . t ;
continue ;
}
if ( await isTimeRestricted ( settings . timeRule ) ) {
break ;
}
// 输出路径已刷新并开始处理的信息
log . info ( ` 该路线已刷新,开始处理。 ` ) ;
await fakeLog ( ` ${ pathing . fileName } ` , false , true , 0 ) ;
@@ -781,10 +768,15 @@ async function processPathingsByGroup(pathings, targetTexts, blacklistKeywords,
// 更新路径的 cdTime
pathing . cdTime = nextEightClock . toLocaleString ( ) ;
await updateCdTimeRecord ( pathings , accountName )
// 输出路径的下次可用时间(本地时间格式)
log . info ( ` 路径 ${ pathing . fileName } 下次可用时间为 ${ nextEightClock . toLocaleString ( ) } ` ) ;
await updateCdTimeRecord ( pathings , accountName ) ;
remainingEstimatedTime -= pathing . t ;
const actualUsedTime = ( new Date ( ) - groupStartTime ) / 1000 ;
const predictRemainingTime = remainingEstimatedTime * actualUsedTime / ( totalEstimatedTime - remainingEstimatedTime - skippedTime ) ;
// 将预计剩余时间转换为时、分、秒表示
const remaininghours = Math . floor ( predictRemainingTime / 3600 ) ;
const remainingminutes = Math . floor ( ( predictRemainingTime % 3600 ) / 60 ) ;
const remainingseconds = predictRemainingTime % 60 ;
log . info ( ` 当前进度:第 ${ targetGroup } 组第 ${ groupPathCount } / ${ totalPathsInGroup } 个 ${ pathing . fileName } 已完成,该组预计剩余: ${ remaininghours } 时 ${ remainingminutes } 分 ${ remainingseconds . toFixed ( 0 ) } 秒 ` ) ;
}
}
}
@@ -837,8 +829,6 @@ async function updateCdTimeRecord(pathings, accountName) {
// 将更新后的内容写回文件
await file . writeText ( filePath , JSON . stringify ( cdTimeData , null , 2 ) , false ) ;
// 输出日志
log . info ( ` 所有路径的 cdTime 已更新并保存到文件 ${ filePath } ` ) ;
} catch ( error ) {
// 捕获并记录错误
log . error ( ` 更新 cdTime 时出错: ${ error . message } ` ) ;
@@ -990,7 +980,76 @@ async function switchPartyIfNeeded(partyName) {
}
}
/**
* 检查当前时间是否处于限制时间内或即将进入限制时间
* @param {string} timeRule - 时间规则字符串,格式如 "4, 4-6, 10-12"
* @param {number} [threshold=5] - 接近限制时间的阈值(分钟)
* @returns {Promise<boolean>} - 如果处于限制时间内或即将进入限制时间,则返回 true, 否则返回 false
*/
async function isTimeRestricted ( timeRule , threshold = 5 ) {
// 如果输入的时间规则为 undefined 或空字符串,视为不进行时间处理,返回 false
if ( timeRule === undefined || timeRule === "" ) {
return false ;
}
// 初始化 0-23 小时为可用状态
const hours = Array ( 24 ) . fill ( false ) ;
// 解析时间规则
const rules = timeRule . split ( ', ' ) . map ( rule => rule . trim ( ) ) ;
// 校验输入的字符串是否符合规则
for ( const rule of rules ) {
if ( rule . includes ( '-' ) ) {
// 处理时间段,如 "4-6"
const [ startHour , endHour ] = rule . split ( '-' ) . map ( Number ) ;
if ( isNaN ( startHour ) || isNaN ( endHour ) || startHour < 0 || startHour >= 24 || endHour <= startHour || endHour > 24 ) {
// 如果时间段格式不正确或超出范围,则报错并返回 true
log . error ( "时间填写不符合规则,请检查" ) ;
return true ;
}
for ( let i = startHour ; i < endHour ; i ++ ) {
hours [ i ] = true ; // 标记为不可用
}
} else {
// 处理单个时间点,如 "4"
const hour = Number ( rule ) ;
if ( isNaN ( hour ) || hour < 0 || hour >= 24 ) {
// 如果时间点格式不正确或超出范围,则报错并返回 true
log . error ( "时间填写不符合规则,请检查" ) ;
return true ;
}
hours [ hour ] = true ; // 标记为不可用
}
}
// 获取当前时间
const now = new Date ( ) ;
const currentHour = now . getHours ( ) ;
const currentMinute = now . getMinutes ( ) ;
// 检查当前时间是否处于限制时间内
if ( hours [ currentHour ] ) {
log . warn ( "处于限制时间内" ) ;
return true ; // 当前时间处于限制时间内
}
// 检查当前时间是否即将进入限制时间
for ( let i = 0 ; i < 24 ; i ++ ) {
if ( hours [ i ] ) {
const nextHour = i ;
const timeUntilNextHour = ( nextHour - currentHour - 1 ) * 60 + ( 60 - currentMinute ) ;
if ( timeUntilNextHour > 0 && timeUntilNextHour <= threshold ) {
// 如果距离下一个限制时间小于等于阈值,则等待到限制时间开始
log . warn ( "接近限制时间,开始等待" ) ;
await sleep ( timeUntilNextHour * 60 * 1000 ) ;
return true ;
}
}
}
log . info ( "不处于限制时间" ) ;
return false ; // 当前时间不在限制时间内
}