JS 脚本: BUG修复和添加问题反馈地址 (#1112)
This commit is contained in:
@@ -20,3 +20,7 @@
|
|||||||
+ 迷你仙灵·薄红
|
+ 迷你仙灵·薄红
|
||||||
+ 迷你仙灵·露草
|
+ 迷你仙灵·露草
|
||||||
+ 嫣朵拉
|
+ 嫣朵拉
|
||||||
|
|
||||||
|
## 问题反馈
|
||||||
|
|
||||||
|
[GitHub issues](https://github.com/ftnfurina/bettergi-js-repo/issues)
|
||||||
|
|||||||
@@ -1,3 +1,30 @@
|
|||||||
|
// src/index.ts
|
||||||
|
async function mouseSmoothMove(sx, sy, ex, ey, duration) {
|
||||||
|
const steps = Math.max(Math.floor(duration / (1e3 / 60)), 20);
|
||||||
|
const points = [];
|
||||||
|
points.push([sx, sy]);
|
||||||
|
for (let i = 1; i < steps - 1; i++) {
|
||||||
|
const t = i / (steps - 1);
|
||||||
|
const x = (1 - t) * sx + t * ex;
|
||||||
|
const y = (1 - t) * sy + t * ey;
|
||||||
|
points.push([x, y]);
|
||||||
|
}
|
||||||
|
points.push([ex, ey]);
|
||||||
|
const interval = duration / steps;
|
||||||
|
for (const [x, y] of points) {
|
||||||
|
moveMouseTo(Math.floor(x), Math.floor(y));
|
||||||
|
await sleep(Math.floor(interval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function mouseSmoothDrag(sx, sy, ex, ey, duration) {
|
||||||
|
moveMouseTo(sx, sy);
|
||||||
|
leftButtonDown();
|
||||||
|
await sleep(50);
|
||||||
|
await mouseSmoothMove(sx, sy, ex, ey, duration - 300);
|
||||||
|
await sleep(250);
|
||||||
|
leftButtonUp();
|
||||||
|
}
|
||||||
|
|
||||||
// 最多尝试 2 次拖动屏幕
|
// 最多尝试 2 次拖动屏幕
|
||||||
const DRAG_SCREEN_MAX = 2;
|
const DRAG_SCREEN_MAX = 2;
|
||||||
// 宠物与模板的对应关系
|
// 宠物与模板的对应关系
|
||||||
@@ -17,25 +44,6 @@ const PETS = [
|
|||||||
{ name: '缥锦机关·留云', file: 'assets/damasked_device.png' },
|
{ name: '缥锦机关·留云', file: 'assets/damasked_device.png' },
|
||||||
{ name: '「式小将」', file: 'assets/shiki_koshou.png' },
|
{ name: '「式小将」', file: 'assets/shiki_koshou.png' },
|
||||||
];
|
];
|
||||||
/**
|
|
||||||
* 垂直拖动屏幕
|
|
||||||
* @param x 初始 x 坐标
|
|
||||||
* @param yStart 起始 y 坐标
|
|
||||||
* @param yEnd 终点 y 坐标
|
|
||||||
* @param step 步长
|
|
||||||
*/
|
|
||||||
async function verticalDragScreen(x, yStart, yEnd, step = 20) {
|
|
||||||
moveMouseTo(x, yStart);
|
|
||||||
await sleep(100);
|
|
||||||
leftButtonDown();
|
|
||||||
const yStep = (yEnd - yStart) / step;
|
|
||||||
for (let i = 1; i <= step; i++) {
|
|
||||||
await sleep(50);
|
|
||||||
moveMouseTo(x, Math.floor(yStart + yStep * i));
|
|
||||||
}
|
|
||||||
await sleep(1000);
|
|
||||||
leftButtonUp();
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 装备宠物
|
* 装备宠物
|
||||||
* @param pet 宠物
|
* @param pet 宠物
|
||||||
@@ -54,7 +62,7 @@ async function equipPet(pet) {
|
|||||||
const petRegion = gameRegion.find(petRo);
|
const petRegion = gameRegion.find(petRo);
|
||||||
if (!petRegion.isExist()) {
|
if (!petRegion.isExist()) {
|
||||||
// 未找到宠物,尝试拖动屏幕
|
// 未找到宠物,尝试拖动屏幕
|
||||||
await verticalDragScreen(1200, 842, 117);
|
await mouseSmoothDrag(1200, 890, 1200, 186, 2000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
petRegion.click();
|
petRegion.click();
|
||||||
@@ -75,7 +83,7 @@ async function equipPet(pet) {
|
|||||||
* 卸下宠物
|
* 卸下宠物
|
||||||
*/
|
*/
|
||||||
async function removePet() {
|
async function removePet() {
|
||||||
const pets = PETS.map(pet => {
|
const pets = PETS.map((pet) => {
|
||||||
const ro = RecognitionObject.templateMatch(file.readImageMatSync(pet.file));
|
const ro = RecognitionObject.templateMatch(file.readImageMatSync(pet.file));
|
||||||
ro.threshold = 0.97;
|
ro.threshold = 0.97;
|
||||||
ro.use3Channels = true;
|
ro.use3Channels = true;
|
||||||
@@ -97,7 +105,7 @@ async function removePet() {
|
|||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
return log.info(`已卸下宠物:${pet.name}`);
|
return log.info(`已卸下宠物:${pet.name}`);
|
||||||
}
|
}
|
||||||
await verticalDragScreen(1200, 842, 117);
|
await mouseSmoothDrag(1200, 890, 1200, 186, 2000);
|
||||||
}
|
}
|
||||||
log.warn('未找到装备中的宠物');
|
log.warn('未找到装备中的宠物');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
"manifest_version": 1,
|
||||||
"name": "装备或卸下跟随宠物",
|
"name": "装备或卸下跟随宠物",
|
||||||
"description": "带上你的宠物,一起冒险吧!\nPS:请在原神分辨率为 1920x1080 下使用该脚本。",
|
"description": "带上你的宠物,一起冒险吧!\nPS:请在原神分辨率为 1920x1080 下使用该脚本。",
|
||||||
"version": "0.0.1",
|
"version": "0.0.4",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"settings_ui": "settings.json",
|
"settings_ui": "settings.json",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|||||||
@@ -4,3 +4,7 @@
|
|||||||
|
|
||||||
1. 修改自定义配置,将好友的 UID 添加到配置中
|
1. 修改自定义配置,将好友的 UID 添加到配置中
|
||||||
2. 执行脚本即可
|
2. 执行脚本即可
|
||||||
|
|
||||||
|
## 问题反馈
|
||||||
|
|
||||||
|
[GitHub issues](https://github.com/ftnfurina/bettergi-js-repo/issues)
|
||||||
|
|||||||
@@ -1,22 +1,28 @@
|
|||||||
// 等待好友确认超时时间 25s
|
// src/index.ts
|
||||||
const WAIT_FRIEND_CONFIRM_TIMEOUT = 25 * 1000;
|
function autoZoomOcr(x, y, w, h) {
|
||||||
/**
|
|
||||||
* 创建自适应 16:9 缩放的 OCR 对象
|
|
||||||
* @param x X 坐标
|
|
||||||
* @param y Y 坐标
|
|
||||||
* @param w 宽度
|
|
||||||
* @param h 高度
|
|
||||||
*/
|
|
||||||
function createAutoZoomOcr(x, y, w, h) {
|
|
||||||
const ratio = genshin.scaleTo1080PRatio;
|
const ratio = genshin.scaleTo1080PRatio;
|
||||||
return RecognitionObject.ocr(x * ratio, y * ratio, w * ratio, h * ratio);
|
return RecognitionObject.ocr(x * ratio, y * ratio, w * ratio, h * ratio);
|
||||||
}
|
}
|
||||||
|
function createTimer(timeout) {
|
||||||
|
let time = Date.now();
|
||||||
|
return Object.freeze({
|
||||||
|
reStart() {
|
||||||
|
time = Date.now();
|
||||||
|
},
|
||||||
|
isTimeout() {
|
||||||
|
return Date.now() - time >= timeout;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待好友确认超时时间 25s
|
||||||
|
const WAIT_FRIEND_CONFIRM_TIMEOUT = 25 * 1000;
|
||||||
/**
|
/**
|
||||||
* 是否在多人游戏中
|
* 是否在多人游戏中
|
||||||
*/
|
*/
|
||||||
function inMultiplayerGame() {
|
function inMultiplayerGame() {
|
||||||
const gameRegion = captureGameRegion();
|
const gameRegion = captureGameRegion();
|
||||||
const playerCountRegin = gameRegion.find(createAutoZoomOcr(340, 18, 53, 53));
|
const playerCountRegin = gameRegion.find(autoZoomOcr(340, 18, 53, 53));
|
||||||
const playerCountText = playerCountRegin.text.trim().toLocaleLowerCase();
|
const playerCountText = playerCountRegin.text.trim().toLocaleLowerCase();
|
||||||
return playerCountText.includes('p');
|
return playerCountText.includes('p');
|
||||||
}
|
}
|
||||||
@@ -26,10 +32,10 @@ function inMultiplayerGame() {
|
|||||||
if (!uid) {
|
if (!uid) {
|
||||||
throw new Error('UID 不能为空');
|
throw new Error('UID 不能为空');
|
||||||
}
|
}
|
||||||
|
await genshin.returnMainUi();
|
||||||
if (inMultiplayerGame()) {
|
if (inMultiplayerGame()) {
|
||||||
throw new Error('正在多人游戏中,无法加入好友世界');
|
throw new Error('正在多人游戏中,无法加入好友世界');
|
||||||
}
|
}
|
||||||
await genshin.returnMainUi();
|
|
||||||
log.info(`尝试加入好友世界(UID: ${uid})`);
|
log.info(`尝试加入好友世界(UID: ${uid})`);
|
||||||
// 打开好友列表
|
// 打开好友列表
|
||||||
keyPress('VK_O');
|
keyPress('VK_O');
|
||||||
@@ -44,20 +50,20 @@ function inMultiplayerGame() {
|
|||||||
await sleep(500);
|
await sleep(500);
|
||||||
const gameRegion = captureGameRegion();
|
const gameRegion = captureGameRegion();
|
||||||
// 尝试找到用户卡片的冒险等阶
|
// 尝试找到用户卡片的冒险等阶
|
||||||
const levelRegin = gameRegion.find(createAutoZoomOcr(425, 445, 106, 37));
|
const levelRegin = gameRegion.find(autoZoomOcr(425, 445, 106, 37));
|
||||||
const levelText = levelRegin.text.trim();
|
const levelText = levelRegin.text.trim();
|
||||||
if (!levelText.includes('冒险等阶')) {
|
if (!levelText.includes('冒险等阶')) {
|
||||||
// 判断是否搜索的用户是否是自己
|
// 判断是否搜索的用户是否是自己
|
||||||
const yourselfRegin = gameRegion.find(createAutoZoomOcr(660, 495, 601, 88));
|
const yourselfRegin = gameRegion.find(autoZoomOcr(660, 495, 601, 88));
|
||||||
if (yourselfRegin.text.includes('其他玩家')) {
|
if (yourselfRegin.text.includes('其他玩家')) {
|
||||||
throw new Error('不能使用自己的UID');
|
throw new Error('不能使用自己的UID');
|
||||||
}
|
}
|
||||||
throw new Error('UID不存在');
|
throw new Error('UID不存在');
|
||||||
}
|
}
|
||||||
const joinOrAddRegin = gameRegion.find(createAutoZoomOcr(1160, 800, 200, 54));
|
const joinOrAddRegin = gameRegion.find(autoZoomOcr(1160, 800, 200, 54));
|
||||||
const joinOrAddText = joinOrAddRegin.text.trim();
|
const joinOrAddText = joinOrAddRegin.text.trim();
|
||||||
if (joinOrAddText === '') {
|
if (joinOrAddText === '') {
|
||||||
throw new Error("你的好友不在线");
|
throw new Error('你的好友不在线');
|
||||||
}
|
}
|
||||||
else if (joinOrAddText === '申请加入') {
|
else if (joinOrAddText === '申请加入') {
|
||||||
log.info(`已经发起加入申请,等待好友同意`);
|
log.info(`已经发起加入申请,等待好友同意`);
|
||||||
@@ -66,12 +72,11 @@ function inMultiplayerGame() {
|
|||||||
else {
|
else {
|
||||||
throw new Error('TA不是你的好友');
|
throw new Error('TA不是你的好友');
|
||||||
}
|
}
|
||||||
const startTime = new Date().getTime();
|
const timer = createTimer(WAIT_FRIEND_CONFIRM_TIMEOUT);
|
||||||
const timeout = WAIT_FRIEND_CONFIRM_TIMEOUT + startTime;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// 等待好友回复
|
// 等待好友回复
|
||||||
const gameRegion = captureGameRegion();
|
const gameRegion = captureGameRegion();
|
||||||
const requestRegin = gameRegion.find(createAutoZoomOcr(725, 195, 465, 45));
|
const requestRegin = gameRegion.find(autoZoomOcr(725, 195, 465, 45));
|
||||||
const requestText = requestRegin.text.trim();
|
const requestText = requestRegin.text.trim();
|
||||||
if (requestText.endsWith('拒绝了多人游戏申请')) {
|
if (requestText.endsWith('拒绝了多人游戏申请')) {
|
||||||
throw new Error('好友拒绝了多人游戏');
|
throw new Error('好友拒绝了多人游戏');
|
||||||
@@ -80,7 +85,7 @@ function inMultiplayerGame() {
|
|||||||
log.info('成功加入好友世界');
|
log.info('成功加入好友世界');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (new Date().getTime() > timeout) {
|
if (timer.isTimeout()) {
|
||||||
throw new Error('请求超时');
|
throw new Error('请求超时');
|
||||||
}
|
}
|
||||||
await sleep(50);
|
await sleep(50);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 1,
|
"manifest_version": 1,
|
||||||
"name": "加入好友的世界",
|
"name": "加入好友的世界",
|
||||||
"description": "快让我访问!",
|
"description": "快让我访问!",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"settings_ui": "settings.json",
|
"settings_ui": "settings.json",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|||||||
Reference in New Issue
Block a user