diff --git a/repo/js/AutoSwitchRoles/Assets/characterimage/班尼特02.png b/repo/js/AutoSwitchRoles/Assets/characterimage/班尼特02.png new file mode 100644 index 000000000..bebbb87eb Binary files /dev/null and b/repo/js/AutoSwitchRoles/Assets/characterimage/班尼特02.png differ diff --git a/repo/js/AutoSwitchRoles/main.js b/repo/js/AutoSwitchRoles/main.js index 33edeb4c7..05994b455 100644 --- a/repo/js/AutoSwitchRoles/main.js +++ b/repo/js/AutoSwitchRoles/main.js @@ -35,10 +35,10 @@ function readAliases() { setGameMetrics(1920, 1080, 1); // 返回主界面 await genshin.returnMainUi(); - //切换配对 - if (settings.switchPartyName) { - await genshin.switchParty(settings.switchPartyName); - } + //切换配对 + if (settings.switchPartyName) { + await genshin.switchParty(settings.switchPartyName); + } const option = settings.option; if (option === '推荐-非快速配对模式 @Tool_tingsu') { @@ -50,6 +50,9 @@ function readAliases() { [1462, 538] ]; + // 获取初始角色数组 + const initialAvatars = getAvatars(); + // 读取别名 const aliases = readAliases(); @@ -58,15 +61,21 @@ function readAliases() { settings.position2, settings.position3, settings.position4 - ].map(input => { - if (input && input.trim()!== "") { + ].map((input, index) => { + if (input && input.trim() !== "") { const actualName = aliases[input] || input; log.info(`设置对应号位为【${input}】,切换角色为【${actualName}】`); + // 替换初始数组对应位置 + initialAvatars[index] = actualName; return actualName; } return null; }); + // 目标角色数组(替换后的初始数组) + const targetAvatars = [...initialAvatars]; + log.info(`目标角色: [${targetAvatars}]`); + // 识别对象定义 const roTeamConfig = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`Assets/RecognitionObject/队伍配置.png`), 0, 0, 1920, 1080); const roReplace = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`Assets/RecognitionObject/更换.png`), 0, 0, 1920, 1080); @@ -74,9 +83,11 @@ function readAliases() { let openPairingTries = 0; let totalOpenPairingTries = 0; + let retryCount = 0; // 重试计数器 + let switchSuccess = false; // 在进入角色切换逻辑前进行检测,如果所有角色设置均为空则直接退出 - if (positionSettings.every((item) =>!item)) { + if (positionSettings.every((item) => !item)) { log.info("未设置任何角色,跳过切换队伍步骤"); await genshin.returnMainUi(); return; @@ -104,97 +115,130 @@ function readAliases() { } } - if (!(await openPairingInterface())) { + // 角色切换逻辑封装 + async function switchCharacters() { + if (!(await openPairingInterface())) { + return false; + } + + for (let i = 0; i < positionSettings.length; i++) { + let rolenum = i + 1; + const selectedCharacter = positionSettings[i]; + if (!selectedCharacter) { + log.info(`未设置${rolenum}号位角色,跳过`); + continue; + } + const [x, y] = positionCoordinates[i]; + click(x, y); + log.info(`开始设置${rolenum}号位角色`); + await sleep(1000); + let characterFound = false; + let pageTries = 0; + + // 最多尝试滚动页面20次 + while (pageTries < 20) { + // 尝试识别所有可能的角色文件名 + for (let num = 1; ; num++) { + const paddedNum = num.toString().padStart(2, "0"); + const characterFileName = `${selectedCharacter}${paddedNum}`; + try { + const characterRo = RecognitionObject.TemplateMatch( + file.ReadImageMatSync(`Assets/characterimage/${characterFileName}.png`), + 0, 0, 1920, 1080 + ); + const characterResult = captureGameRegion().find(characterRo); + if (characterResult.isExist()) { + log.info(`已找到角色【${selectedCharacter}】`); + characterResult.click(); + await sleep(500); + characterFound = true; + break; + } + } catch (error) { + // 文件不存在,跳出循环 + break; + } + } + + if (characterFound) { + break; + } + + // 滚动页面 + if (pageTries < 15) { + log.info("当前页面没有目标角色,滚动页面"); + await scrollPage(200); + } + pageTries++; + } + + if (!characterFound) { + log.error(`未找到【${selectedCharacter}】`); + continue; + } + + // 识别"更换"或"加入"按钮 + const replaceResult = captureGameRegion().find(roReplace); + const joinResult = captureGameRegion().find(roJoin); + + if (replaceResult.isExist() || joinResult.isExist()) { + await sleep(300); + if (replaceResult.isExist()){ + replaceResult.click(); + } else { + joinResult.click(); + } + keyPress("VK_LBUTTON"); + await sleep(500); + } else { + log.error(`该角色已在队伍中,无需切换`); + await sleep(300); + keyPress("VK_ESCAPE"); + await sleep(500); + } + await sleep(500); + } + return true; + } + + // 执行切换并检查结果 + while (retryCount < 2) { // 最多尝试2次(初始1次+重试1次) + if (!await switchCharacters()) { + log.error("角色切换过程失败"); + return; + } + + // 返回主界面后获取最终角色数组 + await genshin.returnMainUi(); + const finalAvatars = getAvatars(); + + // 比较数组是否完全一致 + const arraysEqual = targetAvatars.length === finalAvatars.length && + targetAvatars.every((val, idx) => val === finalAvatars[idx]); + + if (arraysEqual) { + log.info("角色切换成功"); + switchSuccess = true; + break; + } else { + log.warn("角色不匹配,准备重试..."); + retryCount++; + if (retryCount >= 2) { + log.error("角色切换失败"); + return; + } + // 重新打开配对界面准备重试 + await genshin.returnMainUi(); + } + } + + if (!switchSuccess) { + log.error("角色切换失败"); return; } - // 角色切换逻辑 - for (let i = 0; i < positionSettings.length; i++) { - let rolenum = i + 1; - const selectedCharacter = positionSettings[i]; - if (!selectedCharacter) { - log.info(`未设置${rolenum}号位角色,跳过`); - continue; - } - const [x, y] = positionCoordinates[i]; - click(x, y); - log.info(`开始设置${rolenum}号位角色`); - await sleep(1000); - let characterFound = false; - let pageTries = 0; - - // 最多尝试滚动页面20次 - while (pageTries < 20) { - // 尝试识别所有可能的角色文件名 - for (let num = 1; ; num++) { - const paddedNum = num.toString().padStart(2, "0"); - const characterFileName = `${selectedCharacter}${paddedNum}`; - try { - const characterRo = RecognitionObject.TemplateMatch( - file.ReadImageMatSync(`Assets/characterimage/${characterFileName}.png`), - 0, - 0, - 1920, - 1080 - ); - const characterResult = captureGameRegion().find(characterRo); - if (characterResult.isExist()) { - log.info(`已找到角色${selectedCharacter}`); - // 计算向右偏移70像素、向下偏移70像素的位置 - const targetX = characterResult.x + 35; - const targetY = characterResult.y + 35; - - // 边界检查,确保坐标在屏幕范围内 - const safeX = Math.min(Math.max(targetX, 0), 1920); - const safeY = Math.min(Math.max(targetY, 0), 1080); - - click(safeX, safeY); - await sleep(500); // 点击角色后等待0.5秒 - characterFound = true; - break; - } - } catch (error) { - // 如果文件不存在,跳出循环 - break; - } - } - - if (characterFound) { - break; - } - - // 如果不是最后一次尝试,尝试滚动页面 - if (pageTries < 15) { - log.info("当前页面没有目标角色,滚动页面"); - await scrollPage(200); // 滚动距离可根据实际情况调整 - } - pageTries++; - } - - if (!characterFound) { - log.error(`未找到【${selectedCharacter}】`); - continue; - } - - // 识别"更换"或"加入"按钮 - const replaceResult = captureGameRegion().find(roReplace); - const joinResult = captureGameRegion().find(roJoin); - - if (replaceResult.isExist() || joinResult.isExist()) { - await sleep(300); - click(68, 1020); - keyPress("VK_LBUTTON"); - await sleep(500); - } else { - log.error(`该角色已在队伍中,无需切换`); - await sleep(300); - keyPress("VK_ESCAPE"); - await sleep(500); - } - await sleep(500); - } } else if (option === '存在bug-快速配对模式 @兩夢三醒') { - // 切换队伍 + // 切换队伍 if (!!settings.partyName) { try { log.info("正在尝试切换至" + settings.partyName); @@ -212,6 +256,9 @@ function readAliases() { await genshin.returnMainUi(); } + // 获取初始角色数组 + const initialAvatars = getAvatars(); + // 角色位置坐标 const positionCoordinates = [ [107, 190], @@ -224,25 +271,31 @@ function readAliases() { const aliases = readAliases(); // 获取需要切换的角色,并进行别名替换 - const positionSettings = [settings.position1, settings.position2, settings.position3, settings.position4].map(input => { - if (input && input.trim()!== "") { + const positionSettings = [settings.position1, settings.position2, settings.position3, settings.position4].map((input, index) => { + if (input && input.trim() !== "") { const actualName = aliases[input] || input; log.info(`设置对应号位为【${input}】,切换角色为【${actualName}】`); + // 替换初始数组对应位置 + initialAvatars[index] = actualName; return actualName; } return null; }); + // 目标角色数组(替换后的初始数组) + const targetAvatars = [...initialAvatars]; + log.info(`目标角色: [${targetAvatars}]`); + // 识别对象定义 const roTeamConfig = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`Assets/RecognitionObject/队伍配置.png`), 0, 0, 1920, 1080); - // const roReplace = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`Assets/RecognitionObject/更换.png`), 0, 0, 1920, 1080); - // const roJoin = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`Assets/RecognitionObject/加入.png`), 0, 0, 1920, 1080); let openPairingTries = 0; let totalOpenPairingTries = 0; + let retryCount = 0; // 重试计数器 + let switchSuccess = false; // 在进入角色切换逻辑前进行检测,如果所有角色设置均为空则直接退出 - if (positionSettings.every((item) =>!item)) { + if (positionSettings.every((item) => !item)) { log.info("未设置任何角色,跳过切换队伍步骤"); await genshin.returnMainUi(); return; @@ -271,130 +324,160 @@ function readAliases() { } } - if (!(await openPairingInterface())) { - return; - } - - // 需要取消选择的数量 - const ocrRegions = [ - [340, 181, 315, 330], - [655, 181, 315, 330], - [970, 181, 315, 330], - [1285, 181, 315, 330], - ]; - let regionsWithTextCount = 0; - let captureRegion = captureGameRegion(); - for (const [x, y, w, h] of ocrRegions) { - const regionOcrResult = captureRegion.findMulti(RecognitionObject.ocr(x, y, w, h)); - if (regionOcrResult.count > 0) { - regionsWithTextCount++; + // 角色切换逻辑封装 + async function switchCharacters() { + if (!(await openPairingInterface())) { + return false; } - } - log.info(`有文字的区域数量为: ${regionsWithTextCount}`); - // 角色切换逻辑 - click(1212, 1020); // 点击快速编队 - await sleep(1000); - log.info(`点击快速编队`); - for (let i = 0; i < regionsWithTextCount; i++) { - if (i >= positionCoordinates.length) { - break; - } - const [x, y] = positionCoordinates[i]; - click(x, y); - await sleep(1000); - log.info(`取消选择${x},${y}位置的角色`); - } - - for (let i = 0; i < positionSettings.length; i++) { - let rolenum = i + 1; - const selectedCharacter = positionSettings[i]; - const [x, y] = positionCoordinates[i]; - click(800, 123); - await sleep(1000); - if (!selectedCharacter) { - log.info(`未设置${rolenum}号位角色,保持原来的选择,可能存在未知bug`); - click(x, y); - await sleep(1000); - continue; - } - log.info(`开始设置${rolenum}号位角色`); - log.info(`目标角色为:【${selectedCharacter}】`); - - let characterFound = false; - let pageTries = 0; - - // 最多尝试滚动页面20×2次 - while (pageTries < 40) { - // 尝试识别所有可能的角色文件名 - for (let num = 1; ; num++) { - const paddedNum = num.toString().padStart(2, "0"); - const characterFileName = `${selectedCharacter}${paddedNum}`; - try { - const characterRo = RecognitionObject.TemplateMatch( - file.ReadImageMatSync(`Assets/characterimage/${characterFileName}.png`), - 0, - 0, - 1920, - 1080 - ); - const characterResult = captureGameRegion().find(characterRo); - if (characterResult.isExist()) { - log.info(`已找到角色【${selectedCharacter}】`); - // 计算向右偏移70像素、向下偏移70像素的位置 - const targetX = characterResult.x + 35; - const targetY = characterResult.y + 35; - - // 边界检查,确保坐标在屏幕范围内 - const safeX = Math.min(Math.max(targetX, 0), 1920); - const safeY = Math.min(Math.max(targetY, 0), 1080); - - click(safeX, safeY); - await sleep(500); // 点击角色后等待0.5秒 - characterFound = true; - break; - } - } catch (error) { - // 如果文件不存在,跳出循环 - break; - } + // 需要取消选择的数量 + const ocrRegions = [ + [340, 181, 315, 330], + [655, 181, 315, 330], + [970, 181, 315, 330], + [1285, 181, 315, 330], + ]; + let regionsWithTextCount = 0; + let captureRegion = captureGameRegion(); + for (const [x, y, w, h] of ocrRegions) { + const regionOcrResult = captureRegion.findMulti(RecognitionObject.ocr(x, y, w, h)); + if (regionOcrResult.count > 0) { + regionsWithTextCount++; } + } + log.info(`有文字的区域数量为: ${regionsWithTextCount}`); - if (characterFound) { + // 角色切换逻辑 + click(1212, 1020); // 点击快速编队 + await sleep(1000); + log.info(`点击快速编队`); + for (let i = 0; i < regionsWithTextCount; i++) { + if (i >= positionCoordinates.length) { break; } - - // 如果不是最后一次尝试,尝试滚动页面 - if (pageTries < 30) { - log.info(`当前页面没有目标角色【${selectedCharacter}】,滚动页面`); - await scrollPage(200); // 滚动距离可根据实际情况调整 - } - if (pageTries == 15) { - log.info("滚动完毕,重置位置,再试一次"); - click(800, 123); - await sleep(1000); - } - pageTries++; - } - - if (!characterFound) { - log.error(`未找到【${selectedCharacter}】,尝试选择原来的角色`); - click(800, 123); - await sleep(1000); + const [x, y] = positionCoordinates[i]; click(x, y); await sleep(1000); - continue; + log.info(`取消选择${x},${y}位置的角色`); + } + + for (let i = 0; i < positionSettings.length; i++) { + let rolenum = i + 1; + const selectedCharacter = positionSettings[i]; + const [x, y] = positionCoordinates[i]; + click(800, 123); + await sleep(1000); + if (!selectedCharacter) { + log.info(`未设置${rolenum}号位角色,保持原来的选择,可能存在未知bug`); + click(x, y); + await sleep(1000); + continue; + } + log.info(`开始设置${rolenum}号位角色`); + log.info(`目标角色为:【${selectedCharacter}】`); + + let characterFound = false; + let pageTries = 0; + + // 最多尝试滚动页面20×2次 + while (pageTries < 40) { + // 尝试识别所有可能的角色文件名 + for (let num = 1; ; num++) { + const paddedNum = num.toString().padStart(2, "0"); + const characterFileName = `${selectedCharacter}${paddedNum}`; + try { + const characterRo = RecognitionObject.TemplateMatch( + file.ReadImageMatSync(`Assets/characterimage/${characterFileName}.png`), + 0, 0, 1920, 1080 + ); + const characterResult = captureGameRegion().find(characterRo); + if (characterResult.isExist()) { + log.info(`已找到角色【${selectedCharacter}】`); + characterResult.click(); + await sleep(500); + characterFound = true; + break; + } + } catch (error) { + // 文件不存在,跳出循环 + break; + } + } + + if (characterFound) { + break; + } + + // 滚动页面 + if (pageTries < 30) { + log.info(`当前页面没有目标角色【${selectedCharacter}】,滚动页面`); + await scrollPage(200); + } + if (pageTries == 15) { + log.info("滚动完毕,重置位置,再试一次"); + click(800, 123); + await sleep(1000); + } + pageTries++; + } + + if (!characterFound) { + log.error(`未找到【${selectedCharacter}】,尝试选择原来的角色`); + click(800, 123); + await sleep(1000); + click(x, y); + await sleep(1000); + continue; + } + } + + // 点击保存 + click(427, 1024); + await sleep(1000); + keyPress("VK_LBUTTON"); + await sleep(500); + return true; + } + + // 执行切换并检查结果 + while (retryCount < 2) { // 最多尝试2次(初始1次+重试1次) + if (!await switchCharacters()) { + log.error("角色切换过程失败"); + return; + } + + // 返回主界面后获取最终角色数组 + await genshin.returnMainUi(); + const finalAvatars = getAvatars(); + + // 比较数组是否完全一致 + const arraysEqual = targetAvatars.length === finalAvatars.length && + targetAvatars.every((val, idx) => val === finalAvatars[idx]); + + if (arraysEqual) { + log.info("角色切换成功"); + switchSuccess = true; + break; + } else { + log.warn("角色不匹配,准备重试..."); + retryCount++; + if (retryCount >= 2) { + log.error("角色切换失败"); + return; + } + // 重新打开配对界面准备重试 + await genshin.returnMainUi(); } } - // 点击保存 - click(427, 1024); - await sleep(1000); - keyPress("VK_LBUTTON"); - await sleep(500); - } - // 返回主界面 - await genshin.returnMainUi(); - //清空角色缓存 - genshin.ClearPartyCache(); + if (!switchSuccess) { + log.error("角色切换失败"); + return; + } + } + + // 返回主界面 + await genshin.returnMainUi(); + // 清空角色缓存 + genshin.ClearPartyCache(); })(); \ No newline at end of file