chore(js): 更新图片资源适应高分辨率 (#2721)
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 813 B |
@@ -1,6 +1,6 @@
|
||||
import { __name } from "./rolldown-runtime.js";
|
||||
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/workflow.js
|
||||
//#region node_modules/@bettergi/utils/dist/workflow.js
|
||||
/** 默认最大重试次数 */
|
||||
const defaultMaxAttempts = 5;
|
||||
/** 默认重试间隔(毫秒) */
|
||||
@@ -61,7 +61,7 @@ const waitForRegionDisappear = async (regionProvider, retryAction, options) => {
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/asserts.js
|
||||
//#region node_modules/@bettergi/utils/dist/asserts.js
|
||||
/**
|
||||
* 断言某个区域即将出现,否则抛出异常
|
||||
* @param regionProvider 返回区域的函数
|
||||
@@ -85,7 +85,7 @@ const assertRegionDisappearing = async (regionProvider, message, retryAction, op
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/exception.js
|
||||
//#region node_modules/@bettergi/utils/dist/exception.js
|
||||
/**
|
||||
* 获取错误信息字符串
|
||||
* @param err 异常对象
|
||||
@@ -104,7 +104,7 @@ const isHostException = (err) => {
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/mouse.js
|
||||
//#region node_modules/@bettergi/utils/dist/mouse.js
|
||||
/** 使用回放脚本模拟滚动 */
|
||||
const simulateScroll = async (wheelDelta, times) => {
|
||||
const script = {
|
||||
@@ -144,7 +144,10 @@ const mouseScrollDownLines = (lines, lineHeight = 175) => {
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/ocr.js
|
||||
//#region node_modules/@bettergi/utils/dist/ocr.js
|
||||
const scaleTo1080P = (n) => {
|
||||
return genshin.scaleTo1080PRatio <= 1 ? n : Math.floor(n / genshin.scaleTo1080PRatio);
|
||||
};
|
||||
/**
|
||||
* 在指定区域内搜索图片
|
||||
* @param image 图片路径 或 图片Mat
|
||||
@@ -223,31 +226,30 @@ const findTextWithinBounds = (text, x, y, w, h, options, config = {}) => {
|
||||
* @param condition 查找条件
|
||||
* @param listView 列表视图参数
|
||||
* @param retryOptions 重试选项
|
||||
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
||||
* @param threshold 采样区域匹配阈值(默认:0.9)
|
||||
* @param threshold 列表视图变化匹配阈值(默认:0.9)
|
||||
* @returns 如果找到匹配的区域,则返回该区域,否则返回 undefined
|
||||
*/
|
||||
const findWithinListView = async (condition, listView, retryOptions, sampling, threshold = 0.9) => {
|
||||
const findWithinListView = async (condition, listView, retryOptions, threshold = 0.9) => {
|
||||
const { x, y, w, h, lineHeight, scrollLines = 1, paddingX = 10, paddingY = 10 } = listView;
|
||||
const { maxAttempts = 99, retryInterval = 1200 } = retryOptions || {};
|
||||
sampling ??= (r) => r.deriveCrop(1, r.height * 0.5, r.width - 1, r.height * 0.5);
|
||||
const captureListViewRegion = () => captureGameRegion().deriveCrop(x, y, w, h);
|
||||
const isReachedBottom = (() => {
|
||||
let captured;
|
||||
let lastCaptured;
|
||||
return () => {
|
||||
const newRegion = captureListViewRegion();
|
||||
if (!newRegion?.isExist()) return true;
|
||||
try {
|
||||
captured = captureListViewRegion();
|
||||
if (!lastCaptured) return false;
|
||||
const oldRegion = sampling(lastCaptured);
|
||||
if (!oldRegion?.isExist()) return true;
|
||||
const ro = RecognitionObject.templateMatch(oldRegion.srcMat);
|
||||
const lc = lastCaptured.deriveCrop(1, 1, lastCaptured.width - 2, lastCaptured.height - 2);
|
||||
const ro = RecognitionObject.templateMatch(lc.srcMat);
|
||||
ro.threshold = threshold;
|
||||
ro.use3Channels = true;
|
||||
ro.initTemplate();
|
||||
return newRegion.find(ro)?.isExist();
|
||||
return captured.find(ro).isExist();
|
||||
} catch {
|
||||
return true;
|
||||
} finally {
|
||||
lastCaptured = newRegion;
|
||||
lastCaptured = captured;
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -259,7 +261,7 @@ const findWithinListView = async (condition, listView, retryOptions, sampling, t
|
||||
},
|
||||
async () => {
|
||||
moveMouseTo(x + w - paddingX, y + paddingY);
|
||||
await sleep(50);
|
||||
await sleep(200);
|
||||
await mouseScrollDownLines(scrollLines, lineHeight);
|
||||
},
|
||||
{
|
||||
@@ -269,14 +271,9 @@ const findWithinListView = async (condition, listView, retryOptions, sampling, t
|
||||
);
|
||||
if (targetRegion?.isExist()) {
|
||||
const { item1, item2 } = targetRegion.convertPositionToGameCaptureRegion(0, 0);
|
||||
const scale = genshin.width / 1920;
|
||||
const [x$1, y$1] = [
|
||||
Math.floor(scale <= 1 ? item1 : item1 / scale),
|
||||
Math.floor(scale <= 1 ? item2 : item2 / scale),
|
||||
];
|
||||
Object.assign(targetRegion, {
|
||||
x: x$1,
|
||||
y: y$1,
|
||||
x: scaleTo1080P(item1),
|
||||
y: scaleTo1080P(item2),
|
||||
});
|
||||
return targetRegion;
|
||||
}
|
||||
@@ -288,8 +285,7 @@ const findWithinListView = async (condition, listView, retryOptions, sampling, t
|
||||
* @param matchOptions 搜索选项
|
||||
* @param retryOptions 重试选项
|
||||
* @param config 识别对象配置
|
||||
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
||||
* @param threshold 采样区域匹配阈值(默认:0.9)
|
||||
* @param threshold 列表视图变化匹配阈值(默认:0.9)
|
||||
* @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
|
||||
*/
|
||||
const findTextWithinListView = async (
|
||||
@@ -298,7 +294,6 @@ const findTextWithinListView = async (
|
||||
matchOptions,
|
||||
retryOptions,
|
||||
config = {},
|
||||
sampling,
|
||||
threshold = 0.9,
|
||||
) => {
|
||||
const ro = RecognitionObject.ocrThis;
|
||||
@@ -311,13 +306,12 @@ const findTextWithinListView = async (
|
||||
},
|
||||
listView,
|
||||
retryOptions,
|
||||
sampling,
|
||||
threshold,
|
||||
);
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/misc.js
|
||||
//#region node_modules/@bettergi/utils/dist/misc.js
|
||||
/**
|
||||
* 深度合并多个对象
|
||||
* @param objects 多个对象
|
||||
@@ -335,7 +329,7 @@ const deepMerge = (...objects) => {
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/time.js
|
||||
//#region node_modules/@bettergi/utils/dist/time.js
|
||||
/**
|
||||
* 获取下一个(含当日)凌晨4点的时间
|
||||
*/
|
||||
@@ -393,7 +387,7 @@ const formatDurationAsReadable = (duration) => {
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/progress.js
|
||||
//#region node_modules/@bettergi/utils/dist/progress.js
|
||||
/** 进度追踪器 */
|
||||
var ProgressTracker = class {
|
||||
total = 0;
|
||||
@@ -466,7 +460,7 @@ var ProgressTracker = class {
|
||||
};
|
||||
|
||||
//#endregion
|
||||
//#region node_modules/.pnpm/@bettergi+utils@0.1.27/node_modules/@bettergi/utils/dist/store.js
|
||||
//#region node_modules/@bettergi/utils/dist/store.js
|
||||
/**
|
||||
* 创建一个持久化存储对象,用于管理应用状态数据
|
||||
* 该函数会创建一个代理对象,对该对象的所有属性的修改都会自动同步到相应的JSON文件(脚本的 `store` 目录下)中。
|
||||
@@ -475,7 +469,7 @@ var ProgressTracker = class {
|
||||
*/
|
||||
const useStore = (name) => {
|
||||
const filePath = `store/${name}.json`;
|
||||
const obj = (() => {
|
||||
const storeData = (() => {
|
||||
try {
|
||||
if (
|
||||
![...file.readPathSync("store")].map((path) => path.replace(/\\/g, "/")).includes(filePath)
|
||||
@@ -487,34 +481,34 @@ const useStore = (name) => {
|
||||
return {};
|
||||
}
|
||||
})();
|
||||
const createProxy = (target, parentPath = []) => {
|
||||
if (typeof target !== "object" || target === null) return target;
|
||||
return new Proxy(target, {
|
||||
get: (target$1, key) => {
|
||||
const value = Reflect.get(target$1, key);
|
||||
const createProxy = (targetObject, parentPath = []) => {
|
||||
if (typeof targetObject !== "object" || targetObject === null) return targetObject;
|
||||
return new Proxy(targetObject, {
|
||||
get: (target, key) => {
|
||||
const value = Reflect.get(target, key);
|
||||
return typeof value === "object" && value !== null
|
||||
? createProxy(value, [...parentPath, key])
|
||||
: value;
|
||||
},
|
||||
set: (target$1, key, value) => {
|
||||
const success = Reflect.set(target$1, key, value);
|
||||
set: (target, key, value) => {
|
||||
const success = Reflect.set(target, key, value);
|
||||
if (success)
|
||||
Promise.resolve().then(() => {
|
||||
file.writeTextSync(filePath, JSON.stringify(obj, null, 2));
|
||||
file.writeTextSync(filePath, JSON.stringify(storeData, null, 2));
|
||||
});
|
||||
return success;
|
||||
},
|
||||
deleteProperty: (target$1, key) => {
|
||||
const success = Reflect.deleteProperty(target$1, key);
|
||||
deleteProperty: (target, key) => {
|
||||
const success = Reflect.deleteProperty(target, key);
|
||||
if (success)
|
||||
Promise.resolve().then(() => {
|
||||
file.writeTextSync(filePath, JSON.stringify(obj, null, 2));
|
||||
file.writeTextSync(filePath, JSON.stringify(storeData, null, 2));
|
||||
});
|
||||
return success;
|
||||
},
|
||||
});
|
||||
};
|
||||
return createProxy(obj);
|
||||
return createProxy(storeData);
|
||||
};
|
||||
/**
|
||||
* 创建一个带有默认值的持久化存储对象,用于管理应用状态数据
|
||||
|
||||
@@ -28,7 +28,7 @@ const findBottomBtnText = (text, contains) => {
|
||||
const findCloseDialog = () => {
|
||||
const iro = findImageWithinBounds("assets/UI_BtnIcon_Close.png", 410, 160, 1100, 660, {
|
||||
useMask: true,
|
||||
threshold: 0.7,
|
||||
threshold: 0.8,
|
||||
});
|
||||
iro?.drawSelf("group_img");
|
||||
return iro;
|
||||
@@ -41,20 +41,11 @@ const clickToContinue = () => {
|
||||
const findUidText = () => {
|
||||
return findTextWithinBounds("UID", 1620, 1050, 300, 30, { contains: true });
|
||||
};
|
||||
//! 查找元素视野按钮(判断处于大世界条件一)
|
||||
//! 查找元素视野按钮(判断处于大世界)
|
||||
const findElementViewBtn = () => {
|
||||
const iro = findImageWithinBounds("assets/UI_BtnIcon_ElementView.png", 0, 0, 500, 80, {
|
||||
useMask: true,
|
||||
threshold: 0.85,
|
||||
});
|
||||
iro?.drawSelf("group_img");
|
||||
return iro;
|
||||
};
|
||||
//! 查找推荐奇域按钮(判断处于大世界条件二)
|
||||
const findBeyondRecommendBtn = () => {
|
||||
const iro = findImageWithinBounds("assets/UI_BtnIcon_Beyond_Recommend.png", 960, 0, 960, 80, {
|
||||
useMask: true,
|
||||
threshold: 0.75,
|
||||
threshold: 0.8,
|
||||
});
|
||||
iro?.drawSelf("group_img");
|
||||
return iro;
|
||||
@@ -63,7 +54,7 @@ const findBeyondRecommendBtn = () => {
|
||||
const findBeyondHallBtn = () => {
|
||||
const iro = findImageWithinBounds("assets/UI_BtnIcon_Beyond_Hall.png", 200, 0, 150, 100, {
|
||||
useMask: true,
|
||||
threshold: 0.75,
|
||||
threshold: 0.8,
|
||||
});
|
||||
iro?.drawSelf("group_img");
|
||||
return iro;
|
||||
@@ -175,7 +166,8 @@ const findDeleteStageSaveBtn = () => {
|
||||
//! 关卡:查找关卡退出按钮
|
||||
const findStageEscBtn = () => {
|
||||
const iro = findImageWithinBounds("assets/UI_Icon_Leave.png", 0, 0, 100, 100, {
|
||||
threshold: 0.75,
|
||||
useMask: true,
|
||||
threshold: 0.8,
|
||||
});
|
||||
iro?.drawSelf("group_img");
|
||||
return iro;
|
||||
@@ -216,7 +208,7 @@ const findFetchRewardBtn = () => {
|
||||
{
|
||||
useMask: true,
|
||||
use3Channels: true,
|
||||
threshold: 0.9,
|
||||
threshold: 0.8,
|
||||
},
|
||||
);
|
||||
iro?.drawSelf("group_img");
|
||||
@@ -233,7 +225,6 @@ export {
|
||||
findBeyondBattlepassPopup,
|
||||
findBeyondFavoritesBtn,
|
||||
findBeyondHallBtn,
|
||||
findBeyondRecommendBtn,
|
||||
findBottomBtnText,
|
||||
findClearInputBtn,
|
||||
findCloseDialog,
|
||||
|
||||
@@ -3,7 +3,6 @@ import { assertRegionAppearing, waitForAction } from "../@bettergi+utils.js";
|
||||
import { userConfig } from "../constants/config.js";
|
||||
import {
|
||||
findBeyondHallBtn,
|
||||
findBeyondRecommendBtn,
|
||||
findConfirmBtn,
|
||||
findElementViewBtn,
|
||||
findGotTeyvatBtn,
|
||||
@@ -14,9 +13,7 @@ import {
|
||||
//! 判断是否处于奇域大厅
|
||||
const isInLobby = () => findBeyondHallBtn() !== void 0;
|
||||
//! 判断是否处于提瓦特大陆
|
||||
const isInTeyvat = () => {
|
||||
return findBeyondRecommendBtn() !== void 0 && findElementViewBtn() !== void 0;
|
||||
};
|
||||
const isInTeyvat = () => findElementViewBtn() !== void 0;
|
||||
//! 退出大厅返回提瓦特大陆
|
||||
const exitLobbyToTeyvat = async () => {
|
||||
if (!userConfig.goToTeyvat) return;
|
||||
|
||||
@@ -59,10 +59,15 @@ const fetchBattlepassExp = async () => {
|
||||
async () => {
|
||||
//! 重复确认,防止误领纪游奖励(部件礼箱会卡流程)而不是经验
|
||||
if (findHeaderTitle("任务", true)) {
|
||||
findBottomBtnText("领取", true)?.click();
|
||||
clickToContinue();
|
||||
await sleep(1e3);
|
||||
clickToContinue();
|
||||
const reward = findBottomBtnText("领取", true);
|
||||
if (reward) {
|
||||
reward.click();
|
||||
await sleep(50);
|
||||
reward.click();
|
||||
clickToContinue();
|
||||
await sleep(1e3);
|
||||
clickToContinue();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -72,16 +77,28 @@ const fetchBattlepassExp = async () => {
|
||||
);
|
||||
await genshin.returnMainUi();
|
||||
};
|
||||
//! 点击领取奖励按钮
|
||||
const clickClaimRewardBtn = async () => {
|
||||
const reward = findFetchRewardBtn();
|
||||
if (reward) {
|
||||
reward.click();
|
||||
await sleep(50);
|
||||
reward.click();
|
||||
clickToContinue();
|
||||
await sleep(1e3);
|
||||
clickToContinue();
|
||||
}
|
||||
};
|
||||
//! 领取绮衣珍赏奖励
|
||||
const fetchRaimentCollection = async () => {
|
||||
//! 打开绮衣珍赏
|
||||
await assertRegionAppearing(
|
||||
() => findHeaderTitle("珍赏", true),
|
||||
() => findHeaderTitle("绮衣", true) || findHeaderTitle("珍赏", true),
|
||||
"打开绮衣珍赏超时,活动未轮换/已结束",
|
||||
async () => {
|
||||
keyPress("VK_F6");
|
||||
await sleep(2e3);
|
||||
if (findHeaderTitle("珍赏", true) === void 0) keyPress("VK_Q");
|
||||
if (!findHeaderTitle("绮衣", true) && !findHeaderTitle("珍赏", true)) keyPress("VK_Q");
|
||||
},
|
||||
{
|
||||
maxAttempts: 5,
|
||||
@@ -93,13 +110,7 @@ const fetchRaimentCollection = async () => {
|
||||
findFetchRewardBtn,
|
||||
"领取绮衣珍赏奖励超时",
|
||||
async () => {
|
||||
const reward = findFetchRewardBtn();
|
||||
if (reward) {
|
||||
reward.click();
|
||||
clickToContinue();
|
||||
await sleep(1e3);
|
||||
clickToContinue();
|
||||
}
|
||||
await clickClaimRewardBtn();
|
||||
},
|
||||
{
|
||||
maxAttempts: 5,
|
||||
@@ -129,13 +140,7 @@ const fetchInvitationToWonderland = async () => {
|
||||
findFetchRewardBtn,
|
||||
"领取妙思觅索奖励超时",
|
||||
async () => {
|
||||
const reward = findFetchRewardBtn();
|
||||
if (reward) {
|
||||
reward.click();
|
||||
clickToContinue();
|
||||
await sleep(1e3);
|
||||
clickToContinue();
|
||||
}
|
||||
await clickClaimRewardBtn();
|
||||
},
|
||||
{
|
||||
maxAttempts: 5,
|
||||
|
||||
@@ -67,9 +67,9 @@ const playStage = async (playbacks) => {
|
||||
};
|
||||
//! 执行通关回放文件(随机抽取)
|
||||
const execStagePlayback = async (playbacks) => {
|
||||
const file$1 = playbacks[Math.floor(Math.random() * playbacks.length)];
|
||||
log.info("执行通关回放文件: {file}", file$1);
|
||||
await keyMouseScript.runFile(file$1);
|
||||
const file = playbacks[Math.floor(Math.random() * playbacks.length)];
|
||||
log.info("执行通关回放文件: {file}", file);
|
||||
await keyMouseScript.runFile(file);
|
||||
};
|
||||
//! 退出关卡
|
||||
const exitStage = async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "千星奇域·每周经验刷取(回放通关版)",
|
||||
"version": "0.1.9",
|
||||
"version": "0.1.10",
|
||||
"bgi_version": "0.54.0",
|
||||
"description": "千星奇域·每周经验刷取(回放通关版)",
|
||||
"authors": [
|
||||
@@ -11,7 +11,7 @@
|
||||
},
|
||||
{
|
||||
"name": "躁动的氨气",
|
||||
"link": "https://github.com/A-Little-AnQi"
|
||||
"link": "https://github.com/zaodonganqi"
|
||||
}
|
||||
],
|
||||
"main": "main.js",
|
||||
|
||||