feat(auto-tool): 添加队伍切换功能并支持元素匹配

- 在SevenElement中新增矿物元素类型
- 实现基于路径的元素匹配和队伍切换逻辑
- 添加SwitchTeam工具模块实现队伍配置功能
- 集成OCR识别和图像匹配的队伍切换机制
- 支持自动翻页查找目标队伍功能
- 实现七天神像传送和队伍缓存清理功能
This commit is contained in:
yan
2026-01-11 23:20:39 +08:00
parent 1aac828633
commit 55ac84fe0d
9 changed files with 242 additions and 4 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

View File

@@ -40,8 +40,9 @@ const config_list = {
}
const SevenElement = {
SevenElements: ['火', '水', '风', '雷', '草', '冰', '岩'],
SevenElements: ['矿物', '火', '水', '风', '雷', '草', '冰', '岩'],
SevenElementsMap: new Map([
['矿物', []],
['火', []],
['水', ['海露花']],
['风', ['蒲公英籽']],
@@ -51,6 +52,8 @@ const SevenElement = {
['岩', []],
]),
}
const team = {
current: undefined,
currentElementName: undefined,
@@ -302,6 +305,7 @@ async function getValueByMultiCheckboxName(name) {
async function init() {
let settingsConfig = await initSettings();
let utils = [
"SwitchTeam",
"uid",
]
for (let util of utils) {
@@ -671,6 +675,30 @@ async function runPath(path, stopKey = AUTO_STOP) {
log.info(`[{mode}] 路径已执行: {path},跳过执行`, settings.mode, path)
return
}
const entry = [...SevenElement.SevenElementsMap.entries()].find(([key, val]) => {
return val.some(item => path.includes(`\\${item}\\`));
});
if (entry) {
const [key, val] = entry;
const index = SevenElement.SevenElements.indexOf(key);
const teamName = team.SevenElements.length > index && index >= 0 ?
team.SevenElements[index] : undefined;
if (!teamName || teamName === "") {
log.debug(`[{mode}] 没有设置队伍: {teamName},跳过切换`, settings.mode, teamName);
} else if (team.current === teamName) {
log.debug(`[{mode}] 当前队伍为: {teamName},无需切换`, settings.mode, teamName);
} else {
log.info(`[{mode}] 检测到需要: {key},切换至{val}`, settings.mode, key, teamName);
const teamSwitch = await switchUtil.SwitchPartyMain(teamName);
if (teamSwitch) {
team.current = teamSwitch;
}
}
}
try {
const one = JSON.parse(file.readTextSync(path))
if (one.info && one.info.description.includes("请配置好战斗策略")) {

View File

@@ -49,13 +49,13 @@
{
"name": "teamSevenElements",
"type": "input-text",
"label": "7元素队伍配置 按 火,水,风,雷,草,冰,岩 该顺序填写",
"label": "队伍配置 按 `矿物,火,水,风,雷,草,冰,岩` 该顺序填写",
"default": ""
},
{
"name": "choose_best",
"type": "checkbox",
"label": "择优模式",
"label": "择优模式(默认关闭 优先跑之前没跑过的)",
"default": false
},
{
@@ -66,6 +66,6 @@
{
"name": "autoSkip",
"type": "input-text",
"label": "自动跳过运行快捷键(独立BGI的快捷键请勿冲突)"
"label": "【测试功能-无效配置】自动跳过运行快捷键(独立BGI的快捷键请勿冲突)"
}
]

View File

@@ -0,0 +1,210 @@
// Party Setup
const QuickSetupButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Quick Setup Button.png"), 1100, 900, 400, 180);
const ConfigureTeamButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Configure Team Button.png"), 0, 900, 200, 180);
const ConfirmDeployButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Confirm Deploy Button.png"), 0, 900, 1920, 180);
// Slider
const LeftSliderTopRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Slider Top.png"), 650, 50, 100, 100);
const LeftSliderBottomRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Slider Bottom.png"), 650, 100, 100, 900);
const MiddleSliderTopRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Slider Top.png"), 1250, 50, 100, 200);
const MiddleSliderBottomRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Slider Bottom.png"), 1250, 100, 100, 900);
const RightSliderTopRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Slider Top.png"), 1750, 100, 100, 100);
const RightSliderBottomRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/Slider Bottom.png"), 1750, 100, 100, 900);
// 翻页
async function pageDown(SliderBottomRo) {
let captureRegion = captureGameRegion();
let SliderBottom = captureRegion.find(SliderBottomRo);
captureRegion.dispose();
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 * 2));
await moveMouseTo(0, 0);
await sleep(100);
}
}
// 滑条顶端
async function pageTop(SliderTopRo) {
let captureRegion = captureGameRegion();
let SliderTop = captureRegion.find(SliderTopRo);
captureRegion.dispose();
if (SliderTop.isExist()) {
log.info("识别到滑条顶端位置:({x},{y},{h},{w})", SliderTop.x, SliderTop.y, SliderTop.Width, SliderTop.Height);
await moveMouseTo(Math.ceil(SliderTop.x + SliderTop.Width / 2), Math.ceil(SliderTop.y + SliderTop.Height * 1));
leftButtonDown();
await sleep(1000);
leftButtonUp();
await moveMouseTo(0, 0);
await sleep(100);
}
}
// 切换队伍
async function SwitchParty(partyName) {
let ConfigureStatue = false;
let foundQuickSetup = false;
for (let j = 0; j < 2; j++) { // 尝试两次
keyPress("VK_L");
await sleep(2000);
for (let i = 0; i < 2; i++) {
let captureRegion = captureGameRegion();
let QuickSetupButton = captureRegion.find(QuickSetupButtonRo);
captureRegion.dispose();
if (QuickSetupButton.isExist()) {
log.info("已进入队伍配置页面");
foundQuickSetup = true;
break;
} else {
await sleep(1000);
}
}
if (foundQuickSetup) {
break; // 第一次找到就退出循环
}
}
if (!foundQuickSetup) {
log.error("两次尝试都未能进入队伍配置页面");
return false;
}
// 识别当前队伍
let captureRegion = captureGameRegion();
let resList = captureRegion.findMulti(RecognitionObject.ocr(100, 900, 300, 180));
captureRegion.dispose();
let currentPartyFound = false;
for (let i = 0; i < resList.count; i++) {
let res = resList[i];
log.info("当前队伍名称位置:({x},{y},{w},{h}), 识别结果:{text}", res.x, res.y, res.Width, res.Height, res.text);
if (res.text.includes(partyName)) {
log.info("当前队伍即为目标队伍,无需切换");
notification.send(`当前队伍即为目标队伍:${partyName},无需切换`);
keyPress("VK_ESCAPE");
await sleep(500);
currentPartyFound = true;
break;
}
}
if (!currentPartyFound) {
await sleep(1000);
let captureRegion = captureGameRegion();
let ConfigureTeamButton = captureRegion.find(ConfigureTeamButtonRo);
captureRegion.dispose();
if (ConfigureTeamButton.isExist()) {
log.info("识别到配置队伍按钮");
ConfigureTeamButton.click();
await sleep(500);
await pageTop(LeftSliderTopRo);
for (let p = 0; p < 4; p++) {
// 识别当前页
let captureRegion = captureGameRegion();
let resList = captureRegion.findMulti(RecognitionObject.ocr(0, 100, 400, 900));
captureRegion.dispose();
for (let i = 0; i < resList.count; i++) {
let res = resList[i];
if (settings.enableDebug) {
log.info("文本位置:({x},{y},{w},{h}), 识别内容:{text}", res.x, res.y, res.Width, res.Height, res.text);
}
if (res.text.includes(partyName)) {
log.info("目标队伍位置:({x},{y},{w},{h}), 识别结果:{text}", res.x, res.y, res.Width, res.Height, res.text);
click(Math.ceil(res.x + 360), res.y + Math.ceil(res.Height / 2));
// 找到目标队伍,点击确定、部署
await sleep(1500);
let ConfirmButtonCaptureRegion = captureGameRegion();
let ConfirmButton = ConfirmButtonCaptureRegion.find(ConfirmDeployButtonRo);
ConfirmButtonCaptureRegion.dispose();
if (ConfirmButton.isExist()) {
log.info("识别到确定按钮:({x},{y},{w},{h})", ConfirmButton.x, ConfirmButton.y, ConfirmButton.Width, ConfirmButton.Height);
ConfirmButton.click();
}
await sleep(1500);
let DeployButtonCaptureRegion = captureGameRegion();
let DeployButton = DeployButtonCaptureRegion.find(ConfirmDeployButtonRo);
DeployButtonCaptureRegion.dispose();
if (DeployButton.isExist()) {
log.info("识别到部署按钮:({x},{y},{w},{h})", DeployButton.x, DeployButton.y, DeployButton.Width, DeployButton.Height);
DeployButton.click();
notification.send(`寻找到目标队伍:${partyName}`);
ConfigureStatue = true;
break;
}
}
}
if (ConfigureStatue) {
await genshin.returnMainUi();
break;
} else {
await pageDown(LeftSliderBottomRo);
}
}
if (!ConfigureStatue) {
// 没找到指定队伍名称的队伍,抛出异常
log.error(`没有找到指定队伍名称:${partyName}`);
notification.error(`没有找到指定队伍名称:${partyName}`);
await genshin.returnMainUi();
throw new Error(`没有找到指定队伍名称:${partyName}`);
}
} else {
// 没找到配置队伍按钮,抛出异常
log.error("没有找到配置队伍按钮");
notification.error("没有找到配置队伍按钮");
await genshin.returnMainUi();
throw new Error("没有找到配置队伍按钮");
}
} else {
// 当前队伍就是目标队伍,设置成功状态
ConfigureStatue = true;
}
return ConfigureStatue;
}
async function SwitchPartyMain(partyName, disableGoStatue) {
if (!!partyName) {
try {
if (!disableGoStatue) {
// 强制去七天神像换队
log.info("强制传送到七天神像切换队伍");
await genshin.TpToStatueOfTheSeven();
log.info("正在尝试切换至" + partyName);
await SwitchParty(partyName);
} else {
// 先尝试在当前位置换队
await genshin.returnMainUi();
log.info("正在尝试切换至" + partyName);
let switchResult = await SwitchParty(partyName);
if (!switchResult) {
// 如果当前位置换队失败,去七天神像再试一次
log.info("当前位置换队失败,传送到七天神像重试");
await genshin.TpToStatueOfTheSeven();
log.info("正在七天神像重新尝试切换至" + partyName);
await SwitchParty(partyName);
}
}
genshin.clearPartyCache();
return partyName
} catch (error) {
log.error("队伍切换失败:" + error.message);
notification.error("队伍切换失败:" + error.message);
await genshin.returnMainUi();
}
} else {
log.error("没有设置切换队伍");
notification.error("没有设置切换队伍");
await genshin.returnMainUi();
}
}
this.switchUtil={
SwitchPartyMain
}
// /**
// * @returns {Promise<void>}
// */
//
// (async function () {
// await SwitchPartyMain(settings.partyName, settings.disableGoStatue);
// })();