JS: 切换账号三合一 (#2298)

* JS: 切换账号三合一

* 存档以供后人参考
This commit is contained in:
起个名字好难的喵
2025-11-02 19:19:54 +08:00
committed by GitHub
parent e431135464
commit b54fef9161
50 changed files with 1061 additions and 367 deletions

View File

@@ -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.5BGI版本≥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.5BGI版本≥0.44.6
# 更新记录
2025年6月26日 version 1.1 整合代码
2025年6月27日 version 1.2 解决循环无法跳出的问题

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 852 B

After

Width:  |  Height:  |  Size: 852 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

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

View File

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

View File

@@ -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": "密码(账号只保存在本地,请妥善保管)"
}
]

View File

@@ -1,64 +1,64 @@
(async function () {
/**
* 不使用屏幕识别的登出至其他账号的脚本
* 版本
* 原神5.5
* BIG0.44.6
*/
//实测缩放倍数1.0、1.5可行实测凡169大于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
* BIG0.44.6
*/
//实测缩放倍数1.0、1.5可行实测凡169大于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();
})();

View File

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

View File

@@ -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": "密码(账号只保存在本地)"
}
]

View File

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 367 B

View File

Before

Width:  |  Height:  |  Size: 646 B

After

Width:  |  Height:  |  Size: 646 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,35 @@
# 下拉列表模式
## 使用前准备
确保你想要切换的账号是已登录状态,且账号选择列表中存在。
## 使用方式
1. 把此脚本添加到配置组
2. 右键点击选择"修改JS脚本自定义配置"
3. 填入你想登录的账户名称,该名称必须和账号列表中显示的一致
- 请确认你此次登录使用的是手机号还是邮箱
# 账号+密码 / 账号+密码+OCR模式
**重要免责声明:**
1. **数据安全:**
1. 本脚本使用的用户名、密码等敏感信息仅存储在本地设备,开发者无法获取。
2. 使用者需自行承担账户信息泄露风险,请勿在公共设备或不可信环境中使用。
2. **使用风险:**
1. 本脚本为开源学习项目,禁止用于商业用途或违反游戏条款的行为。
2. 滥用可能导致游戏账号封禁,开发者不承担任何直接或间接责任。
3. **责任限制:**
1. 本脚本按“现状”提供,不承诺兼容性、安全性或功能完整性。
2. 因使用本脚本导致的账号、数据、设备损失,开发者概不负责。
4. **禁止条款:**
1. 严禁逆向工程、恶意篡改或用于外挂等非法用途。
2. 若游戏运营商提出要求,开发者保留随时停止维护的权利。
使用脚本即表示您已阅读并同意上述条款。
如果使用BGI一条龙启动且第一个脚本就是账号切换则需要开启BGI启动配置-同时启动原神-自动进入游戏
根据使用者设备配置和网络环境,脚本中的延时可以适当调整。(如果不熟悉脚本操作则不建议修改延时)

View File

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

View File

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

View File

@@ -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切换模式为下拉列表时无需填写"
}
]