diff --git a/repo/js/切换账号(OCR)版本/README.md b/archive/js/切换账号(OCR)版本/README.md similarity index 97% rename from repo/js/切换账号(OCR)版本/README.md rename to archive/js/切换账号(OCR)版本/README.md index f0d48ab5f..abbc7bcab 100644 --- a/repo/js/切换账号(OCR)版本/README.md +++ b/archive/js/切换账号(OCR)版本/README.md @@ -1,42 +1,42 @@ -# 自动切换账号脚本 - -**重要免责声明:** - -1. **数据安全:** - 1. 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。 - 2. 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用。 -2. **使用风险:** - 1. 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为。 - 2. 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任。 -3. **责任限制:** - 1. 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性。 - 2. 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。 -4. **禁止条款:** - 1. 严禁逆向工程、恶意篡改或用于外挂等非法用途。 - 2. 若游戏运营商提出要求,开发者保留随时停止维护的权利。 - -使用脚本即表示您已阅读并同意上述条款。 - -如果使用BGI一条龙启动,且第一个脚本就是账号切换,则需要开启BGI启动配置-同时启动原神-自动进入游戏 - -根据使用者设备配置和网络环境,脚本中的延时可以适当调整。(如果不熟悉脚本操作则不建议修改延时) - -作者留言: -毕竟都使用BGI了,时间还算个事吗?(笑) - -需要国际服适配脚本私信我。 - -**Last Updated:** 2025-06-26 - ---- -# 脚本信息 - @name 原神自动化登录脚本 - @version 1.2 - @description 原神自动登录工具(仅供学习交流,请勿商业用途) - @author 彩虹QQ人 - @match 原神版本:≥5.5;BGI版本:≥0.44.6 - - # 更新记录 -2025年6月26日 version 1.1 整合代码 - -2025年6月27日 version 1.2 解决循环无法跳出的问题 +# 自动切换账号脚本 + +**重要免责声明:** + +1. **数据安全:** + 1. 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。 + 2. 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用。 +2. **使用风险:** + 1. 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为。 + 2. 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任。 +3. **责任限制:** + 1. 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性。 + 2. 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。 +4. **禁止条款:** + 1. 严禁逆向工程、恶意篡改或用于外挂等非法用途。 + 2. 若游戏运营商提出要求,开发者保留随时停止维护的权利。 + +使用脚本即表示您已阅读并同意上述条款。 + +如果使用BGI一条龙启动,且第一个脚本就是账号切换,则需要开启BGI启动配置-同时启动原神-自动进入游戏 + +根据使用者设备配置和网络环境,脚本中的延时可以适当调整。(如果不熟悉脚本操作则不建议修改延时) + +作者留言: +毕竟都使用BGI了,时间还算个事吗?(笑) + +需要国际服适配脚本私信我。 + +**Last Updated:** 2025-06-26 + +--- +# 脚本信息 + @name 原神自动化登录脚本 + @version 1.2 + @description 原神自动登录工具(仅供学习交流,请勿商业用途) + @author 彩虹QQ人 + @match 原神版本:≥5.5;BGI版本:≥0.44.6 + + # 更新记录 +2025年6月26日 version 1.1 整合代码 + +2025年6月27日 version 1.2 解决循环无法跳出的问题 diff --git a/repo/js/切换账号(OCR)版本/assets/agree.png b/archive/js/切换账号(OCR)版本/assets/agree.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/agree.png rename to archive/js/切换账号(OCR)版本/assets/agree.png diff --git a/repo/js/切换账号(OCR)版本/assets/click_into.png b/archive/js/切换账号(OCR)版本/assets/click_into.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/click_into.png rename to archive/js/切换账号(OCR)版本/assets/click_into.png diff --git a/repo/js/切换账号(OCR)版本/assets/input_password.png b/archive/js/切换账号(OCR)版本/assets/input_password.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/input_password.png rename to archive/js/切换账号(OCR)版本/assets/input_password.png diff --git a/repo/js/切换账号(OCR)版本/assets/input_phone_or_email.png b/archive/js/切换账号(OCR)版本/assets/input_phone_or_email.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/input_phone_or_email.png rename to archive/js/切换账号(OCR)版本/assets/input_phone_or_email.png diff --git a/repo/js/切换账号(OCR)版本/assets/login_other_account.png b/archive/js/切换账号(OCR)版本/assets/login_other_account.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/login_other_account.png rename to archive/js/切换账号(OCR)版本/assets/login_other_account.png diff --git a/repo/js/切换账号(OCR)版本/assets/login_other_account_1.png b/archive/js/切换账号(OCR)版本/assets/login_other_account_1.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/login_other_account_1.png rename to archive/js/切换账号(OCR)版本/assets/login_other_account_1.png diff --git a/repo/js/切换账号(OCR)版本/assets/login_out_account.png b/archive/js/切换账号(OCR)版本/assets/login_out_account.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/login_out_account.png rename to archive/js/切换账号(OCR)版本/assets/login_out_account.png diff --git a/repo/js/切换账号(OCR)版本/assets/out_account.png b/archive/js/切换账号(OCR)版本/assets/out_account.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/out_account.png rename to archive/js/切换账号(OCR)版本/assets/out_account.png diff --git a/repo/js/切换账号(OCR)版本/assets/out_to_login.png b/archive/js/切换账号(OCR)版本/assets/out_to_login.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/out_to_login.png rename to archive/js/切换账号(OCR)版本/assets/out_to_login.png diff --git a/repo/js/切换账号(OCR)版本/assets/pm_menu.png b/archive/js/切换账号(OCR)版本/assets/pm_menu.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/pm_menu.png rename to archive/js/切换账号(OCR)版本/assets/pm_menu.png diff --git a/repo/js/切换账号(OCR)版本/assets/pm_out.png b/archive/js/切换账号(OCR)版本/assets/pm_out.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/pm_out.png rename to archive/js/切换账号(OCR)版本/assets/pm_out.png diff --git a/repo/js/切换账号(OCR)版本/assets/verification.png b/archive/js/切换账号(OCR)版本/assets/verification.png similarity index 100% rename from repo/js/切换账号(OCR)版本/assets/verification.png rename to archive/js/切换账号(OCR)版本/assets/verification.png diff --git a/repo/js/切换账号(OCR)版本/main.js b/archive/js/切换账号(OCR)版本/main.js similarity index 97% rename from repo/js/切换账号(OCR)版本/main.js rename to archive/js/切换账号(OCR)版本/main.js index 2cc2faa9f..2f0cfdca0 100644 --- a/repo/js/切换账号(OCR)版本/main.js +++ b/archive/js/切换账号(OCR)版本/main.js @@ -1,201 +1,201 @@ -const author = "彩虹QQ人"; -const script_name = "切换账号(OCR)版本"; - -const pm_out = { - template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/pm_out.png")), - name: "pm_out.png" -}; -const out_to_login = { - template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/out_to_login.png")), - name: "out_to_login.png" -}; -const login_out_account = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/login_out_account.png")), - name: "login_out_account.png" -}; -const out_account = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/out_account.png")), - name: "out_account.png" -}; -const login_other_account = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/login_other_account_1.png")), - name: "login_other_account.png" -}; -const input_phone_or_email = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/input_phone_or_email.png")), - name: "input_phone_or_email.png" -}; -const input_password = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/input_password.png")), - name: "input_password.png" -}; -const agree = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/agree.png")), - name: "agree.png" -}; -//人机验证识别图片 -const login_verification = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/verification.png")), - name: "verification.png" -}; - -async function clickCenter(x, y, width, height) { - let centerX = Math.round(x + width / 2); - let centerY = Math.round(y + height / 2); - await click(centerX, centerY); - await sleep(500); // 确保点击后有足够的时间等待 - return { success: true, x: centerX, y: centerY }; -} - -async function matchImgAndClick(obj, desc, timeout = 8000) { - const start = Date.now(); - let retryCount = 0; // 识别次数计数 - let status = false; // 用于记录是否匹配成功 - try { - while (Date.now() - start < timeout && !status) { - await sleep(300); - const ro = captureGameRegion(); - let result = ro.Find(obj.template); - ro.dispose(); - await sleep(500); // 短暂延迟,避免过快循环 - if (result.isExist()) { - let clickResult = await clickCenter(result.x, result.y, result.width, result.height); - log.info(`【IMG】成功识别并点击 ${desc}| 耗时: ${Date.now() - start}ms`); - status = true; // 设置匹配成功状态 - return {success: true, x: clickResult.x, y: clickResult.y}; - } - // await sleep(200); // 短暂延迟,避免过快循环 - log.info(`【IMG】第${retryCount++}次识别并点击 ${desc} 失败 | 耗时: ${Date.now() - start}ms`); - } - } catch (error) { - log.error(`【IMG】${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); - //如果有配置通知…… - notification.error(`【IMG】${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); - throw new Error(`【IMG】识别图像时发生异常: ${error.message}`); - } - return {success: false}; -} -async function recognizeTextAndClick(targetText, ocrRegion, timeout = 8000) { - let start = Date.now(); - let retryCount = 0; // 重试计数 - let status = false; // 用于记录是否匹配成功 - try { - while (Date.now() - start < timeout && !status) { - const ro = captureGameRegion(); - let resultList = ro.findMulti(ocrRegion); - ro.dispose(); - await sleep(500); // 短暂延迟,避免过快循环 - for (let result of resultList) { - if (result.text.includes(targetText)) { - let clickResult = await clickCenter(result.x, result.y, result.width, result.height); - log.info(`【OCR】成功识别并点击 ${targetText}| 耗时: ${Date.now() - start}ms`); - status = true; // 设置匹配成功状态 - return {success: true, x: clickResult.x, y: clickResult.y}; - } - } - // await sleep(200); // 短暂延迟,避免过快循环 - log.info(`【OCR】${targetText}失败,正在进行第 ${retryCount++} 次重试...`); - } - }catch (error) { - log.warn(`【OCR】经过多次尝试,仍然无法识别文字: ”${targetText}“,尝试点击默认中心位置`); - await clickCenter(result.x, result.y, result.width, result.height); - //如果有配置通知…… - notification.error(`【OCR】识别文字: “${targetText}”,发生异常`); - throw new Error(`【OCR】识别文字时发生异常: ${error.message}`); - } - return {success: false }; -} -/** - * main流程开始 - */ -(async function () { - - setGameMetrics(1920, 1080, 1); - // 如果切换账号是第一个脚本,则有可能出现月卡选项 - //防止genshin.blessingOfTheWelkinMoon();方法失效,先使用物理点击。 - try { - keyDown("VK_MENU"); - await sleep(500); - for(let i = 0; i<=4; i++){ - await click(genshin.width / 2.0, genshin.height * 0.8); - await sleep(1000); - } - }finally { - keyUp("VK_MENU"); - } - //await genshin.blessingOfTheWelkinMoon(); - //await sleep(1000); - //await genshin.blessingOfTheWelkinMoon(); - //await sleep(1000); - await genshin.returnMainUi(); - - await keyPress("VK_ESCAPE"); - await sleep(500); - try { - await matchImgAndClick(pm_out,"左下角退出门"); - await matchImgAndClick(out_to_login,"退出至登陆页面"); - //这一步根据 电脑配置和当前网络情况不同休眠时间不同,建议实际运行之后,如果有日志 : 第x次 识别失败,就适当增加休眠时间 - await sleep(9000); - await matchImgAndClick(login_out_account,"登录页的右下角退出按钮"); - await matchImgAndClick(out_account,"退出当前账号"); - await matchImgAndClick(login_other_account,"登录其他账号"); - await sleep(1000); - await matchImgAndClick(input_phone_or_email,"填写邮箱/手机号"); - await inputText(settings.username); - await sleep(1000); - await matchImgAndClick(input_password,"填写密码"); - await inputText(settings.password); - await sleep(1000); - //按下回车登录账号,弹出用户协议对话框 - await keyPress("VK_RETURN"); - //点击回车后,等待特瓦特大门加载 - await matchImgAndClick(agree,"同意用户协议"); - //如果当天上下线次数过于频繁 - for(let i = 1;i<=2;i++){ - const ro = captureGameRegion(); - let verify = ro.Find(login_verification.template); - ro.dispose(); - //等待1s避免循环速度过快 - await sleep(1000); - if (verify.isExist()) { - //这里可配置通知方法 - notification.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); - log.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); - } - } - /** - * 根据不同网络环境和电脑配置,此操作可能会将领取月卡操作取代,但是不影响使用 - * 如果发现卡在这一步,请适当延长sleep时间 - */ - await sleep(8000); - await recognizeTextAndClick("点击进入", RecognitionObject.Ocr(862, 966, 206, 104), 960, 540, 5000); - await sleep(15000); - - //可能登录账号的时候出现月卡提醒,则先点击一次月卡。 - //await genshin.blessingOfTheWelkinMoon(); - //await sleep(1000); - //await genshin.blessingOfTheWelkinMoon(); - //await sleep(1000); - //防止genshin.blessingOfTheWelkinMoon();方法失效,先使用物理点击。 - await sleep(2000); - keyDown("VK_MENU"); - await sleep(500); - for(let i = 0; i<=4; i++){ - await click(genshin.width / 2.0, genshin.height * 0.8); - await sleep(1000); - } - //keyUp("VK_MENU"); - await genshin.returnMainUi(); - await sleep(1000); - // 如果配置了通知 - notification.send("账号【" + settings.UID + "】切换成功"); - }catch (error) { - log.error(`${script_name}脚本执行过程中发生错误:${error.message}`); - //如果发生错误,则发送通知 - notification.error(`${script_name}脚本执行过程中发生错误:${error.message}`); - throw new Error(`${script_name}脚本执行过程中发生错误:${error.message}`); - }finally { - keyUp("VK_MENU"); - } - +const author = "彩虹QQ人"; +const script_name = "切换账号(OCR)版本"; + +const pm_out = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/pm_out.png")), + name: "pm_out.png" +}; +const out_to_login = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/out_to_login.png")), + name: "out_to_login.png" +}; +const login_out_account = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/login_out_account.png")), + name: "login_out_account.png" +}; +const out_account = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/out_account.png")), + name: "out_account.png" +}; +const login_other_account = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/login_other_account_1.png")), + name: "login_other_account.png" +}; +const input_phone_or_email = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/input_phone_or_email.png")), + name: "input_phone_or_email.png" +}; +const input_password = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/input_password.png")), + name: "input_password.png" +}; +const agree = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/agree.png")), + name: "agree.png" +}; +//人机验证识别图片 +const login_verification = { + template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/verification.png")), + name: "verification.png" +}; + +async function clickCenter(x, y, width, height) { + let centerX = Math.round(x + width / 2); + let centerY = Math.round(y + height / 2); + await click(centerX, centerY); + await sleep(500); // 确保点击后有足够的时间等待 + return { success: true, x: centerX, y: centerY }; +} + +async function matchImgAndClick(obj, desc, timeout = 8000) { + const start = Date.now(); + let retryCount = 0; // 识别次数计数 + let status = false; // 用于记录是否匹配成功 + try { + while (Date.now() - start < timeout && !status) { + await sleep(300); + const ro = captureGameRegion(); + let result = ro.Find(obj.template); + ro.dispose(); + await sleep(500); // 短暂延迟,避免过快循环 + if (result.isExist()) { + let clickResult = await clickCenter(result.x, result.y, result.width, result.height); + log.info(`【IMG】成功识别并点击 ${desc}| 耗时: ${Date.now() - start}ms`); + status = true; // 设置匹配成功状态 + return {success: true, x: clickResult.x, y: clickResult.y}; + } + // await sleep(200); // 短暂延迟,避免过快循环 + log.info(`【IMG】第${retryCount++}次识别并点击 ${desc} 失败 | 耗时: ${Date.now() - start}ms`); + } + } catch (error) { + log.error(`【IMG】${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); + //如果有配置通知…… + notification.error(`【IMG】${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); + throw new Error(`【IMG】识别图像时发生异常: ${error.message}`); + } + return {success: false}; +} +async function recognizeTextAndClick(targetText, ocrRegion, timeout = 8000) { + let start = Date.now(); + let retryCount = 0; // 重试计数 + let status = false; // 用于记录是否匹配成功 + try { + while (Date.now() - start < timeout && !status) { + const ro = captureGameRegion(); + let resultList = ro.findMulti(ocrRegion); + ro.dispose(); + await sleep(500); // 短暂延迟,避免过快循环 + for (let result of resultList) { + if (result.text.includes(targetText)) { + let clickResult = await clickCenter(result.x, result.y, result.width, result.height); + log.info(`【OCR】成功识别并点击 ${targetText}| 耗时: ${Date.now() - start}ms`); + status = true; // 设置匹配成功状态 + return {success: true, x: clickResult.x, y: clickResult.y}; + } + } + // await sleep(200); // 短暂延迟,避免过快循环 + log.info(`【OCR】${targetText}失败,正在进行第 ${retryCount++} 次重试...`); + } + }catch (error) { + log.warn(`【OCR】经过多次尝试,仍然无法识别文字: ”${targetText}“,尝试点击默认中心位置`); + await clickCenter(result.x, result.y, result.width, result.height); + //如果有配置通知…… + notification.error(`【OCR】识别文字: “${targetText}”,发生异常`); + throw new Error(`【OCR】识别文字时发生异常: ${error.message}`); + } + return {success: false }; +} +/** + * main流程开始 + */ +(async function () { + + setGameMetrics(1920, 1080, 1); + // 如果切换账号是第一个脚本,则有可能出现月卡选项 + //防止genshin.blessingOfTheWelkinMoon();方法失效,先使用物理点击。 + try { + keyDown("VK_MENU"); + await sleep(500); + for(let i = 0; i<=4; i++){ + await click(genshin.width / 2.0, genshin.height * 0.8); + await sleep(1000); + } + }finally { + keyUp("VK_MENU"); + } + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + await genshin.returnMainUi(); + + await keyPress("VK_ESCAPE"); + await sleep(500); + try { + await matchImgAndClick(pm_out,"左下角退出门"); + await matchImgAndClick(out_to_login,"退出至登陆页面"); + //这一步根据 电脑配置和当前网络情况不同休眠时间不同,建议实际运行之后,如果有日志 : 第x次 识别失败,就适当增加休眠时间 + await sleep(9000); + await matchImgAndClick(login_out_account,"登录页的右下角退出按钮"); + await matchImgAndClick(out_account,"退出当前账号"); + await matchImgAndClick(login_other_account,"登录其他账号"); + await sleep(1000); + await matchImgAndClick(input_phone_or_email,"填写邮箱/手机号"); + await inputText(settings.username); + await sleep(1000); + await matchImgAndClick(input_password,"填写密码"); + await inputText(settings.password); + await sleep(1000); + //按下回车登录账号,弹出用户协议对话框 + await keyPress("VK_RETURN"); + //点击回车后,等待特瓦特大门加载 + await matchImgAndClick(agree,"同意用户协议"); + //如果当天上下线次数过于频繁 + for(let i = 1;i<=2;i++){ + const ro = captureGameRegion(); + let verify = ro.Find(login_verification.template); + ro.dispose(); + //等待1s避免循环速度过快 + await sleep(1000); + if (verify.isExist()) { + //这里可配置通知方法 + notification.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); + log.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); + } + } + /** + * 根据不同网络环境和电脑配置,此操作可能会将领取月卡操作取代,但是不影响使用 + * 如果发现卡在这一步,请适当延长sleep时间 + */ + await sleep(8000); + await recognizeTextAndClick("点击进入", RecognitionObject.Ocr(862, 966, 206, 104), 960, 540, 5000); + await sleep(15000); + + //可能登录账号的时候出现月卡提醒,则先点击一次月卡。 + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + //防止genshin.blessingOfTheWelkinMoon();方法失效,先使用物理点击。 + await sleep(2000); + keyDown("VK_MENU"); + await sleep(500); + for(let i = 0; i<=4; i++){ + await click(genshin.width / 2.0, genshin.height * 0.8); + await sleep(1000); + } + //keyUp("VK_MENU"); + await genshin.returnMainUi(); + await sleep(1000); + // 如果配置了通知 + notification.send("账号【" + settings.UID + "】切换成功"); + }catch (error) { + log.error(`${script_name}脚本执行过程中发生错误:${error.message}`); + //如果发生错误,则发送通知 + notification.error(`${script_name}脚本执行过程中发生错误:${error.message}`); + throw new Error(`${script_name}脚本执行过程中发生错误:${error.message}`); + }finally { + keyUp("VK_MENU"); + } + })(); \ No newline at end of file diff --git a/repo/js/切换账号(OCR)版本/manifest.json b/archive/js/切换账号(OCR)版本/manifest.json similarity index 97% rename from repo/js/切换账号(OCR)版本/manifest.json rename to archive/js/切换账号(OCR)版本/manifest.json index 53f961f90..472b7b8b0 100644 --- a/repo/js/切换账号(OCR)版本/manifest.json +++ b/archive/js/切换账号(OCR)版本/manifest.json @@ -1,19 +1,19 @@ -{ - "manifest_version": 1, - "name": "切换账号(OCR)版本", - "version": "1.3", - "description": "使用OCR实现:从主页面退出登录实现切换选定账号。脚本维护/脚本问题请联系作者。\n免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。若因使用此脚本导致的账号泄露、封禁问题与脚本作者无关。", - "tags": [ - "切换账号", - "OCR" - ], - "authors": [ - { - "name": "彩虹QQ人", - "email": "846224811@qq.com", - "links": "https://github.com/KRdingsan" - } - ], - "settings_ui": "settings.json", - "main": "main.js" +{ + "manifest_version": 1, + "name": "切换账号(OCR)版本", + "version": "1.3", + "description": "使用OCR实现:从主页面退出登录实现切换选定账号。脚本维护/脚本问题请联系作者。\n免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。若因使用此脚本导致的账号泄露、封禁问题与脚本作者无关。", + "tags": [ + "切换账号", + "OCR" + ], + "authors": [ + { + "name": "彩虹QQ人", + "email": "846224811@qq.com", + "links": "https://github.com/KRdingsan" + } + ], + "settings_ui": "settings.json", + "main": "main.js" } \ No newline at end of file diff --git a/repo/js/切换账号(OCR)版本/settings.json b/archive/js/切换账号(OCR)版本/settings.json similarity index 95% rename from repo/js/切换账号(OCR)版本/settings.json rename to archive/js/切换账号(OCR)版本/settings.json index 2357498a0..3cb60e644 100644 --- a/repo/js/切换账号(OCR)版本/settings.json +++ b/archive/js/切换账号(OCR)版本/settings.json @@ -1,13 +1,13 @@ -[ - { - "name": "username", - "type": "input-text", - "label": "账号(账号只保存在本地,请妥善保管)" - }, - { - "name": "password", - "type": "input-text", - "label": "密码(账号只保存在本地,请妥善保管)" - } - -] +[ + { + "name": "username", + "type": "input-text", + "label": "账号(账号只保存在本地,请妥善保管)" + }, + { + "name": "password", + "type": "input-text", + "label": "密码(账号只保存在本地,请妥善保管)" + } + +] diff --git a/repo/js/切换账号(非OCR)版本/README.md b/archive/js/切换账号(非OCR)版本/README.md similarity index 100% rename from repo/js/切换账号(非OCR)版本/README.md rename to archive/js/切换账号(非OCR)版本/README.md diff --git a/repo/js/切换账号(非OCR)版本/main.js b/archive/js/切换账号(非OCR)版本/main.js similarity index 96% rename from repo/js/切换账号(非OCR)版本/main.js rename to archive/js/切换账号(非OCR)版本/main.js index 4890f0947..362f9da3e 100644 --- a/repo/js/切换账号(非OCR)版本/main.js +++ b/archive/js/切换账号(非OCR)版本/main.js @@ -1,64 +1,64 @@ -(async function () { - /** - * 不使用屏幕识别的登出至其他账号的脚本 - * 版本: - * 原神:5.5 - * BIG:0.44.6 - */ - //实测缩放倍数1.0、1.5可行,实测凡16:9(大于1920*1080)均能正常使用。 - setGameMetrics(1920, 1080, 2.0); - //到达主页面 - await genshin.returnMainUi(); - await sleep(1000); - //打开派蒙页面 - keyPress("VK_ESCAPE"); - await sleep(1000); - click(50, 1030); - //退出门图标 - await sleep(1000); - //退出至登录页面 - click(978, 540); - await sleep(10000); - //登录页面退出当前账号的小门图标 - click(1828, 985); - await sleep(1000); - //勾选:退出并保留登录记录 - click(701, 573); - await sleep(1000); - //点击退出大按钮 - click(1107, 684); - await sleep(1000); - //登录其他账号 - click(946, 703); - await sleep(1000); - //点击用户名输入框 - click(815, 400); - //如果有文本,清除 - await keyPress("VK_DELETE"); - // 输入文本 - await inputText(settings.username); - await sleep(500); - //点击密码输入框 - click(815, 480); - //如果有文本,清除 - await keyPress("VK_DELETE"); - // 输入文本 - await inputText(settings.password); - await sleep(500); - //登录 - keyPress("VK_RETURN"); - await sleep(500); - //用户协议弹窗,点击同意,等待8.5s,增加容错 - click(1093, 593); - await sleep(8500); - //进入世界循环点击,增加容错 - for(let i = 3;i>0;i--){ - click(960, 540); - await sleep(1500); - } - //确保进入主页面 - await sleep(12000); - //点击领月卡 - await genshin.blessingOfTheWelkinMoon(); - +(async function () { + /** + * 不使用屏幕识别的登出至其他账号的脚本 + * 版本: + * 原神:5.5 + * BIG:0.44.6 + */ + //实测缩放倍数1.0、1.5可行,实测凡16:9(大于1920*1080)均能正常使用。 + setGameMetrics(1920, 1080, 2.0); + //到达主页面 + await genshin.returnMainUi(); + await sleep(1000); + //打开派蒙页面 + keyPress("VK_ESCAPE"); + await sleep(1000); + click(50, 1030); + //退出门图标 + await sleep(1000); + //退出至登录页面 + click(978, 540); + await sleep(10000); + //登录页面退出当前账号的小门图标 + click(1828, 985); + await sleep(1000); + //勾选:退出并保留登录记录 + click(701, 573); + await sleep(1000); + //点击退出大按钮 + click(1107, 684); + await sleep(1000); + //登录其他账号 + click(946, 703); + await sleep(1000); + //点击用户名输入框 + click(815, 400); + //如果有文本,清除 + await keyPress("VK_DELETE"); + // 输入文本 + await inputText(settings.username); + await sleep(500); + //点击密码输入框 + click(815, 480); + //如果有文本,清除 + await keyPress("VK_DELETE"); + // 输入文本 + await inputText(settings.password); + await sleep(500); + //登录 + keyPress("VK_RETURN"); + await sleep(500); + //用户协议弹窗,点击同意,等待8.5s,增加容错 + click(1093, 593); + await sleep(8500); + //进入世界循环点击,增加容错 + for(let i = 3;i>0;i--){ + click(960, 540); + await sleep(1500); + } + //确保进入主页面 + await sleep(12000); + //点击领月卡 + await genshin.blessingOfTheWelkinMoon(); + })(); \ No newline at end of file diff --git a/repo/js/切换账号(非OCR)版本/manifest.json b/archive/js/切换账号(非OCR)版本/manifest.json similarity index 96% rename from repo/js/切换账号(非OCR)版本/manifest.json rename to archive/js/切换账号(非OCR)版本/manifest.json index 8b399186c..20eccb6c3 100644 --- a/repo/js/切换账号(非OCR)版本/manifest.json +++ b/archive/js/切换账号(非OCR)版本/manifest.json @@ -1,19 +1,19 @@ -{ - "manifest_version": 1, - "name": "切换账号(非OCR方案)", - "version": "1.0", - "description": "从主页面退出登录实现切换选定账号。\n脚本问题请联系作者。\n免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。\n", - "tags": [ - "切换账号", - "坐标点击" - ], - "authors": [ - { - "name": "彩虹QQ人", - "email": "846224811@qq.com", - "links": "https://github.com/KRdingsan" - } - ], - "settings_ui": "settings.json", - "main": "main.js" +{ + "manifest_version": 1, + "name": "切换账号(非OCR方案)", + "version": "1.0", + "description": "从主页面退出登录实现切换选定账号。\n脚本问题请联系作者。\n免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。\n", + "tags": [ + "切换账号", + "坐标点击" + ], + "authors": [ + { + "name": "彩虹QQ人", + "email": "846224811@qq.com", + "links": "https://github.com/KRdingsan" + } + ], + "settings_ui": "settings.json", + "main": "main.js" } \ No newline at end of file diff --git a/repo/js/切换账号(非OCR)版本/settings.json b/archive/js/切换账号(非OCR)版本/settings.json similarity index 94% rename from repo/js/切换账号(非OCR)版本/settings.json rename to archive/js/切换账号(非OCR)版本/settings.json index 1e56970bc..f26474621 100644 --- a/repo/js/切换账号(非OCR)版本/settings.json +++ b/archive/js/切换账号(非OCR)版本/settings.json @@ -1,13 +1,13 @@ -[ - { - "name": "username", - "type": "input-text", - "label": "账号(账号只保存在本地)" - }, - { - "name": "password", - "type": "input-text", - "label": "密码(账号只保存在本地)" - } - -] +[ + { + "name": "username", + "type": "input-text", + "label": "账号(账号只保存在本地)" + }, + { + "name": "password", + "type": "input-text", + "label": "密码(账号只保存在本地)" + } + +] diff --git a/repo/js/切换账号Dropdown/README.md b/archive/js/切换账号Dropdown/README.md similarity index 100% rename from repo/js/切换账号Dropdown/README.md rename to archive/js/切换账号Dropdown/README.md diff --git a/repo/js/切换账号Dropdown/assets/caret.png b/archive/js/切换账号Dropdown/assets/caret.png similarity index 100% rename from repo/js/切换账号Dropdown/assets/caret.png rename to archive/js/切换账号Dropdown/assets/caret.png diff --git a/repo/js/切换账号Dropdown/assets/logout.png b/archive/js/切换账号Dropdown/assets/logout.png similarity index 100% rename from repo/js/切换账号Dropdown/assets/logout.png rename to archive/js/切换账号Dropdown/assets/logout.png diff --git a/repo/js/切换账号Dropdown/assets/paimon_cancel.png b/archive/js/切换账号Dropdown/assets/paimon_cancel.png similarity index 100% rename from repo/js/切换账号Dropdown/assets/paimon_cancel.png rename to archive/js/切换账号Dropdown/assets/paimon_cancel.png diff --git a/repo/js/切换账号Dropdown/assets/paimon_menu.png b/archive/js/切换账号Dropdown/assets/paimon_menu.png similarity index 100% rename from repo/js/切换账号Dropdown/assets/paimon_menu.png rename to archive/js/切换账号Dropdown/assets/paimon_menu.png diff --git a/repo/js/切换账号Dropdown/assets/quit.png b/archive/js/切换账号Dropdown/assets/quit.png similarity index 100% rename from repo/js/切换账号Dropdown/assets/quit.png rename to archive/js/切换账号Dropdown/assets/quit.png diff --git a/repo/js/切换账号Dropdown/main.js b/archive/js/切换账号Dropdown/main.js similarity index 100% rename from repo/js/切换账号Dropdown/main.js rename to archive/js/切换账号Dropdown/main.js diff --git a/repo/js/切换账号Dropdown/manifest.json b/archive/js/切换账号Dropdown/manifest.json similarity index 100% rename from repo/js/切换账号Dropdown/manifest.json rename to archive/js/切换账号Dropdown/manifest.json diff --git a/repo/js/切换账号Dropdown/settings.json b/archive/js/切换账号Dropdown/settings.json similarity index 100% rename from repo/js/切换账号Dropdown/settings.json rename to archive/js/切换账号Dropdown/settings.json diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/agree.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/agree.png new file mode 100644 index 000000000..04d02d66f Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/agree.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/caret.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/caret.png new file mode 100644 index 000000000..3bb837eb0 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/caret.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/click_into.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/click_into.png new file mode 100644 index 000000000..b99a56d08 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/click_into.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/input_password.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/input_password.png new file mode 100644 index 000000000..8f82c32f9 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/input_password.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/input_phone_or_email.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/input_phone_or_email.png new file mode 100644 index 000000000..638230a5a Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/input_phone_or_email.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_other_account.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_other_account.png new file mode 100644 index 000000000..48a78f1ca Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_other_account.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_other_account_1.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_other_account_1.png new file mode 100644 index 000000000..299b31389 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_other_account_1.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_out_account.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_out_account.png new file mode 100644 index 000000000..7efbff243 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/login_out_account.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/logout.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/logout.png new file mode 100644 index 000000000..99cc210ea Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/logout.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/out_account.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/out_account.png new file mode 100644 index 000000000..4e25371ca Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/out_account.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/out_to_login.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/out_to_login.png new file mode 100644 index 000000000..4c863424a Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/out_to_login.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/paimon_cancel.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/paimon_cancel.png new file mode 100644 index 000000000..2bffc12fb Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/paimon_cancel.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/paimon_menu.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/paimon_menu.png new file mode 100644 index 000000000..c424325b1 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/paimon_menu.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/pm_menu.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/pm_menu.png new file mode 100644 index 000000000..f1c7a3855 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/pm_menu.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/pm_out.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/pm_out.png new file mode 100644 index 000000000..df31ebd6f Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/pm_out.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/quit.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/quit.png new file mode 100644 index 000000000..1d11fa5a3 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/quit.png differ diff --git a/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/verification.png b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/verification.png new file mode 100644 index 000000000..939b7a9d9 Binary files /dev/null and b/repo/js/SwitchAccountMultipleMode/Assets/RecognitionObject/verification.png differ diff --git a/repo/js/SwitchAccountMultipleMode/README.md b/repo/js/SwitchAccountMultipleMode/README.md new file mode 100644 index 000000000..7c784f2bc --- /dev/null +++ b/repo/js/SwitchAccountMultipleMode/README.md @@ -0,0 +1,35 @@ +# 下拉列表模式 + +## 使用前准备 + +确保你想要切换的账号是已登录状态,且账号选择列表中存在。 + +## 使用方式 + +1. 把此脚本添加到配置组 +2. 右键点击选择"修改JS脚本自定义配置" +3. 填入你想登录的账户名称,该名称必须和账号列表中显示的一致 + - 请确认你此次登录使用的是手机号还是邮箱 + +# 账号+密码 / 账号+密码+OCR模式 + +**重要免责声明:** + +1. **数据安全:** + 1. 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。 + 2. 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用。 +2. **使用风险:** + 1. 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为。 + 2. 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任。 +3. **责任限制:** + 1. 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性。 + 2. 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。 +4. **禁止条款:** + 1. 严禁逆向工程、恶意篡改或用于外挂等非法用途。 + 2. 若游戏运营商提出要求,开发者保留随时停止维护的权利。 + +使用脚本即表示您已阅读并同意上述条款。 + +如果使用BGI一条龙启动,且第一个脚本就是账号切换,则需要开启BGI启动配置-同时启动原神-自动进入游戏 + +根据使用者设备配置和网络环境,脚本中的延时可以适当调整。(如果不熟悉脚本操作则不建议修改延时) \ No newline at end of file diff --git a/repo/js/SwitchAccountMultipleMode/main.js b/repo/js/SwitchAccountMultipleMode/main.js new file mode 100644 index 000000000..614bffbb2 --- /dev/null +++ b/repo/js/SwitchAccountMultipleMode/main.js @@ -0,0 +1,604 @@ +// ====================================================== +// 切换账号(OCR)版本 +const author = "彩虹QQ人"; +const script_name = "切换账号(OCR)版本"; + +const pm_out = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/pm_out.png")), + name: "pm_out.png" +}; +const out_to_login = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/out_to_login.png")), + name: "out_to_login.png" +}; +const login_out_account = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/login_out_account.png")), + name: "login_out_account.png" +}; +const out_account = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/out_account.png")), + name: "out_account.png" +}; +const login_other_account = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/login_other_account_1.png")), + name: "login_other_account.png" +}; +const input_phone_or_email = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/input_phone_or_email.png")), + name: "input_phone_or_email.png" +}; +const input_password = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/input_password.png")), + name: "input_password.png" +}; +const agree = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/agree.png")), + name: "agree.png" +}; +//人机验证识别图片 +const login_verification = { + template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/verification.png")), + name: "verification.png" +}; + +async function clickCenter(x, y, width, height) { + let centerX = Math.round(x + width / 2); + let centerY = Math.round(y + height / 2); + await click(centerX, centerY); + await sleep(500); // 确保点击后有足够的时间等待 + return { success: true, x: centerX, y: centerY }; +} + +async function matchImgAndClick(obj, desc, timeout = 8000) { + const start = Date.now(); + let retryCount = 0; // 识别次数计数 + let status = false; // 用于记录是否匹配成功 + try { + while (Date.now() - start < timeout && !status) { + await sleep(300); + const ro = captureGameRegion(); + let result = ro.Find(obj.template); + ro.dispose(); + await sleep(500); // 短暂延迟,避免过快循环 + if (result.isExist()) { + let clickResult = await clickCenter(result.x, result.y, result.width, result.height); + log.info(`【IMG】成功识别并点击 ${desc}| 耗时: ${Date.now() - start}ms`); + status = true; // 设置匹配成功状态 + return { success: true, x: clickResult.x, y: clickResult.y }; + } + // await sleep(200); // 短暂延迟,避免过快循环 + log.info(`【IMG】第${retryCount++}次识别并点击 ${desc} 失败 | 耗时: ${Date.now() - start}ms`); + } + } catch (error) { + log.error(`【IMG】${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); + //如果有配置通知…… + notification.error(`【IMG】${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); + throw new Error(`【IMG】识别图像时发生异常: ${error.message}`); + } + return { success: false }; +} +async function recognizeTextAndClick(targetText, ocrRegion, timeout = 8000) { + let start = Date.now(); + let retryCount = 0; // 重试计数 + let status = false; // 用于记录是否匹配成功 + try { + while (Date.now() - start < timeout && !status) { + const ro = captureGameRegion(); + let resultList = ro.findMulti(ocrRegion); + ro.dispose(); + await sleep(500); // 短暂延迟,避免过快循环 + for (let result of resultList) { + if (result.text.includes(targetText)) { + let clickResult = await clickCenter(result.x, result.y, result.width, result.height); + log.info(`【OCR】成功识别并点击 ${targetText}| 耗时: ${Date.now() - start}ms`); + status = true; // 设置匹配成功状态 + return { success: true, x: clickResult.x, y: clickResult.y }; + } + } + // await sleep(200); // 短暂延迟,避免过快循环 + log.info(`【OCR】${targetText}失败,正在进行第 ${retryCount++} 次重试...`); + } + } catch (error) { + log.warn(`【OCR】经过多次尝试,仍然无法识别文字: ”${targetText}“,尝试点击默认中心位置`); + await clickCenter(result.x, result.y, result.width, result.height); + //如果有配置通知…… + notification.error(`【OCR】识别文字: “${targetText}”,发生异常`); + throw new Error(`【OCR】识别文字时发生异常: ${error.message}`); + } + return { success: false }; +} +// 切换账号(OCR)版本 +// ====================================================== + +// ====================================================== +//切换账号DropDown + + +//切换账号DropDown +// ====================================================== + +(async function () { + // ====================================================== + // Library functions + + var u = {}; // utilities 工具函数集合 + u.logi = function (message, args) { log.info("[切换账号]" + message, args) }; + u.logw = function (message, args) { log.warn("[切换账号]" + message, args) }; + u.x = function (value) { return (value === undefined) ? genshin.width : genshin.width * (value / 1920); }; + u.y = function (value) { return (value === undefined) ? genshin.height : genshin.height * (value / 1080); }; + u.loadTemplate = function (filePath, x /* 0 if omit */, y /* 0 if omit */, w /* maxWidth if omit */, h /* maxHeight if omit */) { + const _x = u.x(x === undefined ? 0 : x); + const _y = u.y(y === undefined ? 0 : y); + const _w = u.x(w) - _x; + const _h = u.y(h) - _y; + return RecognitionObject.TemplateMatch(file.ReadImageMatSync(filePath), _x, _y, _w, _h); + }; + u.findText = function (resList, text) { + for (let i = 0; i < resList.count; i++) { + let res = resList[i]; + if (res.text == text) { + return res; + } + } + return null; + }; + u.matchUser = function (text, username) { + if (typeof text !== "string" || typeof username !== "string") return false; + if (text.length !== username.length) return false; + for (let i = 0; i < text.length; i++) { + const a = text[i]; + const b = username[i]; + if (a === '*' || b === '*') continue; + if (a !== b) return false; + } + return true; + }; + u.matchUserRelaxed = function (text, username) { + if (typeof text !== "string" || typeof username !== "string") return false; + // Check the head + for (let i = 0; i < text.length; i++) { + const a = text[i]; + const b = username[i]; + if (a === '*') break; // Stop checking when a '*' is found in text. + if (a !== b) return false; + } + // Check the tail + for (let i = 0; i < text.length; i++) { + const a = text[text.length - 1 - i]; + const b = username[username.length - 1 - i]; + if (a === '*') break; // Stop checking when a '*' is found in text. + if (a !== b) return false; + } + return true; + }; + u.waitAndFindImage = async function (asset, internal = 500, timeout = 60000) { + const start = Date.now(); + let lastLog = start; + let endTime = start + timeout; + while (Date.now() < endTime) { + let captureRegion = captureGameRegion(); + let res = captureRegion.Find(asset); + captureRegion.dispose(); + if (!res.isEmpty()) { + return res; + } + if (Date.now() - lastLog >= 10000) { + let elapsed = ((Date.now() - start) / 1000).toFixed(1); + u.logw("等待匹配图像已持续 {0} 秒,仍在尝试寻找图像:{1}", elapsed, asset.Name); + lastLog = Date.now(); + } + await sleep(internal); + } + return null; + } + u.waitAndFindText = async function (text, x, y, w, h, internal = 500) { + const start = Date.now(); + let lastLog = start; + while (true) { + let captureRegion = captureGameRegion(); + let resList = captureRegion.findMulti(RecognitionObject.ocr(x, y, w, h)); + captureRegion.dispose(); + if (typeof text === "string") { + let textFound = u.findText(resList, text); + if (textFound) { + return textFound; + } + } else if (text instanceof Array) { + var textFound = null; + for (let i = 0; i < text.length; i++) { + let textItem = text[i]; + textFound = u.findText(resList, textItem); + if (!textFound) { + break; + } + } + if (textFound) { + return textFound; + } + } + + if (Date.now() - lastLog >= 10000) { + let elapsed = ((Date.now() - start) / 1000).toFixed(1); + u.logw("等待匹配图像已持续 {0} 秒,仍在尝试寻找文字:{1}", elapsed, text.toString()); + lastLog = Date.now(); + } + await sleep(internal); + } + } + + // ====================================================== + // Setup + + const targetUser = settings.username; + + const assetLogoutIcon = u.loadTemplate("Assets/RecognitionObject/logout.png", 1750, 900); + const assetPaimonMenuIcon = u.loadTemplate("Assets/RecognitionObject/paimon_menu.png", 0, 0, 150, 150); + + // Check current state + + /** + * 领取空月祝福 + */ + async function useBlessingOfTheWelkinMoon() { + u.logi("开始尝试领取空月祝福"); + + let captureRegion = captureGameRegion(); + let resList = captureRegion.findMulti(RecognitionObject.ocrThis); + captureRegion.dispose(); + + for (let i = 0; i < resList.count; i++) { + let res = resList[i]; + if (res.text.includes("点击领取") || res.text.includes("空月祝福")) { + res.click(); + await sleep(500); + res.click(); + res.click(); + await sleep(500); + } + } + + let captureRegionGetReward = captureGameRegion(); + let resGetReward = captureRegionGetReward.findMulti(RecognitionObject.ocrThis); + captureRegionGetReward.dispose(); + for (let i = 0; i < resGetReward.count; i++) { + let res = resGetReward[i]; + if (res.text.includes("点击") || res.text.includes("空白") || res.text.includes("获得")) { + res.click(); + await sleep(500); + } + } + + u.logi("空月祝福领取成功"); + } + + async function waitAndDetermineCurrentView() { + u.logi("开始判断当前画面状态"); + while (true) { + let captureRegion = captureGameRegion(); + let res = captureRegion.Find(assetLogoutIcon); + let logoutIconFound = !res.isEmpty(); + + if (logoutIconFound) { + let resList = captureRegion.findMulti(RecognitionObject.ocr(u.x(850), u.y(970), u.x(220), u.y(100))); + captureRegion.dispose(); + if (u.findText(resList, "点击进入")) { + u.logi("检测到目前处于登录界面"); + return false; + } + } + + // 尝试领取空月祝福 + await useBlessingOfTheWelkinMoon(); + + // Not in the login screen, check if is in the game main menu. + let paimonIcon = captureRegion.Find(assetPaimonMenuIcon); + captureRegion.dispose(); + if (!paimonIcon.isEmpty()) { + u.logi("检测到目前处于游戏主界面"); + return true; + } + + // Not in the main game screen either, wait and try again. + u.logi("未检测到登出按钮或派蒙菜单图标,可能处于游戏中,等待状态变化"); + genshin.blessingOfTheWelkinMoon(); + moveMouseTo(960, 0); + await sleep(100); + middleButtonClick(); + genshin.returnMainUi(); + await sleep(4900); + } + } + + async function stateReturnToGenshinGate() { + const assetPaimonCancelIcon = u.loadTemplate("Assets/RecognitionObject/paimon_cancel.png", 0, 0, 100, 100); + + while (true) { + let paimonIcon = await u.waitAndFindImage(assetPaimonMenuIcon, 500, 1000); + if (!paimonIcon) { + u.logi("检测到派蒙菜单图标不存在,可能已开启菜单,进入登出按钮识别流程"); + break; + } + moveMouseTo(960, 0); + await sleep(100); + middleButtonClick(); + keyPress("VK_ESCAPE"); + u.logi("已按下ESC键,打开派蒙菜单"); + await sleep(1000); + } + + // 识别派蒙菜单,点击登出按钮 + await u.waitAndFindImage(assetPaimonCancelIcon); + // u.logi("点击登出按钮"); + click(u.x(50), u.y(1024)); + + // 退出至登录界面 + let btnExitToLogin = await u.waitAndFindText("退出至登录界面", u.x(680), u.y(380), u.x(540), u.y(340)); + // u.logi("检测到\"退出至登录界面\"按钮,点击"); + // btnExitToLogin.DrawSelf("ExitToLoginBtn"); + btnExitToLogin.Click(); + } + + async function stateLogout() { + u.logi("开始登出"); + + let btnLogout = await u.waitAndFindImage(assetLogoutIcon); + // u.logi("识别到登出按钮,点击"); + btnLogout.DrawSelf("LogoutBtn"); + btnLogout.Click(); + + const assetQuitTextButton = u.loadTemplate("Assets/RecognitionObject/quit.png", 680, 380, 1220, 720); + let btnQuit = await u.waitAndFindImage(assetQuitTextButton, 200); + // u.logi("识别到退出按钮,点击"); + // btnQuit.DrawSelf("QuitBtn"); + btnQuit.Click(); + }; + + async function stateChangeUser() { + u.logi("开始切换账号"); + await u.waitAndFindText(["进入游戏", "登录其他账号"], u.x(680), u.y(380), u.x(540), u.y(340), 200); + + const assetSelectUserDropDownIcon = u.loadTemplate("Assets/RecognitionObject/caret.png", 680, 380, 1220, 720); + let captureRegion = captureGameRegion(); + let res = captureRegion.Find(assetSelectUserDropDownIcon); + captureRegion.dispose(); + if (res.isEmpty()) { + u.logi("未找到下拉菜单图标,点击硬编码的坐标(960, 500)展开菜单"); + click(u.x(960), u.y(500)); + } else { + // u.logi("识别到下拉菜单,点击"); + // res.DrawSelf("UserDropdown"); + res.Click(); + } + + u.logi("开始从下拉列表选择账号"); + var selectedUser = null; + { + const start = Date.now(); + let lastLog = start; + while (selectedUser == null) { + await sleep(200); + + let captureRegion = captureGameRegion(); + let resList = captureRegion.findMulti(RecognitionObject.ocr(u.x(680), u.y(540), u.x(540), u.y(500))); + captureRegion.dispose(); + for (let i = 0; i < resList.count; i++) { + let res = resList[i]; + let user = lastLog > start ? u.matchUserRelaxed(res.text, targetUser) : u.matchUser(res.text, targetUser); + if (user) { + selectedUser = res; + break; + } + } + + if (Date.now() - lastLog >= 10000) { + let elapsed = ((Date.now() - start) / 1000).toFixed(1); + u.logw("等待匹配图像已持续 {0} 秒,仍在尝试寻找账号文本:{1}", elapsed, targetUser); + lastLog = Date.now(); + for (let i = 0; i < resList.count; i++) { + let res = resList[i]; + u.logw("账户文本:{0}", res.text); + } + } + } + } + + u.logi("识别到目标账号:{0}", selectedUser.text); + selectedUser.DrawSelf("SelectUser"); + selectedUser.Click(); + + await sleep(500); + { + let captureRegion = captureGameRegion(); + let btnEnterGame = captureRegion.DeriveCrop(u.x(684), u.y(598), u.x(552), u.y(66)); + btnEnterGame.Click(); + captureRegion.dispose(); + btnEnterGame.dispose(); + // btnEnterGame.DrawSelf("EnterGameBtn"); + // u.logi("已点击\"进入游戏\"按钮,完成账号选择。"); + } + } + + async function stateEnterGame() { + // u.logi("开始进入游戏,等待游戏加载。"); + let textClickToStart = await u.waitAndFindText("点击进入", u.x(850), u.y(970), u.x(220), u.y(100)); + // u.logi("已识别到\"点击进入\"文本,点击鼠标进入游戏。"); + textClickToStart.DrawSelf("ClickToStart"); + textClickToStart.Click(); + } + + // ====================================================== + // Main flow + + if (settings.Modes == "下拉列表") { + await DropDownMode(); + } else if (settings.Modes == "账号+密码") { + await KeyboardMouseMode(); + } else if (settings.Modes == "账号+密码+OCR") { + await OcrMode(); + } else { + log.info("尖尖哇嘎乃") + } + + async function DropDownMode() { + const isInGame = await waitAndDetermineCurrentView(); + if (isInGame) { + await stateReturnToGenshinGate(); + await sleep(1000); + } + await stateLogout(); + await sleep(500); + await stateChangeUser(); + await sleep(500); + await stateEnterGame(); + await sleep(20000); + await waitAndDetermineCurrentView(); + + } + + async function KeyboardMouseMode() { + setGameMetrics(1920, 1080, 2.0); + //到达主页面 + await genshin.returnMainUi(); + await sleep(1000); + //打开派蒙页面 + keyPress("VK_ESCAPE"); + await sleep(1000); + click(50, 1030); + //退出门图标 + await sleep(1000); + //退出至登录页面 + click(978, 540); + await sleep(15000); + //登录页面退出当前账号的小门图标 + click(1828, 985); + await sleep(1000); + //勾选:退出并保留登录记录 + click(701, 573); + await sleep(1000); + //点击退出大按钮 + click(1107, 684); + await sleep(1000); + //登录其他账号 + click(946, 703); + await sleep(1000); + //点击用户名输入框 + click(815, 400); + //如果有文本,清除 + await keyPress("VK_DELETE"); + // 输入文本 + await inputText(settings.username); + await sleep(500); + //点击密码输入框 + click(815, 480); + //如果有文本,清除 + await keyPress("VK_DELETE"); + // 输入文本 + await inputText(settings.password); + await sleep(500); + //登录 + keyPress("VK_RETURN"); + await sleep(500); + //用户协议弹窗,点击同意,等待8.5s,增加容错 + click(1093, 593); + await sleep(8500); + //进入世界循环点击,增加容错 + for (let i = 3; i > 0; i--) { + click(960, 540); + await sleep(1500); + } + //确保进入主页面 + await sleep(12000); + //点击领月卡 + await genshin.blessingOfTheWelkinMoon(); + } + + async function OcrMode() { + setGameMetrics(1920, 1080, 1); + // 如果切换账号是第一个脚本,则有可能出现月卡选项 + //防止genshin.blessingOfTheWelkinMoon();方法失效,先使用物理点击。 + try { + keyDown("VK_MENU"); + await sleep(500); + for (let i = 0; i <= 4; i++) { + await click(genshin.width / 2.0, genshin.height * 0.8); + await sleep(1000); + } + } finally { + keyUp("VK_MENU"); + } + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + await genshin.returnMainUi(); + + await keyPress("VK_ESCAPE"); + await sleep(500); + try { + await matchImgAndClick(pm_out, "左下角退出门"); + await matchImgAndClick(out_to_login, "退出至登陆页面"); + //这一步根据 电脑配置和当前网络情况不同休眠时间不同,建议实际运行之后,如果有日志 : 第x次 识别失败,就适当增加休眠时间 + await sleep(9000); + await matchImgAndClick(login_out_account, "登录页的右下角退出按钮"); + await matchImgAndClick(out_account, "退出当前账号"); + await matchImgAndClick(login_other_account, "登录其他账号"); + await sleep(1000); + await matchImgAndClick(input_phone_or_email, "填写邮箱/手机号"); + await inputText(settings.username); + await sleep(1000); + await matchImgAndClick(input_password, "填写密码"); + await inputText(settings.password); + await sleep(1000); + //按下回车登录账号,弹出用户协议对话框 + await keyPress("VK_RETURN"); + //点击回车后,等待特瓦特大门加载 + await matchImgAndClick(agree, "同意用户协议"); + //如果当天上下线次数过于频繁 + for (let i = 1; i <= 2; i++) { + const ro = captureGameRegion(); + let verify = ro.Find(login_verification.template); + ro.dispose(); + //等待1s避免循环速度过快 + await sleep(1000); + if (verify.isExist()) { + //这里可配置通知方法 + notification.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); + log.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); + } + } + /** + * 根据不同网络环境和电脑配置,此操作可能会将领取月卡操作取代,但是不影响使用 + * 如果发现卡在这一步,请适当延长sleep时间 + */ + await sleep(8000); + await recognizeTextAndClick("点击进入", RecognitionObject.Ocr(862, 966, 206, 104), 960, 540, 5000); + await sleep(15000); + + //可能登录账号的时候出现月卡提醒,则先点击一次月卡。 + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + //await genshin.blessingOfTheWelkinMoon(); + //await sleep(1000); + //防止genshin.blessingOfTheWelkinMoon();方法失效,先使用物理点击。 + await sleep(2000); + keyDown("VK_MENU"); + await sleep(500); + for (let i = 0; i <= 4; i++) { + await click(genshin.width / 2.0, genshin.height * 0.8); + await sleep(1000); + } + //keyUp("VK_MENU"); + await genshin.returnMainUi(); + await sleep(1000); + // 如果配置了通知 + notification.send("账号【" + settings.UID + "】切换成功"); + } catch (error) { + log.error(`${script_name}脚本执行过程中发生错误:${error.message}`); + //如果发生错误,则发送通知 + notification.error(`${script_name}脚本执行过程中发生错误:${error.message}`); + throw new Error(`${script_name}脚本执行过程中发生错误:${error.message}`); + } finally { + keyUp("VK_MENU"); + } + } +})(); diff --git a/repo/js/SwitchAccountMultipleMode/manifest.json b/repo/js/SwitchAccountMultipleMode/manifest.json new file mode 100644 index 000000000..c78faaaa8 --- /dev/null +++ b/repo/js/SwitchAccountMultipleMode/manifest.json @@ -0,0 +1,32 @@ +{ + "manifest_version": 1, + "name": "切换账号多模式", + "version": "1.0", + "bgi_version": "0.49.0", + "description": "多种模式的切换账号,有下拉列表、填写账号密码,OCR操作或键鼠操作\n免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。若因使用此脚本导致的账号泄露、封禁问题与脚本作者无关。", + "tags": [ + "切换账号", + "鼠标点击", + "OCR" + ], + "authors": [ + { + "name": "起个名字好难的喵", + "links": "https://github.com/MisakaAldrich" + }, + { + "name": "密密麻麻" + }, + { + "name": "羊汪汪", + "links": "https://github.com/ColinXHL" + }, + { + "name": "彩虹QQ人", + "email": "846224811@qq.com", + "links": "https://github.com/KRdingsan" + } + ], + "settings_ui": "settings.json", + "main": "main.js" +} \ No newline at end of file diff --git a/repo/js/SwitchAccountMultipleMode/settings.json b/repo/js/SwitchAccountMultipleMode/settings.json new file mode 100644 index 000000000..fe9cfde7e --- /dev/null +++ b/repo/js/SwitchAccountMultipleMode/settings.json @@ -0,0 +1,23 @@ +[ + { + "name": "Modes", + "type": "select", + "label": "切换模式", + "options": [ + "下拉列表", + "账号+密码", + "账号+密码+OCR" + ], + "default": "下拉列表" + }, + { + "name": "username", + "type": "input-text", + "label": "账号(只保存在本地,请妥善保管)\n下拉列表手机号格式:114******98\n下拉列表邮箱格式:11****1@919.com\n账号密码模式请输入完整的手机号或邮箱" + }, + { + "name": "password", + "type": "input-text", + "label": "密码(只保存在本地,请妥善保管)\n切换模式为下拉列表时无需填写" + } +] \ No newline at end of file