Files
bettergi-scripts-list/repo/js/AIPC珍贵宝箱无限刷/main.js
起个名字好难 873e10619e fix: typos.
2025-06-25 06:39:47 +08:00

408 lines
16 KiB
JavaScript
Raw 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.

const SettingsButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/SettingsButton.png"), 0, 650, 100, 300);
const RestoreButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/RestoreButton.png"), 1400, 950, 130, 130);
const MaterialsRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/Materials.png"), 900, 0, 100, 100);
const MaterialsSelectedRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/MaterialsSelected.png"), 900, 0, 100, 100);
const SliderBottomRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/SliderBottom.png"), 1280, 110, 25, 845);
const CabbageRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/Cabbage.png"), 110, 90, 1170, 875);
const RadishRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/Radish.png"), 110, 90, 1170, 875);
const AbandonCurrentHangoutEventButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/AbandonCurrentHangoutEventButton.png"), 1400, 950, 130, 130);
const ConfirmButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/ConfirmButton.png"));
const StoryQuestsButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/StoryQuestsButton.png"), 90, 900, 150, 150);
const InProgressButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/InProgressButton.png"), 700, 0, 500, 100);
const InProgressButtonSelectedRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/InProgressButtonSelected.png"), 700, 0, 500, 100);
const HangoutEventButtonSelected1Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/HangoutEventButtonSelected1.png"), 800, 0, 350, 100);
const HangoutEventButtonSelected2Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/HangoutEventButtonSelected2.png"), 800, 0, 350, 100);
const HangoutEventButtonSelected3Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/HangoutEventButtonSelected3.png"), 800, 0, 350, 100);
const PlusButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/PlusButton.png"), 0, 325, 140, 200);
const MaxRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/Max.png"), 0, 325, 140, 200);
const LocationButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/LocationButton.png"), 1300, 0, 450, 100);
/**
* @returns {Promise<void>}
*/
(async function () {
// 留空或曾经设定后删除运行30轮否则为设定值
let runTimes = isNaN(settings.runTimes) || settings.runTimes === '' ? 50 : settings.runTimes;
const messages = [
'1.请使用0.44.0或版本号更高的BetterGI运行本JS',
`2.确保完成班尼特邀约任务`,
`3.行走位最好是E恢复角色`,
`4.关闭E技能回血'${settings.disableHealHP ? "是" : "否"}'`,
`5.预期执行轮数'${runTimes}'`,
];
for (let message of messages) {
log.info(message);
await sleep(100);
}
const startTime = Date.now();
await genshin.returnMainUi();
// 实时拾取极速版
dispatcher.addTimer(new RealtimeTimer("AutoPick", {
"forceInteraction": true
}));
// 拾取状态检测
let pickStatus = await UpperLimitPreciousChest(); // 没超过返回true超过返回false
// 默认按键状态检测
let keyStatus = await CheckKeyBindlings(); // 正常返回true异常返回false
log.warn(`启动预检测结束,本机当前状态:${keyStatus ? "正常" : "异常"},系统当前状态:${pickStatus ? "正常" : "异常"}`);
if (keyStatus && pickStatus) {
// 获取等效摩拉计算所需的物品初始数量
if (settings.mora) {
const StartNum = await CabbageRadishNum();
RadishStartNum = StartNum.RadishNum;
CabbageStartNum = StartNum.CabbageNum;
}
log.info(`开始刷取珍贵宝箱`);
if (!settings.enableSimplifyMode) {
await AutoPath(`前往地点${settings.disableFullMode ? "(工程模式)" : ""}`);
}
// let prePickStatus = true; // 测试用
let prePickStatus = await UpperLimitPreciousChest(); // 到达地点时检查一次
log.warn(`检查点检测结束,系统当前状态:${prePickStatus ? "正常" : "异常"}`);
if (prePickStatus) {
await AbandonHangoutEvent(0); // 防止之前没删任务,先删一遍
// 刷宝箱循环
const estimatedStartTime = Date.now();
for (let i = 0; i < runTimes; i++) {
// 滑动接取邀约任务
await ReceiveHangoutEvent(i);
// 路径执行前检查一次
await sleep(500);
let pickStatusBefore = await UpperLimitPreciousChest();
log.warn(`${i + 1} 次预检测结束,系统当前状态 ${pickStatus ? "正常" : "异常"}`);
if (!pickStatusBefore) {
log.warn("本次预检测到超过 3 次宝箱未成功拾取,推测已触发系统风控,主动终止运行");
break;
}
// 执行拾取宝箱路径
await AutoPath(`宝箱(${settings.disableHealHP ? "" : "HP版"}循环)`);
// 路径完成后检查一次
let pickStatusAfter = await UpperLimitPreciousChest();
if (!pickStatusAfter) {
log.warn(`${i + 1} 次循环执行完成,本轮检测到超过 3 次宝箱未成功拾取,推测已触发系统风控,主动终止运行`);
break;
}
// 统计用时
log.info(`已完成循环:${i + 1}/${runTimes}`);
logTimeTaken(startTime);
if (i > 1) {
const estimatedCompletion = calculateEstimatedCompletion(estimatedStartTime, i + 1, runTimes);
log.info(`预计完成时间:${estimatedCompletion}`);
}
// 开启任务菜单放弃邀约任务
await AbandonHangoutEvent(i + 1);
}
// 统计摩拉
if (settings.mora) {
const EndNum = await CabbageRadishNum();
RadishEndNum = EndNum.RadishNum;
CabbageEndNum = EndNum.CabbageNum;
let totalSeconds = logTimeTaken(startTime);
RadishMora = Math.ceil(RadishEndNum - RadishStartNum) * 315
CabbageMora = Math.ceil(CabbageEndNum - CabbageStartNum) * 105
log.info(`获得白萝卜:${RadishEndNum - RadishStartNum},卷心菜:${CabbageEndNum - CabbageStartNum}`);
log.info(`等效摩拉:${RadishMora + CabbageMora},摩拉效率:${((RadishMora + CabbageMora) / totalSeconds).toFixed(2)} 摩拉/秒`);
}
} else {
log.warn("检查点检测结束,检测未能通过: 宝箱未成功拾取,推测当前刷取的宝箱数量已触发风控,被系统禁止拾取,主动终止运行");
}
} else if (!keyStatus) {
log.warn("按键或识别出现异常,可能卡在某个交互页面中,请自行检查");
} else if (!pickStatus) {
log.warn("当前刷取的宝箱已触发风控,被系统禁止拾取,主动终止运行");
} else {
log.warn("按键或识别出现异常,请自行检查");
}
// 以下部分为封装函数
// 默认按键检测
async function CheckKeyBindlings() {
let keyStatus = false;
for (let i = 0; i < 2; i++) {
await TryOpenQuestMenu(0);
let StoryQuestsButton = captureGameRegion().find(StoryQuestsButtonRo);
if (StoryQuestsButton.isExist()) {
log.info("检测到任务菜单已开启,按键正常");
await sleep(1000);
keyStatus = true;
} else {
log.info("检测到任务菜单没有开启,推测快捷键不是默认值,尝试恢复");
await KeyBindlings(); // 恢复默认键位
await TryOpenQuestMenu(0);
let StoryQuestsButton = captureGameRegion().find(StoryQuestsButtonRo);
if (StoryQuestsButton.isExist()) {
log.info("识别到传说任务按钮,按键正常");
await sleep(1000);
keyStatus = true;
} else {
log.warn("尝试恢复任务菜单快捷键默认值失败");
keyStatus = false;
}
}
break;
}
await genshin.returnMainUi();
await sleep(1000);
return keyStatus;
}
// 尝试打开任务菜单
async function TryOpenQuestMenu() {
keyPress("J");
await sleep(1500);
}
// 恢复任务菜单按键
async function KeyBindlings() {
await genshin.returnMainUi();
await sleep(2000);
keyPress("ESCAPE");
await sleep(2000);
let SettingsButton = captureGameRegion().find(SettingsButtonRo);
if (SettingsButton.isExist()) {
log.info("识别到设置按钮");
SettingsButton.click();
await sleep(2000);
let captureRegion = captureGameRegion();
let resList = captureRegion.findMulti(RecognitionObject.ocr(100, 100, 300, 300));
for (let i = 0; i < resList.count; i++) {
let res = resList[i];
if (res.text.includes("Key") || res.text.includes("Bindings") || res.text.includes("按键") || res.text.includes("按鍵")) {
log.info("按键选项卡位置:({x},{y},{h},{w}), 文本{text}", res.x, res.y, res.width, res.Height, res.text);
res.click();
await sleep(2000);
let RestoreButton = captureGameRegion().find(RestoreButtonRo);
if (RestoreButton.isExist()) {
log.info("识别到恢复默认按钮");
RestoreButton.click();
await sleep(1500);
let ConfirmButton = captureGameRegion().find(ConfirmButtonRo);
if (ConfirmButton.isExist()) {
log.info("识别到确认按钮");
ConfirmButton.click();
await sleep(1500);
}
}
}
}
}
await genshin.returnMainUi();
}
// 识别卷心菜、白萝卜数量
async function CabbageRadishNum() {
setGameMetrics(1920, 1080, 1);
await genshin.returnMainUi();
await sleep(1000);
keyPress("B");
await sleep(1500);
let RadishNum = 0
let CabbageNum = 0
let Materials = captureGameRegion().find(MaterialsRo);
let MaterialsSelected = captureGameRegion().find(MaterialsSelectedRo);
if (Materials.isExist()) {
log.info("识别到材料按钮");
Materials.click();
await sleep(1500);
} else if (MaterialsSelected.isExist()) {
log.info("识别到材料按钮");
MaterialsSelected.click();
await sleep(1500);
}
for (let i = 0; i < 10; i++) {
let Radish = captureGameRegion().find(RadishRo);
if (Radish.isExist()) {
// log.info("识别到白萝卜,进行OCR获取数量");
let resList = captureGameRegion().findMulti(RecognitionObject.ocr(Radish.x, Radish.y + Radish.width, Radish.Width, Radish.Height));
for (let i = 0; i < resList.count; i++) {
let Radish = resList[i];
log.info("白萝卜识别结果:({x},{y},{h},{w}), 数量:{text}", Radish.x, Radish.y, Radish.Width, Radish.Height, Radish.text);
RadishNum = Radish.text
break;
}
}
let Cabbage = captureGameRegion().find(CabbageRo);
if (Cabbage.isExist()) {
// log.info("识别到卷心菜,进行OCR获取数量");
let resList = captureGameRegion().findMulti(RecognitionObject.ocr(Cabbage.x, Cabbage.y + Cabbage.width, Cabbage.Width, Cabbage.Height));
for (let i = 0; i < resList.count; i++) {
let Cabbage = resList[i];
log.info("卷心菜识别结果:({x},{y},{h},{w}), 数量:{text}", Cabbage.x, Cabbage.y, Cabbage.Width, Cabbage.Height, Cabbage.text);
CabbageNum = Cabbage.text
break;
}
break;
}
let SliderBottom = captureGameRegion().find(SliderBottomRo);
if (SliderBottom.isExist()) {
log.info("识别到滑块,当前页面没有目标物品,向下滑动");
// log.info("滑块当前位置:({x},{y},{h},{w})", SliderBottom.x, SliderBottom.y, SliderBottom.Width, SliderBottom.Height);
click(Math.ceil(SliderBottom.x + SliderBottom.Width / 2), Math.ceil(SliderBottom.y + SliderBottom.Height + SliderBottom.Height / 2));
await moveMouseTo(0, 0)
await sleep(250);
}
}
await genshin.returnMainUi();
// log.info(`白萝卜数量:${RadishNum},卷心菜数量: ${CabbageNum}`)
return {
RadishNum,
CabbageNum
};
}
// 接取任务
async function ReceiveHangoutEvent(times) {
setGameMetrics(3840, 2160, 2);
for (let r = 0; r < 7; r++) {
await sleep(500);
click(3724, 786); // 切角色邀约,第七次切到班尼特
}
await sleep(1000);
click(3120, 920);
if (times == 0) {
await sleep(500);
await moveMouseTo(105, 787)
for (let p = 0; p < 40; p++) {
let captureRegion = captureGameRegion();
let MaxStatus = captureRegion.Find(MaxRo);
if (MaxStatus.isEmpty()) {
click(105, 787); // 调整缩放到最大
} else if (MaxStatus.isExist()) {
log.info("缩放已调整至最大");
break;
}
await sleep(40);
}
}
if (times == 0) {
let LocationButton = captureGameRegion().find(LocationButtonRo);
if (LocationButton.isExist()) {
log.info("识别到定位当前节点按钮");
LocationButton.click();
await sleep(1000);
}
}
await sleep(1000);
click(3500, 1330); // 蒲公英原始坐标
await sleep(500);
click(3500, 2030); // 继续按钮
}
// 开任务列表删任务
async function AbandonHangoutEvent(times) {
keyPress("J");
await sleep(1500);
if (times == 0) {
let InProgressButton = captureGameRegion().find(InProgressButtonRo);
if (InProgressButton.isExist()) {
log.info("识别到进行中任务按钮");
InProgressButton.click();
await sleep(1500);
}
}
let AbandonCurrentHangoutEventButton = captureGameRegion().find(AbandonCurrentHangoutEventButtonRo);
if (AbandonCurrentHangoutEventButton.isExist()) {
log.info("识别到放弃按钮");
AbandonCurrentHangoutEventButton.click();
await sleep(1500);
}
let ConfirmButton = captureGameRegion().find(ConfirmButtonRo);
if (ConfirmButton.isExist()) {
log.info("识别到确认按钮");
ConfirmButton.click();
await sleep(1500);
}
let StoryQuestsButton = captureGameRegion().find(StoryQuestsButtonRo);
if (StoryQuestsButton.isExist()) {
log.info("识别到传说任务按钮");
StoryQuestsButton.click();
await sleep(1500);
}
if (times == 0) {
let captureRegion = captureGameRegion();
let HangoutEventButtonSelected1 = captureRegion.find(HangoutEventButtonSelected1Ro);
let HangoutEventButtonSelected2 = captureRegion.find(HangoutEventButtonSelected2Ro);
let HangoutEventButtonSelected3 = captureRegion.find(HangoutEventButtonSelected3Ro);
if (HangoutEventButtonSelected1.isExist()) {
log.info("识别到邀约事件选项卡按钮");
HangoutEventButtonSelected1.click();
await sleep(1500);
} else if (HangoutEventButtonSelected2.isExist()) {
log.info("识别到邀约事件选项卡按钮");
HangoutEventButtonSelected2.click();
await sleep(1500);
} else if (HangoutEventButtonSelected3.isExist()) {
log.info("识别到邀约事件选项卡按钮");
HangoutEventButtonSelected3.click();
await sleep(1500);
}
}
}
// 检测宝箱是否已到上限
async function UpperLimitPreciousChest() {
let pickStatus = true;
let failureCount = 0; // 计数检测到宝箱失败的次数
for (let p = 0; p < 5; p++) {
let captureRegion = captureGameRegion();
let resList = captureRegion.findMulti(RecognitionObject.ocr(960, 0, 650, 1080));
for (let i = 0; i < resList.count; i++) {
let res = resList[i];
if (res.text.includes("Precious") || res.text.includes("Chest") || res.text.includes("箱") || res.text.includes("珍貴") || res.text.includes("珍贵")) {
failureCount++;
log.warn(`检测到宝箱未被拾取 (${failureCount}/5) 次`);
if (failureCount >= 3) {
// log.warn("检测到超过 3 次宝箱未成功拾取,推测已触发系统风控,主动终止运行");
pickStatus = false;
break;
}
}
}
}
return pickStatus;
}
// 执行路径
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(2000);
}
// 运行用时
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}`);
return totalTimeInSeconds;
}
// 预估时间
function calculateEstimatedCompletion(estimatedStartTime, current, total) {
if (current === 0) return "计算中...";
const elapsedTime = Date.now() - estimatedStartTime;
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)} 分钟)`;
}
})();