Files
2025-08-08 01:21:11 +08:00

310 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(async function () {
function logTimeTaken(startTime) {
const currentTime = Date.now();
const totalTimeInSeconds = (currentTime - startTime) / 1000;
const minutes = Math.floor(totalTimeInSeconds / 60);
const seconds = totalTimeInSeconds % 60;
const formattedTime = `${minutes}${seconds.toFixed(0).padStart(2, '0')}`;
log.info(`当前运行总时长:${formattedTime}`);
}
// powered by 秋云
function calculateEstimatedCompletion(startTime, current, total) {
if (current === 0) return "计算中...";
const elapsedTime = Date.now() - startTime;
const timePerTask = elapsedTime / current;
const remainingTasks = total - current;
const remainingTime = timePerTask * remainingTasks;
const completionDate = new Date(Date.now() + remainingTime);
return `${completionDate.toLocaleTimeString()} (约 ${Math.round(remainingTime / 60000)} 分钟)`;
}
async function AutoPath(locationName) {
try {
let filePath = `Assets/AutoPath/${locationName}.json`;
await pathingScript.runFile(filePath);
} catch (error) {
log.error(`执行 ${locationName} 路径时发生错误`);
log.error(error.message);
}
await sleep(1000);
}
async function comparePosition() {
const targetPosition = {
X: 3615.48,
Y: -521.27
};
const maxDistance = 20;
let currentPosition;
try {
// 优先使用小地图坐标
await genshin.returnMainUi();
currentPosition = genshin.getPositionFromMap();
// log.info(`当前小地图坐标: X=${currentPosition.X}, Y=${currentPosition.Y}`);
} catch (error) {
// 如果失败,使用大地图坐标
log.warn(`获取小地图坐标失败,使用大地图坐标。错误信息: ${error}`);
await genshin.returnMainUi();
keyPress("M");
await sleep(2000);
currentPosition = genshin.getPositionFromBigMap();
// log.info(`当前大地图坐标: X=${currentPosition.X}, Y=${currentPosition.Y}`);
keyPress("Escape");
}
// 计算欧氏距离
const dx = currentPosition.X - targetPosition.X;
const dy = currentPosition.Y - targetPosition.Y;
const distance = Math.sqrt(dx * dx + dy * dy);
// 判断距离是否在允许范围内
if (distance <= maxDistance) {
log.info(`距离:${distance} 在突发任务范围内,循环继续`);
return true;
} else {
log.warn("距离超出突发任务范围,执行触发线路");
return false;
}
}
async function fakeLog(name, isJs, isStart, duration) {
await sleep(10);
const currentTime = Date.now();
// 参数检查
if (typeof name !== 'string') {
log.error("参数 'name' 必须是字符串类型!");
return;
}
if (typeof isJs !== 'boolean') {
log.error("参数 'isJs' 必须是布尔型!");
return;
}
if (typeof isStart !== 'boolean') {
log.error("参数 'isStart' 必须是布尔型!");
return;
}
if (typeof currentTime !== 'number' || !Number.isInteger(currentTime)) {
log.error("参数 'currentTime' 必须是整数!");
return;
}
if (typeof duration !== 'number' || !Number.isInteger(duration)) {
log.error("参数 'duration' 必须是整数!");
return;
}
// 将 currentTime 转换为 Date 对象并格式化为 HH:mm:ss.sss
const date = new Date(currentTime);
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');
const formattedTime = `${hours}:${minutes}:${seconds}.${milliseconds}`;
// 将 duration 转换为分钟和秒,并保留三位小数
const durationInSeconds = duration / 1000; // 转换为秒
const durationMinutes = Math.floor(durationInSeconds / 60);
const durationSeconds = (durationInSeconds % 60).toFixed(3); // 保留三位小数
// 使用四个独立的 if 语句处理四种情况
if (isJs && isStart) {
// 处理 isJs = true 且 isStart = true 的情况
const logMessage = `正在伪造js开始的日志记录\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`------------------------------\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`→ 开始执行JS脚本: "${name}"`;
log.debug(logMessage);
}
if (isJs && !isStart) {
// 处理 isJs = true 且 isStart = false 的情况
const logMessage = `正在伪造js结束的日志记录\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}${durationSeconds}\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`------------------------------`;
log.debug(logMessage);
}
if (!isJs && isStart) {
// 处理 isJs = false 且 isStart = true 的情况
const logMessage = `正在伪造地图追踪开始的日志记录\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`------------------------------\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`→ 开始执行地图追踪任务: "${name}"`;
log.debug(logMessage);
}
if (!isJs && !isStart) {
// 处理 isJs = false 且 isStart = false 的情况
const logMessage = `正在伪造地图追踪结束的日志记录\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`→ 脚本执行结束: "${name}", 耗时: ${durationMinutes}${durationSeconds}\n\n` +
`[${formattedTime}] [INF] BetterGenshinImpact.Service.ScriptService\n` +
`------------------------------`;
log.debug(logMessage);
}
}
// 好感核心函数
async function AutoFriendship(runTimes, statueTimes, getMeatMode, delayTime, startTime, ocrTimeout) {
for (let i = 0; i < runTimes; i++) {
if ((i + 1) % statueTimes === 0) { // 判断当前循环次数否达到去神像设置值
await genshin.tpToStatueOfTheSeven();
await AutoPath(`好感-张牙舞爪的恶党-触发位置(二净甸)`);
await sleep(delayTime);
} else if (!await comparePosition()) { // 对比触发位置坐标,如果不符合预期坐标则重新执行触发线路
log.info(`导航至突发任务(张牙舞爪的恶党)触发位置(二净甸)`);
await AutoPath(`好感-张牙舞爪的恶党-触发位置(二净甸)`);
await sleep(delayTime);
notification.send(`已抵达突发任务“张牙舞爪的恶党”触发位置`);
}
await genshin.relogin();
// 判断游戏重上后是否在任务触发位置如果在就进行OCR如果不在则退回次数并重新执行触发路线
if (await comparePosition()) {
// OCR识别是否触发任务默认30秒超时
let ocrStatus = false;
let ocrStartTime = Date.now();
while (Date.now() - ocrStartTime < ocrTimeout && !ocrStatus) {
let captureRegion = captureGameRegion();
let resList = captureRegion.findMulti(RecognitionObject.ocr(0, 200, 300, 300));
for (let o = 0; o < resList.count; o++) {
let res = resList[o];
if (res.text.includes("张牙") || res.text.includes("舞爪") || res.text.includes("恶党") || res.text.includes("打倒") || res.text.includes("所有") || res.text.includes("鳄鱼")) {
ocrStatus = true;
break;
}
await sleep(500);
}
}
if (ocrStatus) {
log.info(`当前次数:${i + 1}/${runTimes}`);
// 开启急速拾取
dispatcher.addTimer(new RealtimeTimer("AutoPick", {
"forceInteraction": true
}));
const pathingName = `${i + 1}次,共${runTimes}`
await fakeLog(`${pathingName}`, false, true, 0);
//原版逻辑 await AutoPath(`好感-张牙舞爪的恶党-循环${getMeatMode ? '(二净甸刷肉版)' : '(二净甸)'}`);
//多种拾取模式
if (getMeatMode == "算了我不捡了") {
await AutoPath(`好感-张牙舞爪的恶党-循环(二净甸)`);
} else if (getMeatMode == "通用拾取") {
await AutoPath(`好感-张牙舞爪的恶党-循环(二净甸刷肉版)`);
} else if (getMeatMode == "万叶拾取") {
await AutoPath(`万叶版前往`);
await keyMouseScript.runFile(`assets/万叶拾取.json`);
await AutoPath(`万叶版返回`);
} else {
await AutoPath(`好感-张牙舞爪的恶党-循环(二净甸)`);
}
await fakeLog(`${pathingName}`, false, false, 0);
// 关闭急速拾取
dispatcher.addTimer(new RealtimeTimer("AutoPick", {
"forceInteraction": false
}));
// 根据是否回到触发位置,判定本轮循环是否执行完毕
if (await comparePosition()) {
log.info(`已完成次数:${i + 1}/${runTimes}`);
} else {
i = i - 1; // 退回这次次数
log.warn(`判定本轮循环执行失败,退回本轮执行次数:${i + 1}/${runTimes}`);
}
} else {
notification.send(`未识别到突发任务(张牙舞爪的恶党),兽肉好感结束`);
break;
}
} else {
i = i - 1; // 退回这次次数
log.warn(`判定本轮循环执行失败,退回本轮执行次数:${i + 1}/${runTimes}`);
}
const estimatedCompletion = calculateEstimatedCompletion(startTime, i + 1, runTimes);
logTimeTaken(startTime);
log.info(`预计完成时间:${estimatedCompletion}`);
}
log.info('兽肉好感已完成');
}
// 刷肉相关参数
let getMeatMode = settings.getMeatMode ? settings.getMeatMode : false;
let inputValue = settings.inputValue ? settings.inputValue : 300;
let runTimes = getMeatMode ? (isNaN(inputValue) ? 50 : Math.ceil(inputValue / 6)) : 10;
// 神像相关参数
let goStatue = settings.goStatue ? settings.goStatue : false;
let statueTimes = goStatue ? (isNaN(settings.statueTimes) ? 5 : settings.statueTimes) : 0;
// 延迟相关
let delayTime = settings.delayTime ? settings.delayTime * 1000 : 10000;
let ocrTimeout = settings.ocrTimeout ? settings.ocrTimeout * 1000 : 30000;
// 卡时间相关参数
if (settings.waitTimeMode) {
let maxTimes = settings.maxTimes ? settings.maxTimes : runTimes;
let waitTimeModeDay = settings.waitTimeModeDay
const datePattern = /^\d{4}-\d{2}-\d{2}$/; // 日期正则
if (!datePattern.test(settings.waitTimeModeDay)) {
log.error(`检测到基准日期格式错误,当前输入值为:${waitTimeModeDay}`);
waitTimeModeDay = "2025-03-31";
log.info(`使用的基准日期为:${waitTimeModeDay}`);
}
const now = new Date();
const benchmark = new Date(waitTimeModeDay + "T04:00:00");
const timeDiff = now.getTime() - benchmark.getTime();
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
let period = Number(settings.waitTimeModePeriod);
if (isNaN(period)) {
log.warn(`错误的卡时间模式周期 ${period}!使用 7 天作为周期。`);
period = 7.0;
}
if (period < 1 || period > 48) {
log.warn(`卡时间模式周期 ${period} 超过范围!使用 7 天作为周期。`);
period = 7.0;
}
const daysNormalized = daysDiff >= 0 ? daysDiff : period - (Math.abs(daysDiff) % period);
runTimes = Math.ceil(maxTimes / period) * (daysNormalized % period + 1);
}
// Main
let messages = [
'请确保队伍满员,并为队伍配置相应的战斗策略',
`使用的七天神像周期为: ${statueTimes}`,
`计算后的运行次数为: ${runTimes}`,
];
for (let message of messages) {
log.info(message);
await sleep(500);
}
log.info('兽肉好感开始...');
// 切换队伍
if (!!settings.partyName) {
try {
log.info("正在尝试切换至" + settings.partyName);
if (!await genshin.switchParty(settings.partyName)) {
log.info("切换队伍失败,前往七天神像重试");
await genshin.tpToStatueOfTheSeven();
await genshin.switchParty(settings.partyName);
}
} catch {
log.error("队伍切换失败,可能处于联机模式或其他不可切换状态");
notification.error(`队伍切换失败,可能处于联机模式或其他不可切换状态`);
await genshin.returnMainUi();
}
} else {
await genshin.returnMainUi();
}
const startTime = Date.now();
await AutoFriendship(runTimes, statueTimes, getMeatMode, delayTime, startTime, ocrTimeout);
})();