mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-21 04:19:51 +08:00
优化千星奇域 (#2253)
This commit is contained in:
@@ -11,17 +11,17 @@
|
||||
### 📖 使用方法
|
||||
|
||||
- 将本脚本添加至您的配置组中。
|
||||
- 右键点击脚本自定义配置项(如需要)。
|
||||
- 右键点击脚本自定义配置项(当同时配置了多个关卡id时,假设设置了20次循环,会以20次A,然后20次B这样的形式依次循环)。
|
||||
- 点击运行按钮。
|
||||
|
||||
### 🛠️ 脚本配置
|
||||
|
||||
| 配置项 | 描述 | 默认值 |
|
||||
| -------------- | ------------------------- | ---------- |
|
||||
| 配置项 | 描述 | 默认值 |
|
||||
| -------------- | ------------------------- |------------|
|
||||
| goToTeyvat | 完成后返回提瓦特大陆 | true |
|
||||
| room | 奇域关卡关键词或关卡 GUID | 7015200164 |
|
||||
| room | 奇域关卡关键词或关卡 GUID(支持多个id,用中文或英文逗号隔开) | 7070702264 |
|
||||
| force | 忽略本周经验值已达上限 | false |
|
||||
| thisAttempts | 指定通关次数 | |
|
||||
| thisAttempts | 指定通关次数 | 0 |
|
||||
| expWeeklyLimit | 每周可获取的经验值上限 | 5000 |
|
||||
| expPerAttempt | 每次通关获取的经验值数量 | 20 |
|
||||
|
||||
|
||||
BIN
repo/js/MiliastraExperienceAutomation/assets/exit.png
Normal file
BIN
repo/js/MiliastraExperienceAutomation/assets/exit.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1,7 +1,7 @@
|
||||
// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/workflow.js
|
||||
var defaultMaxAttempts = 5;
|
||||
var defaultRetryInterval = 1e3;
|
||||
var waitForAction = async (condition, retryAction, options) => {
|
||||
const defaultMaxAttempts = 5;
|
||||
const defaultRetryInterval = 1e3;
|
||||
const waitForAction = async (condition, retryAction, options) => {
|
||||
const { maxAttempts = defaultMaxAttempts, retryInterval = defaultRetryInterval } = options || {};
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
if (i === 0 && condition())
|
||||
@@ -13,13 +13,13 @@ var waitForAction = async (condition, retryAction, options) => {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
var waitForRegionAppear = async (regionProvider, retryAction, options) => {
|
||||
const waitForRegionAppear = async (regionProvider, retryAction, options) => {
|
||||
return waitForAction(() => {
|
||||
const region = regionProvider();
|
||||
return region != null && region.isExist();
|
||||
}, retryAction, options);
|
||||
};
|
||||
var waitForRegionDisappear = async (regionProvider, retryAction, options) => {
|
||||
const waitForRegionDisappear = async (regionProvider, retryAction, options) => {
|
||||
return waitForAction(() => {
|
||||
const region = regionProvider();
|
||||
return !region || !region.isExist();
|
||||
@@ -27,13 +27,13 @@ var waitForRegionDisappear = async (regionProvider, retryAction, options) => {
|
||||
};
|
||||
|
||||
// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/asserts.js
|
||||
var assertRegionAppearing = async (regionProvider, message, retryAction, options) => {
|
||||
const assertRegionAppearing = async (regionProvider, message, retryAction, options) => {
|
||||
const isAppeared = await waitForRegionAppear(regionProvider, retryAction, options);
|
||||
if (!isAppeared) {
|
||||
throw new Error(message);
|
||||
}
|
||||
};
|
||||
var assertRegionDisappearing = async (regionProvider, message, retryAction, options) => {
|
||||
const assertRegionDisappearing = async (regionProvider, message, retryAction, options) => {
|
||||
const isDisappeared = await waitForRegionDisappear(regionProvider, retryAction, options);
|
||||
if (!isDisappeared) {
|
||||
throw new Error(message);
|
||||
@@ -41,7 +41,7 @@ var assertRegionDisappearing = async (regionProvider, message, retryAction, opti
|
||||
};
|
||||
|
||||
// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/ocr.js
|
||||
var findFirst = (ir, ro, predicate) => {
|
||||
const findFirst = (ir, ro, predicate) => {
|
||||
const candidates = ir.findMulti(ro);
|
||||
for (let i = 0; i < candidates.count; i++) {
|
||||
if (predicate(candidates[i]))
|
||||
@@ -49,7 +49,7 @@ var findFirst = (ir, ro, predicate) => {
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
var findImageWithinBounds = (path, x, y, w, h) => {
|
||||
const findImageWithinBounds = (path, x, y, w, h) => {
|
||||
try {
|
||||
const ir = captureGameRegion();
|
||||
const ro = RecognitionObject.templateMatch(file.readImageMatSync(path), x, y, w, h);
|
||||
@@ -58,7 +58,7 @@ var findImageWithinBounds = (path, x, y, w, h) => {
|
||||
err?.message && log.warn(`${err.message}`);
|
||||
}
|
||||
};
|
||||
var findText = (text, options) => {
|
||||
const findText = (text, options) => {
|
||||
const { ignoreCase = true, contains = false } = options || {};
|
||||
const searchText = ignoreCase ? text.toLowerCase() : text;
|
||||
const ir = captureGameRegion();
|
||||
@@ -69,7 +69,7 @@ var findText = (text, options) => {
|
||||
return isMatch && region.isExist();
|
||||
});
|
||||
};
|
||||
var findTextWithinBounds = (text, x, y, w, h, options) => {
|
||||
const findTextWithinBounds = (text, x, y, w, h, options) => {
|
||||
const { ignoreCase = true, contains = false } = options || {};
|
||||
const searchText = ignoreCase ? text.toLowerCase() : text;
|
||||
const ir = captureGameRegion();
|
||||
@@ -82,7 +82,7 @@ var findTextWithinBounds = (text, x, y, w, h, options) => {
|
||||
};
|
||||
|
||||
// node_modules/.pnpm/@bettergi+utils@0.1.1/node_modules/@bettergi/utils/dist/store.js
|
||||
var useStore = (name) => {
|
||||
const useStore = (name) => {
|
||||
const filePath = `store/${name}.json`;
|
||||
const obj = (() => {
|
||||
try {
|
||||
@@ -125,9 +125,9 @@ var useStore = (name) => {
|
||||
};
|
||||
|
||||
// src/misc.ts
|
||||
var findHeaderTitle = (title, contains) => findTextWithinBounds(title, 0, 0, 300, 95, { contains });
|
||||
var findBottomButton = (text, contains) => findTextWithinBounds(text, 960, 980, 960, 100, { contains });
|
||||
var getNextMonday4AM = () => {
|
||||
const findHeaderTitle = (title, contains) => findTextWithinBounds(title, 0, 0, 300, 95, { contains });
|
||||
const findBottomButton = (text, contains) => findTextWithinBounds(text, 960, 980, 960, 100, { contains });
|
||||
const getNextMonday4AM = () => {
|
||||
const now = /* @__PURE__ */ new Date();
|
||||
const result = new Date(now);
|
||||
result.setHours(4, 0, 0, 0);
|
||||
@@ -143,11 +143,12 @@ var getNextMonday4AM = () => {
|
||||
};
|
||||
|
||||
// src/lobby.ts
|
||||
var findMessageEnter = () => findImageWithinBounds("assets/Enter.png", 0, 1020, 960, 60);
|
||||
var findMessageEnter2 = () => findImageWithinBounds("assets/Enter2.png", 0, 1020, 960, 60);
|
||||
var findGotTeyvatButton = () => findTextWithinBounds("返回", 1500, 0, 300, 95, { contains: true });
|
||||
var isInLobby = () => findMessageEnter() !== void 0 || findMessageEnter2() !== void 0;
|
||||
var goToLobby = async () => {
|
||||
const findMessageEnter = () => findImageWithinBounds("assets/Enter.png", 0, 1020, 960, 60);
|
||||
const findMessageEnter2 = () => findImageWithinBounds("assets/Enter2.png", 0, 1020, 960, 60);
|
||||
const findExitButton = () => findImageWithinBounds("assets/Exit.png", 960, 0, 960, 540);
|
||||
const findGotTeyvatButton = () => findTextWithinBounds("返回", 1500, 0, 300, 95, { contains: true });
|
||||
const isInLobby = () => findMessageEnter() !== void 0 || findMessageEnter2() !== void 0;
|
||||
const goToLobby = async () => {
|
||||
const ok = await waitForAction(
|
||||
isInLobby,
|
||||
() => {
|
||||
@@ -157,7 +158,7 @@ var goToLobby = async () => {
|
||||
);
|
||||
if (!ok) throw new Error("返回大厅超时");
|
||||
};
|
||||
var goBackToTeyvat = async () => {
|
||||
const goBackToTeyvat = async () => {
|
||||
log.info("打开当前大厅...");
|
||||
await assertRegionAppearing(
|
||||
() => findHeaderTitle("大厅", true),
|
||||
@@ -180,7 +181,7 @@ var goBackToTeyvat = async () => {
|
||||
};
|
||||
|
||||
// src/room.ts
|
||||
var createRoom = async (room) => {
|
||||
const createRoom = async (room) => {
|
||||
log.info("打开人气奇域界面...");
|
||||
await assertRegionAppearing(
|
||||
() => findHeaderTitle("人气", true),
|
||||
@@ -200,6 +201,7 @@ var createRoom = async (room) => {
|
||||
}
|
||||
);
|
||||
log.info("粘贴奇域关卡文本: {room}", room);
|
||||
await sleep(1000);
|
||||
await assertRegionAppearing(
|
||||
() => findTextWithinBounds("清除", 0, 120, 1920, 60),
|
||||
"粘贴关卡文本超时",
|
||||
@@ -253,7 +255,7 @@ var createRoom = async (room) => {
|
||||
{ maxAttempts: 10 }
|
||||
);
|
||||
};
|
||||
var enterRoom = async (room) => {
|
||||
const enterRoom = async (room) => {
|
||||
const inLobby = isInLobby();
|
||||
if (inLobby) {
|
||||
const enterButton = findTextWithinBounds("房间", 1580, 110, 320, 390, {
|
||||
@@ -274,7 +276,7 @@ var enterRoom = async (room) => {
|
||||
log.info("当前不在房间内,创建房间...", room);
|
||||
await createRoom(room);
|
||||
};
|
||||
var startGame = async () => {
|
||||
const startGame = async () => {
|
||||
let outputCount = 0;
|
||||
await assertRegionAppearing(
|
||||
() => findBottomButton("大厅", true),
|
||||
@@ -304,8 +306,22 @@ var startGame = async () => {
|
||||
(async function() {
|
||||
setGameMetrics(1920, 1080, 1.5);
|
||||
await genshin.returnMainUi();
|
||||
|
||||
// 检查当前是否在房间内,如果是则先退回到大厅
|
||||
const inLobby = isInLobby();
|
||||
if (!inLobby) {
|
||||
log.info("检测到当前不在大厅,正在返回大厅...");
|
||||
try {
|
||||
await goToLobby();
|
||||
} catch (e) {
|
||||
log.warn("返回大厅失败,继续执行: " + (e.message || e));
|
||||
}
|
||||
}
|
||||
|
||||
const goToTeyvat = settings.goToTeyvat ?? true;
|
||||
const room = settings.room || "7070702264";
|
||||
const roomStr = settings.room || "7070702264";
|
||||
// 支持中英文逗号分割多个房间号
|
||||
const rooms = roomStr.split(/[,,]/).map(r => r.trim()).filter(r => r);
|
||||
const force = settings.force ?? false;
|
||||
const thisAttempts = Math.max(0, Number(settings.thisAttempts || "0"));
|
||||
const expWeeklyLimit = Math.max(1, Number(settings.expWeeklyLimit || "5000"));
|
||||
@@ -318,38 +334,130 @@ var startGame = async () => {
|
||||
store.weekly = { expGained: 0, attempts: 0 };
|
||||
store.nextWeek = getNextMonday4AM().getTime();
|
||||
}
|
||||
if (store.weekly.expGained >= expWeeklyLimit) {
|
||||
if (force) {
|
||||
log.warn("本周获取经验值已达上限,强制执行");
|
||||
} else {
|
||||
log.warn("本周获取经验值已达上限,跳过执行");
|
||||
return;
|
||||
|
||||
// 如果只有一个房间号,检查经验上限
|
||||
if (rooms.length === 1) {
|
||||
if (store.weekly.expGained >= expWeeklyLimit) {
|
||||
if (force) {
|
||||
log.warn("本周获取经验值已达上限,强制执行");
|
||||
} else {
|
||||
log.warn("本周获取经验值已达上限,跳过执行");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("检测到多个房间号,将忽略经验上限直接执行");
|
||||
}
|
||||
|
||||
// 如果指定了通关次数,不显示经验相关日志
|
||||
const isSpecifiedAttempts = thisAttempts > 0;
|
||||
|
||||
try {
|
||||
const expRemain = expWeeklyLimit - store.weekly.expGained;
|
||||
let attempts = Math.ceil(
|
||||
(expRemain > 0 ? expRemain : expWeeklyLimit) / expPerAttempt
|
||||
);
|
||||
if (thisAttempts > 0) attempts = thisAttempts;
|
||||
for (let i = 0; i < attempts; i++) {
|
||||
log.info(
|
||||
"[{c}/{t}]: 开始本周第 {num} 次奇域挑战...",
|
||||
i + 1,
|
||||
attempts,
|
||||
store.weekly.attempts + 1
|
||||
// 对每个房间号循环执行
|
||||
for (let roomIndex = 0; roomIndex < rooms.length; roomIndex++) {
|
||||
const room = rooms[roomIndex];
|
||||
log.info("开始处理房间 " + room + " (" + (roomIndex + 1) + "/" + rooms.length + ")");
|
||||
|
||||
const expRemain = expWeeklyLimit - store.weekly.expGained;
|
||||
let attempts = Math.ceil(
|
||||
(expRemain > 0 ? expRemain : expWeeklyLimit) / expPerAttempt
|
||||
);
|
||||
await enterRoom(room);
|
||||
await startGame();
|
||||
store.weekly.attempts += 1;
|
||||
store.weekly.expGained += expPerAttempt;
|
||||
if (store.weekly.expGained >= expWeeklyLimit && !force) {
|
||||
log.warn("本周获取经验值已达上限,停止执行");
|
||||
break;
|
||||
if (thisAttempts > 0) attempts = thisAttempts;
|
||||
|
||||
// 对该房间执行指定次数
|
||||
for (let i = 0; i < attempts; i++) {
|
||||
// 多房间模式时忽略经验上限检查
|
||||
if (rooms.length === 1 && !isSpecifiedAttempts) {
|
||||
// 单房间模式且未指定次数:检查是否达到经验上限(仅第一次跳过,其他由内部判断)
|
||||
if (i === 0 && store.weekly.expGained >= expWeeklyLimit && !force) {
|
||||
log.warn("本周获取经验值已达上限,跳过该房间");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 首次执行时,先退出房间
|
||||
if (i === 0) {
|
||||
const inLobby = isInLobby();
|
||||
if (inLobby) {
|
||||
const enterButton = findTextWithinBounds("房间", 1580, 110, 320, 390, {
|
||||
contains: true
|
||||
});
|
||||
if (enterButton) {
|
||||
log.info("首次执行,先退出已有房间...");
|
||||
await sleep(2000);
|
||||
// 进入房间
|
||||
keyPress("P");
|
||||
await sleep(3000);
|
||||
// 等待房间界面出现
|
||||
await assertRegionAppearing(
|
||||
() => findHeaderTitle("房间", true),
|
||||
"等待进入房间超时"
|
||||
);
|
||||
// 点击退出按钮
|
||||
const exitBtn = findExitButton();
|
||||
if (exitBtn) {
|
||||
log.info("找到退出按钮,点击退出...");
|
||||
exitBtn.click();
|
||||
await sleep(2000);
|
||||
// 等待弹窗出现并点击"确认"
|
||||
const confirmBtn = findText("确认");
|
||||
if (confirmBtn && confirmBtn.isExist && confirmBtn.isExist()) {
|
||||
confirmBtn.click();
|
||||
await sleep(1000);
|
||||
} else if (confirmBtn) {
|
||||
confirmBtn.click();
|
||||
await sleep(1000);
|
||||
}
|
||||
} else {
|
||||
log.warn("未找到退出按钮");
|
||||
}
|
||||
// 确认已返回大厅
|
||||
const backToLobby = await waitForAction(
|
||||
isInLobby,
|
||||
null,
|
||||
{maxAttempts: 30, retryInterval: 500}
|
||||
);
|
||||
if (backToLobby) {
|
||||
log.info("已成功退出已有房间");
|
||||
} else {
|
||||
log.warn("退出房间超时,但继续执行");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isSpecifiedAttempts) {
|
||||
log.info(
|
||||
"房间 {room}: [{c}/{t}] 开始第 {num} 次奇域挑战...",
|
||||
room,
|
||||
i + 1,
|
||||
attempts,
|
||||
i + 1
|
||||
);
|
||||
} else {
|
||||
log.info(
|
||||
"房间 {room}: [{c}/{t}] 开始本周第 {num} 次奇域挑战...",
|
||||
room,
|
||||
i + 1,
|
||||
attempts,
|
||||
store.weekly.attempts + 1
|
||||
);
|
||||
}
|
||||
|
||||
await enterRoom(room);
|
||||
await startGame();
|
||||
store.weekly.attempts += 1;
|
||||
store.weekly.expGained += expPerAttempt;
|
||||
|
||||
// 单房间模式且未指定次数时检查经验上限
|
||||
if (rooms.length === 1 && !isSpecifiedAttempts && store.weekly.expGained >= expWeeklyLimit && !force) {
|
||||
log.warn("本周获取经验值已达上限,停止执行");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log.error("脚本执行出错: {error}", { error: e.message || e });
|
||||
log.error("脚本执行出错: " + (e.message || e));
|
||||
await genshin.returnMainUi();
|
||||
}
|
||||
if (goToTeyvat) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "千星奇域每周刷取经验值",
|
||||
"version": "0.1.3",
|
||||
"version": "0.2",
|
||||
"bgi_version": "0.52.0",
|
||||
"description": "千星奇域每周刷取经验值",
|
||||
"authors": [
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "room",
|
||||
"label": "奇域关卡关键词或关卡GUID",
|
||||
"label": "奇域关卡关键词或关卡GUID\n(支持多个id,用中文或英文逗号隔开)",
|
||||
"default": "7070702264"
|
||||
},
|
||||
{
|
||||
@@ -21,7 +21,7 @@
|
||||
"type": "input-text",
|
||||
"name": "thisAttempts",
|
||||
"label": "指定通关次数",
|
||||
"default": ""
|
||||
"default": "0"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
|
||||
Reference in New Issue
Block a user