v.1.6版本 自动幽境危战 20250702 (#1259)

### v.1.6版本:20250702

- **优化**:
1. 优化没找到地脉花领奖的超时退出处理。
2. 优化树脂识别OCR区域。
3. 优化LOG和代码写法和整理。
This commit is contained in:
kaedelcb
2025-07-02 19:12:00 +08:00
committed by GitHub
parent 17a6935d14
commit 8383fd9ce2
3 changed files with 128 additions and 110 deletions

View File

@@ -94,5 +94,12 @@
4. 优化各种`异常状态`的退出处理方法。
5. 优化当有须臾树脂时,脆弱树脂不显示时的处理。
### v.1.6版本20250702
- **优化**
1. 优化没找到地脉花领奖的超时退出处理。
2. 优化树脂识别OCR区域。
3. 优化LOG和代码写法和整理。

View File

@@ -1,18 +1,16 @@
(async function () {
let challengeNum = settings.challengeNum;//挑战次数
if (challengeNum === undefined || challengeNum === ""){challengeNum = 15; }
if (challengeNum === undefined || challengeNum === ""){challengeNum = 15; }//挑战次数
let challengeName = settings.challengeName;//挑战BOSS
if (challengeName === undefined || challengeName === ""){throw new Error("挑战Boss未配置请在JS配置中选择...")}
let Startforward = settings.Startforward*1000 ? settings.Startforward*1000 : 1000;
if (challengeName === undefined || challengeName === ""){throw new Error("挑战Boss未配置请在JS配置中选择...")}//初始化处理
let Startforward = settings.Startforward*1000 ? settings.Startforward*1000 : 1000;//开始战斗的前进时间
var Fighttimeout = settings.timeout * 1000 ? settings.timeout * 1000 : 240000;//战斗超时时间默认为240秒
const ocrRegion1 = { x: 643, y: 58, width: 800, height: 800 }; // 上方挑战成功区域
const ocrRegion2 = { x: 780, y: 406, width: 370, height: 135 }; // 中间挑战失败区域
// const ocrRegion3 = { x: 1782, y: 1023, width: 64, height: 29 }; // 右下角space区域
const ocrRo1 = RecognitionObject.ocr(ocrRegion1.x, ocrRegion1.y, ocrRegion1.width, ocrRegion1.height);
const ocrRo2 = RecognitionObject.ocr(ocrRegion2.x, ocrRegion2.y, ocrRegion2.width, ocrRegion2.height);
// const ocrRo3 = RecognitionObject.ocr(ocrRegion3.x, ocrRegion3.y, ocrRegion3.width, ocrRegion3.height);
var Rewardsuse = settings.Rewardsuse ? settings.Rewardsuse : "1/2";
const ocrRo1 = RecognitionObject.ocr(ocrRegion1.x, ocrRegion1.y, ocrRegion1.width, ocrRegion1.height);//上方挑战成功区域OCR对象
const ocrRo2 = RecognitionObject.ocr(ocrRegion2.x, ocrRegion2.y, ocrRegion2.width, ocrRegion2.height);//中间挑战失败区域OCR对象
var Rewardsuse = settings.Rewardsuse ? settings.Rewardsuse : "1/2";//树脂使用类型默认为1/2即浓缩树脂和原粹树脂
var resinTypes = Rewardsuse.split("/");
var rewards = [];
var onerewards, secendrewards, threendrewards, fourdrewards;
@@ -23,22 +21,22 @@
}
rewards.push(resinType);
}
const resinTypeMap = ["","使用1个浓缩树脂获取2倍产出", "使用20个原粹树脂", "使用1个脆弱树脂获取3倍产出", "使用1个须臾树脂获取3倍产出"];
const golbalRewards = ["","浓缩树脂","原粹树脂","脆弱树脂","须臾树脂"]; // 表示四个奖励的选项
const resinTypeMap = ["","使用1个浓缩树脂获取2倍产出", "使用20个原粹树脂", "使用1个脆弱树脂获取3倍产出", "使用1个须臾树脂获取3倍产出"];//识别树脂领奖文字
const golbalRewards = ["","浓缩树脂","原粹树脂","脆弱树脂","须臾树脂"]; // 对应四种树脂
// 根据 rewards 数组长度,依次赋值给对应的变量
if (rewards.length > 0) onerewards = golbalRewards[rewards[0]];
if (rewards.length > 1) secendrewards = golbalRewards[rewards[1]];
if (rewards.length > 2) threendrewards = golbalRewards[rewards[2]];
if (rewards.length > 3) fourdrewards = golbalRewards[rewards[3]];
const golbalRewardText = [onerewards, secendrewards, threendrewards, fourdrewards].filter(Boolean);//
const golbalRewardText = [onerewards, secendrewards, threendrewards, fourdrewards].filter(Boolean);//过滤树脂使用类型
var advanceNum = 0;//前进次数
var verticalNum = 0;
var resinAgain = false;
var advanceNum = 0;//前进寻找地脉之花次数
var verticalNum = 0;//重试寻找地脉之花次数
var resinAgain = false;//是否重试标志
var Artifacts = settings.Artifacts ? settings.Artifacts : "保持圣遗物奖励不变";
//建立一个数值映射所有圣遗物对应需要识别的图片
//映射所有圣遗物对应需要识别的图片
var artifactImageMap = {
"长夜之誓 / 深廊终曲": "assets/Artifacts/artifact_1.bmp",
"黑曜秘典 / 烬城勇者绘卷": "assets/Artifacts/artifact_2.bmp",
@@ -60,6 +58,14 @@
"如雷的盛怒 / 平息鸣雷的尊者": "assets/Artifacts/artifact_18.bmp"
};
//树脂识别图片
var condensedResin = "assets/condensed_resin_count.png";
var originalResin = "assets/original_resin_count.png";
var fragileResin = "assets/fragile_resin_count.png";
var momentResin = "assets/moment_resin_count.png";
var oneResin = "assets/one.png";
//文字识别封装函数
async function Textocr(wenzi="空参数",chaotime=10,clickocr=0,debugcode=0,x=0,y=0,w=1920,h=1080) {
const startTime = new Date();
for (let ii = 0; ii < 10; ii++)
@@ -92,6 +98,7 @@
}
}
// 图片识别封装函数
async function imageRecognition(imagefilePath="空参数",timeout=10,afterBehavior=0,debugmodel=0,xa=0,ya=0,wa=1920,ha=1080) {
const startTime = new Date();
const Imagidentify = RecognitionObject.TemplateMatch(file.ReadImageMatSync(imagefilePath));
@@ -114,12 +121,7 @@
await sleep(1200);
}
var condensedResin = "assets/condensed_resin_count.png";
var originalResin = "assets/original_resin_count.png";
var fragileResin = "assets/fragile_resin_count.png";
var momentResin = "assets/moment_resin_count.png";
var oneResin = "assets/one.png";
//树脂数量获取函数
async function getRemainResinStatus() {
var condensedResinCount = 0; // 浓缩树脂
var originalResinCount = 0; // 原粹树脂
@@ -170,13 +172,13 @@
var momentResinCountRa = await imageRecognition(momentResin,0.1, 0, 1,1170,0,350,100);
if (momentResinCountRa.found) {
// await moveMouseTo(momentResinCountRa.x+momentResinCountRa.w+15+momentResinCountRa.w+50,momentResinCountRa.y-15+momentResinCountRa.h+25);
let countArea = await Textocr("",0.5, 0, 2,momentResinCountRa.x+momentResinCountRa.w+15,momentResinCountRa.y-15,momentResinCountRa.w+50,momentResinCountRa.h+25);//
let countArea = await Textocr("",0.5, 0, 2,momentResinCountRa.x+momentResinCountRa.w+20,momentResinCountRa.y-15,60,40);//
if (countArea.found){
//log.info("须臾树脂识别数量结果:"+ countArea.text);
momentResinCount = countArea.text
}
else{
var oneRa = await imageRecognition(oneResin,0.1, 0, 1,momentResinCountRa.x+momentResinCountRa.w+15,momentResinCountRa.y-15,momentResinCountRa.w+50,momentResinCountRa.h+25);
var oneRa = await imageRecognition(oneResin,0.1, 0, 1,momentResinCountRa.x+momentResinCountRa.w+20,momentResinCountRa.y-15,60,40);
if (oneRa.found){
momentResinCount = "1";
}else{
@@ -190,14 +192,14 @@
{
var fragileResinCountRa = await imageRecognition(fragileResin,0.1, 0, 1,1170,0,350,100);
if (fragileResinCountRa.found) {
// await moveMouseTo(fragileResinCountRa.x,fragileResinCountRa.y);
let countArea = await Textocr("",0.5, 0, 2,fragileResinCountRa.x+fragileResinCountRa.w+15,fragileResinCountRa.y-15,fragileResinCountRa.w+50,fragileResinCountRa.h+25);//
// await moveMouseTo(fragileResinCountRa.x+fragileResinCountRa.w+20,fragileResinCountRa.y-15);
let countArea = await Textocr("",0.5, 0, 2,fragileResinCountRa.x+fragileResinCountRa.w+20,fragileResinCountRa.y-15,60,40);//
if (countArea.found){
// log.info("脆弱树脂识别数量结果:"+ countArea.text);
fragileResinCount = countArea.text
}
else{
var oneRa = await imageRecognition(oneResin,0.1, 0, 1,fragileResinCountRa.x+fragileResinCountRa.w+15,fragileResinCountRa.y-15,fragileResinCountRa.w+50,fragileResinCountRa.h+25);
var oneRa = await imageRecognition(oneResin,0.1, 0, 1,fragileResinCountRa.x+fragileResinCountRa.w+20,fragileResinCountRa.y-15,60,40);
if (oneRa.found){
fragileResinCount = "1";
}else{
@@ -215,53 +217,58 @@
return {condensedResinCount,originalResinCount,fragileResinCount,momentResinCount}
}
//征讨之花领奖
//征讨之花领奖寻找函数
const autoNavigateToReward = async () => {
// 定义识别对象
const boxIconRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/box.png"));
// 定义识别对象
const boxIconRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/box.png"));
advanceNum = 0;//前进次数
//调整为俯视视野
middleButtonClick();
await sleep(800);
moveMouseBy(0, 1030);
await sleep(400);
moveMouseBy(0, 920);
await sleep(400);
moveMouseBy(0, 710);
log.info("开始领奖");
advanceNum = 0;//前进次数
//调整为俯视视野
middleButtonClick();
await sleep(800);
moveMouseBy(0, 1030);
await sleep(400);
moveMouseBy(0, 920);
await sleep(400);
moveMouseBy(0, 710);
log.info("开始领奖");
while (true) {
// 1. 优先检查是否已到达领奖点
let captureRegion = captureGameRegion();
let rewardTextArea = captureRegion.DeriveCrop(1210, 515, 200, 50);
let rewardResult = rewardTextArea.find(RecognitionObject.ocrThis);
// 检测到特点文字则结束!!!
if (rewardResult.text == "激活地脉之花") {
log.info("已到达领奖点,检测到文字: " + rewardResult.text);
return true;
}
else if(advanceNum > 80){
while (true) {
// 1. 优先检查是否已到达领奖点
let captureRegion = captureGameRegion();
let rewardTextArea = captureRegion.DeriveCrop(1210, 515, 200, 50);
let rewardResult = rewardTextArea.find(RecognitionObject.ocrThis);
// 检测到特点文字则结束!!!
if (rewardResult.text == "激活地脉之花") {
log.info("已到达领奖点,检测到文字: " + rewardResult.text);
return true;
}
else if(advanceNum > 40){
await getOut();
await await genshin.returnMainUi();
throw new Error('前进时间超时');
}
// 2. 未到达领奖点,则调整视野
for(let i = 0; i < 100; i++){
}
// 2. 未到达领奖点,则调整视野
for(let i = 0; i < 100; i++){
captureRegion = captureGameRegion();
let iconRes = captureRegion.Find(boxIconRo);
let climbTextArea = captureRegion.DeriveCrop(1808, 1030, 25, 25);
let climbResult = climbTextArea.find(RecognitionObject.ocrThis);
// 检查是否处于攀爬状态
if (climbResult.isEmpty()){
log.info("检侧到页面错误,尝试脱离");
let SHU = Textocr("地脉之花", 0.3, 1, 0, 840,225, 230, 125);
if (SHU.found){return true;}
await keyDown("w");
await keyPress("VK_ESCAPE");
await sleep(500);
await keyDown("w");
await sleep(5000);
await keyUp("w");
let SHU = Textocr("地脉之花", 0.3, 1, 0, 840,225, 230, 125);
if (SHU.found){
return true;
}
log.info("检侧到页面错误,尝试脱离");
await keyDown("w");
await keyPress("VK_ESCAPE");
await sleep(500);
await keyDown("w");
await sleep(5000);
await keyUp("w");
}
if (iconRes.x >= 920 && iconRes.x <= 980 && iconRes.y <= 540) {
advanceNum++;
log.info(`视野已调正,前进第${advanceNum}`);
@@ -280,10 +287,12 @@
if(i > 97) {
if (verticalNum >= 2) {
verticalNum = 0;
await getOut();
await await genshin.returnMainUi();
throw new Error('领取超时');
}
log.info("领取超时重新尝试1次");
await genshin.returnMainUi(); await sleep(1000);//退出待写
await sleep(1000);
return false;
}
}
@@ -299,6 +308,7 @@
}
}
//向前寻找钥匙函数
async function readyFightIn(){
var startTime = new Date();
await sleep(500);
@@ -320,7 +330,7 @@
return false
}
//异步检测战斗来自D捣蛋&秋云佬的全自动地脉花的代码
//异步检测战斗执行函数来自D捣蛋&秋云佬的全自动地脉花的代码
async function autoFight(timeout) {
const cts = new CancellationTokenSource();
log.info("开始战斗");
@@ -332,6 +342,7 @@
return fightResult;
}
//异步检测战斗结果函数
async function recognizeTextInRegion(timeout) {
return new Promise((resolve, reject) => {
(async () => {
@@ -383,7 +394,7 @@
});
}
// 领取奖励更换
//圣遗物奖励更换函数
async function selectionHolyRelics() {
let artifactImagePath = artifactImageMap[Artifacts];
@@ -445,8 +456,9 @@
return true;
}
// 领取奖励函数
async function claimRewards() {
log.info(`尝试领取奖励,优先${onerewards}'`);
// log.info(`尝试领取奖励,优先${onerewards}'`);
let SHUN01 = await Textocr("激活地脉之花",0.6,2,0,1188,358,200,400);
let SHUN02 = await Textocr("地脉之花", 0.2, 1, 0, 840,225, 230, 125);
if (SHUN01.found || SHUN02.found) {
@@ -457,6 +469,7 @@
log.warn("未找到地脉之花,尝试向前寻找...")
await keyDown("W");await sleep(300);await keyUp("W");
await keyPress("F");
await sleep(1000);
}
await sleep(300);
@@ -476,7 +489,7 @@
await sleep(100);
await click(SHU.x+550,SHU.y)
await sleep(300);
log.info(` ${resinTypeMap[rewards[i]]} 获取奖励...`);
log.info(`${resinTypeMap[rewards[i]]} 获取奖励...`);
await Textocr("锁定辅助",10,0,0,1768,0,115,90);
let { condensedResinCount, originalResinCount, fragileResinCount , momentResinCount} = await getRemainResinStatus();
@@ -501,7 +514,6 @@
if (shouldExit)
{
log.warn("树脂耗尽,停止执行...");
await sleep(1000);
await keyPress("VK_ESCAPE");
await sleep(1000);
@@ -520,6 +532,7 @@
return false;
}
// 进入秘境入口函数
async function VeinEntrance() {
for (let i = 0;i < 2;i++) {
let JIECHU = await Textocr("F",2,2,0,1098,519,35,32);
@@ -544,6 +557,7 @@
}
}
//秘境内退出函数
async function getOut() {
for (let i = 0;i < 2;i++){
@@ -564,7 +578,7 @@
}
log.warn("自动幽境危战版本v1.5");
log.warn("自动幽境危战版本v1.6");
log.warn("请保证队伍战斗实力,战斗失败或执行错误,会重试两次...");
log.warn("使用前请在 <<幽境危战>> 中配置好战斗队伍...");
log.info("使用树脂类型数量:{0} ", rewards.length)
@@ -577,18 +591,22 @@
resinAgain = false; //重试标志
try{
//1.导航进入页面
await genshin.returnMainUi();
await pathingScript.runFile(`assets/全自动幽境危战.json`);
await VeinEntrance();
// 进入-选择难道
//2.难度确认和选择
let intoAction = await Textocr("单人挑战",10,0,0,1554,970,360, 105);
if (!intoAction.found) {await genshin.returnMainUi();throw new Error("未进入挑战页面,停止执行...")}
if (!intoAction.found){
await genshin.returnMainUi();
throw new Error("未进入挑战页面,停止执行...")
}
let adjustmentType = await Textocr("至危挑战", 1, 0, 0,797,144,223,84);
if (adjustmentType.found) {
log.warn("找到至危挑战,尝试切换...")
await sleep(500);
await click(890,191)
await click(adjustmentType.x,adjustmentType.y)
await sleep(500);
}
let hardMode = await Textocr("困难", 0.3, 0, 0,1049,157,72,47);
@@ -604,7 +622,7 @@
await click(1093,399);
}
//圣遗物奖励选择
//3.圣遗物奖励选择
if (Artifacts != "保持圣遗物奖励不变"){
let artifact = await imageRecognition(artifactImageMap[Artifacts],0.2,0,0,186,972,71,71);
if (!artifact.found) {
@@ -616,54 +634,44 @@
}
}
//多点击一次,保证进入挑战页面
//4.进入秘境
await sleep(500);
await click(intoAction.x,intoAction.y)
await sleep(1000);
await click(intoAction.x,intoAction.y)
let enter = await Textocr("Enter",15,0,0,18,990,156,71,71);
if (!enter.found){
await genshin.returnMainUi();
throw new Error("未进入秘境,停止执行...")
}
//进入秘境
let enter = await Textocr("Enter",10,0,0,18,990,156,71,71);
if (!enter.found){await genshin.returnMainUi();throw new Error("未进入秘境,停止执行...")}//退出待写
//向前走进入挑战
//5.向前走进入挑战
if (!(await readyFightIn())){
await getOut();
await genshin.returnMainUi();
throw new Error("未进入准备战斗,停止执行...")
}//退出待写
}
await sleep(1000);
//选择挑战怪兽
//6.选择挑战boss
log.info("选择挑战Boss'{0}' 挑战次数:'{1}'", challengeName,challengeNum)
log.info(`期间树脂耗尽会自动退出秘境...`);
const clickCoordinates = [ { x: 207, y: 349 }, { x: 239, y: 531 }, { x: 227, y: 713 } ]; // Boss坐标1~3
await click(clickCoordinates[challengeName - 1].x, clickCoordinates[challengeName - 1].y);
switch (challengeName) {
case "1":
await click(207,349);
break;
case "2":
await click(239,531);
break;
case "3":
await click(227,713);
break;
default:
throw new Error("未知的挑战Boss类型");
}
//选择队员-苏婷老师-待写
// log.warn("队伍选择功能等伟大的苏苏老师考完试做...")
//6.5选择队员-苏婷老师-待写
//log.warn("队伍选择功能等伟大的苏苏老师考完试做...")
//7.开始挑战
await Textocr("开始挑战",1,1,0,1554,970,360, 105);
var resinexhaustion = false; // 条件1树脂耗尽
//开始战斗循环
//8.战斗循环
for (let i = 0;i < challengeNum; i++) {
//进入秘境
log.info("进入战斗环境,开始第 {0} 次战斗", i+1)
//8.1自动战斗
for (let fightCount = 0; fightCount < 3; fightCount++) {
let battleBegins = await Textocr("战斗开始",20,0,0,877,235,164,50);
@@ -707,6 +715,7 @@
}
}
//8.2领取奖励
if (resinAgain != true) {
await sleep(1000);
@@ -758,7 +767,7 @@
}
}
//是否继续
//8.3判断继续或退出
if (challengeNum == i+1 || resinexhaustion == true || resinAgain == true ){
log.info(resinAgain ? "累计战斗失败 3 次,退出秘境..."
: (challengeNum == i+1) ? `完成 ${i+1}/${challengeNum} 次战斗,退出挑战...`: `树脂耗尽,退出挑战...`);
@@ -791,11 +800,13 @@
}
}
catch (error) {
//9.执行错误,重试处理
log.error(`执行过程中发生错误:${error.message}`);
resinAgain = true;
await genshin.returnMainUi();
continue;
}finally{
//10.结束脚本
await genshin.returnMainUi();
if (resinAgain == false) log.info(`Auto自动幽境危战结束...`);
}

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "自动幽境危战",
"version": "1.5",
"version": "1.6",
"tags": ["幽境危战"],
"bgi_version": "0.44.8",
"description": "请先配置好秘境内的队伍,幽境危战战斗失败或执行错误会重试一次,请保证队伍实力",