diff --git a/repo/js/切换账号(OCR)版本/README.md b/repo/js/切换账号(OCR)版本/README.md index 46999b5f..8c2cbb4a 100644 --- a/repo/js/切换账号(OCR)版本/README.md +++ b/repo/js/切换账号(OCR)版本/README.md @@ -1,31 +1,37 @@ -// ==UserScript== -// @name 原神自动化登录脚本 -// @version 1.0 -// @description 原神自动登录工具(仅供学习交流) -// @author 彩虹QQ人 -// @match 原神版本:5.5;BGI版本:0.44.6 -// ==/UserScript== +# 自动切换账号脚本 -此版本可以发送相关通知,如需要可以修改main中的notification方法。 +**重要免责声明:** -/** - * === 重要免责声明 === - * 1. 数据安全 - * - 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。 - * - 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用。 - * - * 2. 使用风险 - * - 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为。 - * - 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任。 - * - * 3. 责任限制 - * - 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性。 - * - 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。 - * - * 4. 禁止条款 - * - 严禁逆向工程、恶意篡改或用于外挂等非法用途。 - * - 若游戏运营商提出要求,开发者保留随时停止维护的权利。 - * - * 继续使用即表示您已阅读并同意上述条款。 - * Last Updated: 2024-04-22 - */ \ No newline at end of file +1. **数据安全:** + 1. 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。 + 2. 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用。 +2. **使用风险:** + 1. 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为。 + 2. 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任。 +3. **责任限制:** + 1. 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性。 + 2. 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。 +4. **禁止条款:** + 1. 严禁逆向工程、恶意篡改或用于外挂等非法用途。 + 2. 若游戏运营商提出要求,开发者保留随时停止维护的权利。 + +使用脚本即表示您已阅读并同意上述条款。 + +如果使用BGI一条龙启动,且第一个脚本就是账号切换,则需要开启BGI启动配置-同时启动原神-自动进入游戏 + +根据使用者设备配置和网络环境,脚本中的延时可以适当调整。(如果不熟悉脚本操作则不建议修改延时) + +作者留言: +毕竟都使用BGI了,时间还算个事吗?(笑) + +需要国际服适配脚本私信我。 + +**Last Updated:** 2025-06-26 + +--- +# 脚本信息 + @name 原神自动化登录脚本 + @version 1.1 + @description 原神自动登录工具(仅供学习交流,请勿商业用途) + @author 彩虹QQ人 + @match 原神版本:≥5.5;BGI版本:≥0.44.6 diff --git a/repo/js/切换账号(OCR)版本/main.js b/repo/js/切换账号(OCR)版本/main.js index d2b9e8c7..6f76e98b 100644 --- a/repo/js/切换账号(OCR)版本/main.js +++ b/repo/js/切换账号(OCR)版本/main.js @@ -1,9 +1,6 @@ const author = "彩虹QQ人"; const script_name = "切换账号(OCR)版本"; -const pm_menu = { - template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/pm_menu.png")), - name: "pm_menu.png" -}; + const pm_out = { template: RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/pm_out.png")), name: "pm_out.png" @@ -41,113 +38,122 @@ const login_verification = { template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/verification.png")), name: "verification.png" }; -const click_into = { - template:RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/click_into.png")), - name: "click_into.png" -}; - -(async function () { - - /** - * 普通的识别点击方法 - * @param obj 识别对象 - * @param desc 识别对象的描述,方便日志查看 - */ - async function identificationAndClick (obj,desc) { - const start = Date.now(); - // 在截图中寻找 +async function matchImgAndClick(obj, desc,timeout = 8000) { + const start = Date.now(); + let x = 1; // 识别次数计数 + while (Date.now() - start < timeout) { + try { + await sleep(500); // 短暂延迟,避免过快循环 let result = captureGameRegion().Find(obj.template); + await sleep(500); // 短暂延迟,避免过快循环 if (result.isExist()) { - result.click(); - log.info(`成功识别并点击 ${desc} | 耗时: ${Date.now() - start}ms`); - }else { - //这里可配置通知方法 - // notification.error(`${script_name}识别超时===待切换账号:${settings.username}===原因:未找到目标 [${desc}] | 文件:${obj.name}`); - throw new Error(`${script_name}识别超时:未找到目标 [${desc}] | 文件:${obj.name}`); - } - } - - /** - * 等待正确页面的识别点击方法 - * @param obj 识别对象 - * @param desc 识别对象的描述,方便日志查看 - * @param timeout 设置超时时间(默认值为15000即不传此参数情况下) - */ - async function waitForToClick(obj, desc,timeout = 15000) { - await sleep(1000); - const start = Date.now(); - let x = 1; - while (Date.now() - start < timeout) { - let result = captureGameRegion().Find(obj.template); - //等待1s确保识别结果 - await sleep(800); - if (result.isExist()) { + let centerX = Math.round(result.x + result.width / 2); + let centerY = Math.round(result.y + result.height / 2); result.click(); log.info(`成功识别并点击 ${desc}| 耗时: ${Date.now() - start}ms`); - return true; + return { success: true, x: centerX, y: centerY }; } - log.info(`第${x}识别并点击 ${desc} 失败 | 耗时: ${Date.now() - start}ms`); - x++; - await sleep(1000); + } catch (error) { + log.error(`识别图像时发生异常: ${error.message}`); } - //这里可配置通知方法 - //notification.error(`${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); - throw new Error(`${script_name}等待超时:未找到目标 [${desc}] | 文件:${obj.name}`); + log.info(`第${x++}次识别并点击 ${desc} 失败 | 耗时: ${Date.now() - start}ms`); } - + log.warn(`${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); + //这里配置通知方法 + notification.error(`${script_name}等待超时,请人工介入。===待切换账号:${settings.username}===超时原因:未找到目标 [${desc}] | 文件:${obj.name}`); + return { success: false }; +} +async function recognizeTextAndClick(targetText, ocrRegion, timeout = 8000) { + let startTime = Date.now(); + let retryCount = 0; // 重试计数 + while (Date.now() - startTime < timeout) { + try { + // 尝试 OCR 识别 + let resList = captureGameRegion().findMulti(ocrRegion); // 指定识别区域 + // 遍历识别结果,检查是否找到目标文本 + for (let res of resList) { + if (res.text.includes(targetText)) { + // 如果找到目标文本,计算并点击文字的中心坐标 + let centerX = Math.round(res.x + res.width / 2); + let centerY = Math.round(res.y + res.height / 2); + await click(centerX, centerY); + await sleep(500); // 确保点击后有足够的时间等待 + return { success: true, x: centerX, y: centerY }; + } + } + } catch (error) { + retryCount++; // 增加重试计数 + log.warn(`页面标志识别失败,正在进行第 ${retryCount} 次重试...`); + } + await sleep(1000); // 短暂延迟,避免过快循环 + } + log.warn(`经过多次尝试,仍然无法识别文字: ${targetText},尝试点击默认中心位置`); + let centerX = Math.round(ocrRegion.x + ocrRegion.width / 2); + let centerY = Math.round(ocrRegion.y + ocrRegion.height / 2); + await click(centerX, centerY); + await sleep(1000); + return { success: false }; +} +/** + * main流程开始 + */ +(async function () { + + setGameMetrics(1920, 1080, 1); + // 如果切换账号是第一个脚本,则有可能出现月卡选项 + await genshin.blessingOfTheWelkinMoon(); + await sleep(1000); + await genshin.blessingOfTheWelkinMoon(); + await sleep(1000); await genshin.returnMainUi(); - //按下alt键(确保释放) - await keyDown("VK_MENU"); + + await keyPress("VK_ESCAPE"); await sleep(500); - try { - await identificationAndClick(pm_menu,"左上角派蒙脑袋"); - } finally { - await keyUp("VK_MENU"); - } - await waitForToClick(pm_out,"左下角退出门"); - await waitForToClick(out_to_login,"退出至登陆页面"); + + await matchImgAndClick(pm_out,"左下角退出门"); + await matchImgAndClick(out_to_login,"退出至登陆页面"); //这一步根据 电脑配置和当前网络情况不同休眠时间不同,建议实际运行之后,如果有日志 : 第x次 识别失败,就适当增加休眠时间 await sleep(9000); - await waitForToClick(login_out_account,"登录页的右下角退出按钮"); - await waitForToClick(out_account,"退出当前账号"); - await waitForToClick(login_other_account,"登录其他账号"); + await matchImgAndClick(login_out_account,"登录页的右下角退出按钮"); + await matchImgAndClick(out_account,"退出当前账号"); + await matchImgAndClick(login_other_account,"登录其他账号"); await sleep(1000); - await waitForToClick(input_phone_or_email,"填写邮箱/手机号"); + await matchImgAndClick(input_phone_or_email,"填写邮箱/手机号"); await inputText(settings.username); await sleep(1000); - await waitForToClick(input_password,"填写密码"); + await matchImgAndClick(input_password,"填写密码"); await inputText(settings.password); await sleep(1000); //按下回车登录账号,弹出用户协议对话框 await keyPress("VK_RETURN"); //点击回车后,等待特瓦特大门加载 - await waitForToClick(agree,"同意用户协议"); + await matchImgAndClick(agree,"同意用户协议"); //如果当天上下线次数过于频繁 for(let i = 1;i<=2;i++){ - await sleep(1000); let verify = captureGameRegion().Find(login_verification.template); - //等待1s确保识别结果 - await sleep(800); + //等待1s避免循环速度过快 + await sleep(1000); if (verify.isExist()) { //这里可配置通知方法 - //notification.error(`${script_name}触发人机验证,请手动登录。===待切换账号:${settings.username}`); - throw new Error(`${script_name}触发人机验证,请手动登录`); + notification.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); + log.error(`${script_name}触发人机验证,请手动登录。===待切换UID:${settings.UID}`); } } /** * 根据不同网络环境和电脑配置,此操作可能会将领取月卡操作取代,但是不影响使用 * 如果发现卡在这一步,请适当延长sleep时间 */ - log.info("点击中心屏幕,等待提瓦特开门"); - await sleep(5000); - for(let i = 1;i<=8;i++){ - click(genshin.width/2.0,genshin.height/2.0); - await sleep(1000); - } - await sleep(5000); - log.info("执行开门自动领取月卡"); + await sleep(8000); + await recognizeTextAndClick("点击进入", RecognitionObject.Ocr(862, 966, 206, 104), 960, 540, 5000); + await sleep(12000); + + //可能登录账号的时候出现月卡提醒,则先点击一次月卡。 await genshin.blessingOfTheWelkinMoon(); await sleep(1000); - log.info(`账号切换成功,当前帐号:${settings.username}`); + await genshin.blessingOfTheWelkinMoon(); + await sleep(1000); + //如果配置了通知 + notification.send("账号切换成功【UID:" + settings.UID + "】"); + })(); diff --git a/repo/js/切换账号(OCR)版本/manifest.json b/repo/js/切换账号(OCR)版本/manifest.json index cdfd1ce6..cc841aba 100644 --- a/repo/js/切换账号(OCR)版本/manifest.json +++ b/repo/js/切换账号(OCR)版本/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 1, "name": "切换账号(OCR)版本", - "version": "1.0", - "description": "使用OCR实现:从主页面退出登录实现切换选定账号。脚本问题请联系作者。免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。", + "version": "1.1", + "description": "使用OCR实现:从主页面退出登录实现切换选定账号。脚本维护/脚本问题请联系作者。\n免责申明:所有的账号密码均保存在本地,请使用者妥善保管账号密码,请勿外泄账号密码。若因使用此脚本导致的账号泄露、封禁问题与脚本作者无关。", "authors": [ { "name": "彩虹QQ人", @@ -11,4 +11,4 @@ ], "settings_ui": "settings.json", "main": "main.js" -} \ No newline at end of file +}