切换活动页面 (#1618)

* feat: 添加原神初露之源水下采集脚本(init)

* feat: 初露之源添加<自体自身之塔>上部、中部、下部区域采集功能(补齐完整)

* feat: 添加队伍切换功能

* feat: 添加返回主界面功能JS(方便扩展调度器使用)

* feat: 添加活动页面切换功能

* docs: 添加活动切换脚本说明文档及代码优化

* docs: 更新活动切换脚本说明文档

* refactor: (用于提交PR)移除废弃的队伍切换和采集脚本-并修正切换活动页面的默认值

* refactor: 调整分页和OCR计数相关参数
This commit is contained in:
云端客
2025-08-17 12:41:32 +08:00
committed by GitHub
parent cad09b5906
commit a0477d073d
6 changed files with 336 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
脚本名称:切换活动页面
功能描述: 打开活动页面、鼠标上滑并根据活动名称选择活动的脚本 (需要处于主界面)
## 核心功能
1. 返回主界面,打开活动页面,切换活动页面
2. 可设置 启动返回主界面(建议启用), 活动名称,最大识别次数(默认2次,不包含首次识别),滑多少次数到顶(默认6次,建议设大点)
3. 其他料理获取:除了烹饪以外的部分料理的获取[仅有数据,未实装]
## 注意事项
1. 请尽量确保原神分辨率是1920x1080(虽然已兼容其他分辨率,但建议使用1920x1080,其他分辨率未测试过)
## 其它
作者Kirito520Asuna
脚本反馈邮箱doutianmianxia@qq.com

View File

@@ -0,0 +1 @@
{"macroEvents":[{"type":2,"mouseX":699,"mouseY":589,"time":875},{"type":2,"mouseX":699,"mouseY":584,"time":921},{"type":2,"mouseX":700,"mouseY":579,"time":953},{"type":2,"mouseX":701,"mouseY":576,"time":984},{"type":2,"mouseX":701,"mouseY":569,"time":1031},{"type":2,"mouseX":702,"mouseY":561,"time":1062},{"type":2,"mouseX":703,"mouseY":555,"time":1093},{"type":2,"mouseX":704,"mouseY":554,"time":1171},{"type":2,"mouseX":704,"mouseY":545,"time":1203},{"type":2,"mouseX":705,"mouseY":541,"time":1234},{"type":2,"mouseX":706,"mouseY":539,"time":1265},{"type":2,"mouseX":706,"mouseY":534,"time":1312},{"type":2,"mouseX":706,"mouseY":527,"time":1343},{"type":2,"mouseX":706,"mouseY":521,"time":1375},{"type":2,"mouseX":706,"mouseY":517,"time":1421},{"type":2,"mouseX":707,"mouseY":511,"time":1468},{"type":2,"mouseX":707,"mouseY":508,"time":1500}],"info":{"name":"","description":"","x":342,"y":126,"width":1920,"height":1080,"recordDpi":1}}

View File

@@ -0,0 +1 @@
{"macroEvents":[{"type":2,"mouseX":699,"mouseY":599,"time":1125},{"type":2,"mouseX":699,"mouseY":600,"time":1157},{"type":2,"mouseX":699,"mouseY":603,"time":1188},{"type":2,"mouseX":699,"mouseY":607,"time":1235},{"type":2,"mouseX":699,"mouseY":608,"time":1328},{"type":2,"mouseX":699,"mouseY":613,"time":1360},{"type":2,"mouseX":699,"mouseY":618,"time":1391},{"type":2,"mouseX":699,"mouseY":629,"time":1422},{"type":2,"mouseX":699,"mouseY":635,"time":1453},{"type":2,"mouseX":699,"mouseY":644,"time":1485},{"type":2,"mouseX":699,"mouseY":647,"time":1516},{"type":2,"mouseX":699,"mouseY":652,"time":1547},{"type":2,"mouseX":699,"mouseY":653,"time":1594},{"type":2,"mouseX":699,"mouseY":658,"time":1641},{"type":2,"mouseX":698,"mouseY":666,"time":1672},{"type":2,"mouseX":698,"mouseY":669,"time":1703},{"type":2,"mouseX":697,"mouseY":670,"time":1735},{"type":2,"mouseX":697,"mouseY":675,"time":1766},{"type":2,"mouseX":697,"mouseY":679,"time":1797},{"type":2,"mouseX":696,"mouseY":686,"time":1828},{"type":2,"mouseX":696,"mouseY":687,"time":1860},{"type":2,"mouseX":696,"mouseY":689,"time":1922},{"type":2,"mouseX":696,"mouseY":692,"time":1985},{"type":2,"mouseX":696,"mouseY":693,"time":2016}],"info":{"name":"","description":"","x":342,"y":126,"width":1920,"height":1080,"recordDpi":1}}

View File

@@ -0,0 +1,232 @@
// 切换到活动页面
async function switchToActivityPage(activityName, activityKey, maxOcrCount) {
try {
//标记点击成功
let switchToActivity = false;
// 记录日志
log.info(`正在尝试切换到活动页面: ${activityName}`);
// 检查游戏窗口信息
const gameWidth = genshin.width;
const gameHeight = genshin.height;
if (!gameWidth || !gameHeight) {
notification.error('无法获取游戏窗口信息,请确保原神正在运行!');
return;
}
log.info(`按下 ${activityKey}`)
// 打开活动页面
await keyDown(activityKey);
await sleep(1000); // 等待活动页面加载
await keyUp(activityKey);
await sleep(1000);
let ocr_x = parseInt(100 * gameWidth / 1920 + '')
let ocr_y = parseInt(200 * gameHeight / 1080 + '')
let ocr_width = parseInt(450 * gameWidth / 1920 + '')
let ocr_hight = parseInt(600 * gameHeight / 1080 + '')
log.info(`参考值(1920*1080):{"x": 100, "y": 200, "width": 450, "height": 600}`)
let ocrRegion = {
"x": ocr_x,
"y": ocr_y,
"width": ocr_width,
"height": ocr_hight
}
log.info(`实际值(${gameWidth}*${gameHeight}):{"x": ${ocr_x}, "y": ${ocr_y}, "width": ${ocr_width}, "height": ${ocr_hight}}`)
let activity = await lookForClickActivity(ocrRegion, activityName);
switchToActivity = activity.switchToActivity
if (!switchToActivity) {
//第一页没有找到活动
//第一次不记录(存在不标准从第二次<标准化后>开始记录)
let lastActivityNameOne = null//记录最后一个活动名称第一次
let lastActivityNameTwo = null//记录最后一个活动名称第二次
//俩个名称一致时说明活动识别完了
let isOne = true;
let index = 1;//记录滑动几次
while (lastActivityNameOne !== lastActivityNameTwo || (isOne && lastActivityNameOne === null && lastActivityNameTwo === null)) {
isOne = false
await sleep(1000)
if (index === 1) {
//滑动
await slideToTop(activity.act_x1, activity.act_y1);
log.info('滑动到顶')
} else {
await swipeOnePageDown(activity.act_x1, activity.act_y1);
log.info('滑动一页')
}
await sleep(1000)
let clickActivity = await lookForClickActivity(ocrRegion, activityName);
switchToActivity = clickActivity.switchToActivity
if (index % 2 !== 0) {
lastActivityNameOne = clickActivity.lastActivityName
} else {
lastActivityNameTwo = clickActivity.lastActivityName
}
log.info(`滑动次数:${index}`)
if (!switchToActivity && maxOcrCount <= index) {
log.error(`已识别:${index}次,已超出最大次数:${maxOcrCount}`)
break;
}
index += 1
if (switchToActivity) {
//点击成功
break;
}
}
}
if (!switchToActivity) {
notification.error(`未找到活动: ${activityName}`);
}
} catch (error) {
log.error(`切换活动页面失败: ${error.message}`);
notification.error(`错误: ${error.message}`);
}
}
/**
* 移动向上鼠标
* @param height
* @returns {Promise<void>}
*/
async function moveMouseUp(x, y, height) {
for (let i = 0; i < height; i++) {
await moveMouseTo(x, y);
await sleep(1000)
await leftButtonDown();
await keyMouseScript.runFile(`assets/(活动页面)鼠标向上移动一格.json`)
await leftButtonUp();
}
}
/**
* 移动向下鼠标
* @param height
* @returns {Promise<void>}
*/
async function moveMouseDown(x, y, height) {
for (let i = 0; i < height; i++) {
await moveMouseTo(x, y);
await sleep(1000)
await leftButtonDown();
await keyMouseScript.runFile(`assets/(活动页面)鼠标向下移动一格.json`)
await leftButtonUp();
}
}
/**
* 自定义 个活动/一页 ==> 滑动多少次
* @returns {Promise<number>}
*/
async function onePage() {
let onePage = 3
if (settings.onePage && settings.onePage !== '默认') {
onePage = parseInt(settings.onePage)
}
return onePage
}
/**
* 向下滑动一页(6次为一页
*/
async function swipeOnePageDown(x, y) {
let count = await onePage();
let move_height = parseInt(count * genshin.height / 1080 + '')
await moveMouseUp(x, y, move_height)
}
/**
* 滑动到顶次数
* @returns {Promise<function(): Promise<number>>}
*/
async function toTopPage() {
let toTopPage = 4
if (settings.toTopPage && settings.toTopPage !== '默认') {
toTopPage = parseInt(settings.toTopPage)
}
return toTopPage
}
/**
* 滑动到顶
* @param act_x1
* @param act_y1
*/
async function slideToTop(act_x1, act_y1) {
let count = await toTopPage();
let move_height = parseInt(count * genshin.height / 1080 + '')
await moveMouseDown(act_x1, act_y1, move_height)
}
/**
* 查找点击活动
* @param ocrRegion
* @param activityName
* @returns {Promise<boolean>}
*/
async function lookForClickActivity(ocrRegion, activityName) {
let switchToActivity = false
let captureRegion = captureGameRegion();
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height);
// ocrObject.threshold = 1.0;
let resList = captureRegion.findMulti(ocrObject);
let firstRes = null
let lastRes = null
for (let res of resList) {
// log.info(`res:${res}`)
// log.info(`识别结果: ${res.text}, 原始坐标: x=${res.x}, y=${res.y}`);
if (res.text.includes(activityName)) {
log.info(`找到活动: ${activityName}`);
// 模拟点击活动
await sleep(1000)
await click(res.x, res.y);
switchToActivity = true;
break;
}
if (firstRes === null) {
firstRes = res
}
lastRes = res
}
let resObject = {
"switchToActivity": switchToActivity,//记录是否点击成功
"act_x1": null,//第一个活动的x坐标
"act_y1": null,//第一个活动的y坐标
"lastActivityName": null//记录最后一个活动名称 点击成功就为空
}
if (firstRes !== null) {
resObject.act_x1 = firstRes.x
resObject.act_y1 = firstRes.y
}
if (!switchToActivity && (lastRes !== null)) {
// log.info(`test--length-1`)
resObject.lastActivityName = lastRes.text
}
return resObject
}
(async function () {
setGameMetrics(1920, 1080, 2); // 设置游戏窗口大小和DPI
// await swipeOnePageDown(300, 240)
if (settings.enable) {
//返回主界面
log.info('返回主界面');
genshin.returnMainUi();
}
await sleep(1000);
const activityName = settings.activityName;
let activityKey = settings.activityKey;
let maxOcrCount = 3;
if (settings.maxOcrCount && settings.maxOcrCount !== '默认') {
maxOcrCount = parseInt(settings.maxOcrCount)
}
if (!activityName) {
notification.error('未配置活动名称,请设置');
return;
}
if (!activityKey) {
activityKey = 'F5';
}
await switchToActivityPage(activityName, activityKey, maxOcrCount);
})();

View File

@@ -0,0 +1,14 @@
{
"name": "切换活动页面",
"version": "1.0.1",
"description": "(需要处于主界面)一个通过 F5 打开活动页面、鼠标上滑并根据活动名称选择活动的脚本",
"settings_ui": "settings.json",
"main": "main.js",
"authors": [
{
"name": "Kirito520Asuna",
"link": "https://github.com/Kirito520Asuna"
}
],
"dependencies": []
}

View File

@@ -0,0 +1,69 @@
[
{
"name": "enable",
"type": "checkbox",
"label": "启用先返回主界面后执行切换",
"default": true
},
{
"name": "activityName",
"type": "input-text",
"label": "活动名称"
},
{
"name": "maxOcrCount",
"type": "select",
"label": "最大识别次数(默认3次,理论上3次就够了,不包含首次识别)",
"options": [
"默认",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
]
},
{
"name": "toTopPage",
"type": "select",
"label": "滑多少次数到顶(默认4次),建议设大点",
"options": [
"默认",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
]
},
{
"name": "onePage",
"type": "select",
"label": "设置一页多少次(默认3次),建议设置到合适识别即可",
"options": [
"默认",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
]
},
{
"name": "activityKey",
"type": "input-text",
"label": "打开活动页面按键(不填默认F5)"
}
]