Update 更新OCR切换账号脚本 (#1202)

* Update README.md

* Update manifest.json

* Update main.js

* Update README.md
This commit is contained in:
彩虹QQ人
2025-06-26 21:45:31 +08:00
committed by GitHub
parent 3902415eb5
commit c37f9b8dc1
3 changed files with 124 additions and 112 deletions

View File

@@ -1,31 +1,37 @@
// ==UserScript==
// @name 原神自动化登录脚本
// @version 1.0
// @description 原神自动登录工具(仅供学习交流)
// @author 彩虹QQ人
// @match 原神版本5.5BGI版本0.44.6
// ==/UserScript==
# 自动切换账号脚本
此版本可以发送相关通知如需要可以修改main中的notification方法。
**重要免责声明:**
/**
* === 重要免责声明 ===
* 1. 数据安全
* - 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。
* - 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用
*
* 2. 使用风险
* - 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为
* - 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任
*
* 3. 责任限制
* - 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性
* - 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。
*
* 4. 禁止条款
* - 严禁逆向工程、恶意篡改或用于外挂等非法用途。
* - 若游戏运营商提出要求,开发者保留随时停止维护的权利。
*
* 继续使用即表示您已阅读并同意上述条款。
* Last Updated: 2024-04-22
*/
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.5BGI版本≥0.44.6

View File

@@ -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 + "】");
})();

View File

@@ -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"
}
}