mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-29 23:19:59 +08:00
* refactor(ActivitySwitchNotice): 优化通知配置构建逻辑 - 将 configNotice 变量改为 let 声明以支持动态更新 - 新增 async 函数 buildConfigNotice 用于构建通知配置 - 在 sendNotice 函数中调用 buildConfigNotice 确保配置最新 - 在 sendText 函数中添加 buildConfigNotice 调用保证配置同步 * refactor(utils): 导出工具函数并移除全局挂载 - 将 activity.js 中的 activityMain 函数改为导出函数 - 将 campaignArea.js 中的 ocrDailyCommission、ocrWeeklyCount、campaignAreaMain、dailyCommissionMain 函数改为导出函数 - 将 mapMission.js 中的 ocrMapMission、openMap、mapMission 函数改为导出函数 - 将 tool.js 中的 findTextAndClick、getDayOfWeek 函数改为导出函数 - 将 uid.js 中的 saveOnlyNumber、ocrUID、compareUid、checkUid、check 函数改为导出函数 - 将 ws.js 中的 send、sendText 函数改为导出函数 - 移除所有 utils 文件中对 this 对象的挂载操作 - 在 main.js 中导入新的工具函数并移除重复定义的函数 * fix(ActivitySwitchNotice): 修复圣遗物空间检查功能中的显示和逻辑问题 - 修正圣遗物空间不足提醒消息中的标点符号格式 - 修复圣遗物空间阈值错误日志中的数字格式 - 移除不必要的延时操作以优化执行效率 - 调整代码结构以提高运行性能 fix(ActivitySwitchNotice): 修复圣遗物空间检查功能中的显示和逻辑问题 - 修正圣遗物空间不足提醒消息中的标点符号格式 - 修复圣遗物空间阈值错误日志中的数字格式 - 移除不必要的延时操作以优化执行效率 - 调整代码结构以提高运行性能 refactor(ActivitySwitchNotice): 优化圣遗物检查功能中的延迟配置 - 将硬编码的延迟时间替换为可配置的常量 - 统一延迟时间管理,提高代码可维护性 - 保持原有功能逻辑不变的情况下提升代码质量 feat(ActivitySwitchNotice): 更新版本并新增圣遗物空间检测提醒功能 - 将插件版本从 0.1.3 更新至 0.1.5 - 新增圣遗物剩余空间检测提醒功能 - 在版本历史中添加 0.1.5 版本记录 fix(ActivitySwitchNotice): 修复圣遗物剩余空间阈值解析错误 - 添加 try-catch 块处理 parseInt 异常情况 - 当阈值格式错误时默认使用 400 的阈值 - 添加警告日志记录格式错误的阈值设置 - 确保程序在无效配置下仍能正常运行 feat(bag): 添加圣遗物背包空间检查功能 - 新增 HolyRelics.js 工具模块实现圣遗物数量检查逻辑 - 集成 OCR 识别功能用于获取圣遗物数量信息 - 添加背包空间不足提醒功能,可自定义阈值 - 在 main.js 中集成圣遗物检查流程 - 添加新的配置选项包括打开背包按键和圣遗物阈值设置 - 扩展工具类增加 findText、findImg 和 OcrFind 等通用识别方法 - 实现自动打开背包并处理过期物品弹窗功能 * fix(HolyRelics): 修复圣遗物背包空间检测功能 - 添加了进入圣遗物背包的点击状态验证,避免无法进入时继续执行 - 增强了OCR文本解析逻辑,添加了字符串分割长度验证和数值解析校验 - 优化了阈值参数解析,在main.js中添加了更安全的数值转换和错误处理 - 修复了工具函数中资源释放问题,在isInMainUI函数中使用try-finally确保资源被正确释放 - 更新了提醒消息文本,明确标识阈值设置参数
351 lines
10 KiB
JavaScript
351 lines
10 KiB
JavaScript
/**
|
||
* 通用找文本(OCR)
|
||
* @param {string|string[]} text 目标文本(单个文本或文本列表,列表时需全部匹配)
|
||
* @param {number} [x=0] OCR 区域左上角 X
|
||
* @param {number} [y=0] OCR 区域左上角 Y
|
||
* @param {number} [w=1920] OCR 区域宽度
|
||
* @param {number} [h=1080] OCR 区域高度
|
||
* @param {number} [attempts=5] OCR 尝试次数
|
||
* @param {number} [interval=50] 每次 OCR 之间的等待间隔(毫秒)
|
||
*
|
||
* @returns
|
||
* - RecognitionResult | null
|
||
*/
|
||
export async function findText(
|
||
text,
|
||
x = 0,
|
||
y = 0,
|
||
w = 1920,
|
||
h = 1080,
|
||
attempts = 5,
|
||
interval = 50
|
||
) {
|
||
const keywords = (Array.isArray(text) ? text : [text])
|
||
.map(t => t.toLowerCase());
|
||
|
||
for (let i = 0; i < attempts; i++) {
|
||
const gameRegion = captureGameRegion();
|
||
try {
|
||
const ro = RecognitionObject.Ocr(x, y, w, h);
|
||
const results = gameRegion.findMulti(ro);
|
||
|
||
for (let j = 0; j < results.count; j++) {
|
||
const res = results[j];
|
||
if (!res.isExist() || !res.text) continue;
|
||
|
||
const ocrText = res.text.toLowerCase();
|
||
const matched = keywords.every(k => ocrText.includes(k));
|
||
if (matched) {
|
||
return res;
|
||
}
|
||
}
|
||
} finally {
|
||
gameRegion.dispose();
|
||
}
|
||
|
||
await sleep(interval);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 通用找文本并点击(OCR)
|
||
* @param {string} text 目标文本(单个文本)
|
||
* @param {number} [x=0] OCR 区域左上角 X
|
||
* @param {number} [y=0] OCR 区域左上角 Y
|
||
* @param {number} [w=1920] OCR 区域宽度
|
||
* @param {number} [h=1080] OCR 区域高度
|
||
* @param {number} [attempts=5] OCR 尝试次数
|
||
* @param {number} [interval=50] 每次 OCR 之间的等待间隔(毫秒)
|
||
* @param {number} [preClickDelay=50] 点击前等待时间(毫秒)
|
||
* @param {number} [postClickDelay=50] 点击后等待时间(毫秒)
|
||
*
|
||
* @returns
|
||
* - RecognitionResult | null
|
||
*/
|
||
export async function findTextAndClick(
|
||
text,
|
||
x = 0,
|
||
y = 0,
|
||
w = 1920,
|
||
h = 1080,
|
||
attempts = 5,
|
||
interval = 50,
|
||
preClickDelay = 50,
|
||
postClickDelay = 50
|
||
) {
|
||
const keyword = text.toLowerCase();
|
||
|
||
for (let i = 0; i < attempts; i++) {
|
||
const gameRegion = captureGameRegion();
|
||
try {
|
||
const ro = RecognitionObject.Ocr(x, y, w, h);
|
||
const results = gameRegion.findMulti(ro);
|
||
|
||
for (let j = 0; j < results.count; j++) {
|
||
const res = results[j];
|
||
if (
|
||
res.isExist() &&
|
||
res.text &&
|
||
res.text.toLowerCase().includes(keyword)
|
||
) {
|
||
await sleep(preClickDelay);
|
||
res.click();
|
||
await sleep(postClickDelay);
|
||
return res;
|
||
}
|
||
}
|
||
} finally {
|
||
gameRegion.dispose();
|
||
}
|
||
|
||
await sleep(interval);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 通用找图/找RO(支持图片文件路径、Mat)
|
||
* @param {string|Mat} target 图片路径或已构造的 Mat
|
||
* @param {number} [x=0] 识别区域左上角 X
|
||
* @param {number} [y=0] 识别区域左上角 Y
|
||
* @param {number} [w=1920] 识别区域宽度
|
||
* @param {number} [h=1080] 识别区域高度
|
||
* @param {number} [timeout=1000] 识别时间上限(毫秒)
|
||
* @param {number} [interval=50] 每次识别之间的等待间隔(毫秒)
|
||
*
|
||
* @returns
|
||
* - RecognitionResult | null
|
||
*/
|
||
export async function findImg(
|
||
target,
|
||
x = 0,
|
||
y = 0,
|
||
w = 1920,
|
||
h = 1080,
|
||
timeout = 1000,
|
||
interval = 50
|
||
) {
|
||
const ro =
|
||
typeof target === 'string'
|
||
? RecognitionObject.TemplateMatch(
|
||
file.readImageMatSync(target),
|
||
x, y, w, h
|
||
)
|
||
: RecognitionObject.TemplateMatch(
|
||
target,
|
||
x, y, w, h
|
||
);
|
||
|
||
const start = Date.now();
|
||
|
||
while (Date.now() - start <= timeout) {
|
||
const gameRegion = captureGameRegion();
|
||
try {
|
||
const res = gameRegion.find(ro);
|
||
if (!res.isEmpty()) {
|
||
return res;
|
||
}
|
||
} catch (e) {
|
||
log.error(e.toString());
|
||
} finally {
|
||
gameRegion.dispose();
|
||
}
|
||
|
||
await sleep(interval);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
|
||
/**
|
||
* 通用找图并点击(支持图片文件路径、Mat)
|
||
* @param {string|Mat} target 图片路径或已构造的 Mat
|
||
* @param {number} [x=0] 识别区域左上角 X
|
||
* @param {number} [y=0] 识别区域左上角 Y
|
||
* @param {number} [w=1920] 识别区域宽度
|
||
* @param {number} [h=1080] 识别区域高度
|
||
* @param {number} [timeout=1000] 识别时间上限(毫秒)
|
||
* @param {number} [interval=50] 每次识别之间的等待间隔(毫秒)
|
||
* @param {number} [preClickDelay=50] 点击前等待时间(毫秒)
|
||
* @param {number} [postClickDelay=50] 点击后等待时间(毫秒)
|
||
*
|
||
* @returns
|
||
* - RecognitionResult | null
|
||
*/
|
||
export async function findImgAndClick(
|
||
target,
|
||
x = 0,
|
||
y = 0,
|
||
w = 1920,
|
||
h = 1080,
|
||
timeout = 1000,
|
||
interval = 50,
|
||
preClickDelay = 50,
|
||
postClickDelay = 50
|
||
) {
|
||
const ro =
|
||
typeof target === 'string'
|
||
? RecognitionObject.TemplateMatch(
|
||
file.readImageMatSync(target),
|
||
x, y, w, h
|
||
)
|
||
: RecognitionObject.TemplateMatch(
|
||
target,
|
||
x, y, w, h
|
||
);
|
||
|
||
const start = Date.now();
|
||
|
||
while (Date.now() - start <= timeout) {
|
||
const gameRegion = captureGameRegion();
|
||
try {
|
||
const res = gameRegion.find(ro);
|
||
if (!res.isEmpty()) {
|
||
await sleep(preClickDelay);
|
||
res.click();
|
||
await sleep(postClickDelay);
|
||
return res;
|
||
}
|
||
} finally {
|
||
gameRegion.dispose();
|
||
}
|
||
|
||
await sleep(interval);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
|
||
/**
|
||
* 使用OCR技术在指定区域内查找文本
|
||
* @param {number} x - 区域左上角x坐标
|
||
* @param {number} y - 区域左上角y坐标
|
||
* @param {number} width - 区域宽度
|
||
* @param {number} height - 区域高度
|
||
* @returns {Promise<Region|null>} 返回找到的文本,如果没有找到则返回null
|
||
*/
|
||
export async function OcrFind(x, y, width, height) {
|
||
let captureRegion = captureGameRegion(); // 获取游戏区域截图
|
||
try {
|
||
// 创建OCR识别对象,指定识别区域
|
||
const recognitionObject = RecognitionObject.Ocr(x, y, width, height);
|
||
// 在截图上执行OCR识别
|
||
const result = captureRegion.find(recognitionObject);
|
||
// 返回识别到的文本,如果未识别到则返回undefined
|
||
return result
|
||
} finally {
|
||
// 确保截图资源被正确释放,防止内存泄漏
|
||
if (captureRegion) {
|
||
captureRegion.dispose(); // 释放截图资源
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 使用OCR技术在指定区域内查找文本内容
|
||
* @param {number} x - 区域左上角x坐标
|
||
* @param {number} y - 区域左上角y坐标
|
||
* @param {number} width - 区域宽度
|
||
* @param {number} height - 区域高度
|
||
* @returns {Promise<Region[]>} 返回找到的文本内容数组
|
||
*/
|
||
export async function OcrFindList(x, y, width, height) {
|
||
let captureRegion = captureGameRegion(); // 获取游戏区域截图
|
||
try {
|
||
// 创建OCR识别对象,指定识别区域
|
||
const recognitionObject = RecognitionObject.Ocr(x, y, width, height);
|
||
// 在截图区域中查找多个匹配项
|
||
const resList = captureRegion.findMulti(recognitionObject);
|
||
return resList // 返回找到的文本列表
|
||
} finally {
|
||
// 确保释放截图资源,防止内存泄漏
|
||
if (captureRegion) {
|
||
captureRegion.dispose(); // 释放截图资源
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取当前日期的星期信息
|
||
* @param {boolean} [calibrationGameRefreshTime=true] 是否进行游戏刷新时间校准
|
||
* @returns {Object} 返回包含星期数字和星期名称的对象
|
||
*/
|
||
export async function getDayOfWeek(calibrationGameRefreshTime = true) {
|
||
// 获取当前日期对象
|
||
let today = new Date();//4点刷新 所以要减去4小时
|
||
if (calibrationGameRefreshTime) {
|
||
today.setHours(today.getHours() - 4); // 减去 4 小
|
||
}
|
||
// 获取当前日期是星期几(0代表星期日,1代表星期一,以此类推)
|
||
const day = today.getDay();
|
||
// 创建包含星期名称的数组
|
||
const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||
let weekDay = `${weekDays[day]}`;
|
||
|
||
log.debug(`今天是[{day}]`, day)
|
||
log.debug(`今天是[{weekDays}]`, weekDay)
|
||
// 返回包含星期数字和对应星期名称的对象
|
||
return {
|
||
day: day,
|
||
dayOfWeek: weekDay
|
||
}
|
||
}
|
||
|
||
// 判断是否在主界面的函数
|
||
export const isInMainUI = () => {
|
||
let captureRegion = captureGameRegion();
|
||
|
||
try {
|
||
const res = captureRegion.Find(RecognitionObject.TemplateMatch(
|
||
file.ReadImageMatSync("assets/paimon_menu.png"),
|
||
0,
|
||
0,
|
||
640,
|
||
216
|
||
));
|
||
return !res.isEmpty();
|
||
} finally {
|
||
if (captureRegion) {
|
||
captureRegion.dispose();
|
||
}
|
||
}
|
||
};
|
||
|
||
export async function toMainUi() {
|
||
let ms = 300
|
||
let index = 1
|
||
await sleep(ms);
|
||
while (!isInMainUI()) {
|
||
await sleep(ms);
|
||
await genshin.returnMainUi(); // 如果未启用,则返回游戏主界面
|
||
await sleep(ms);
|
||
if (index > 3) {
|
||
throw new Error(`多次尝试返回主界面失败`);
|
||
}
|
||
index += 1
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 打开背包(检测过期物品)
|
||
*/
|
||
export async function openBag() {
|
||
const openBagKey = settings.openBagKey || "B";
|
||
await toMainUi();
|
||
await keyPress(openBagKey);
|
||
await sleep(500);
|
||
const expiredText = await findText("物品过期", 870, 280, 170, 40, 2);
|
||
if (expiredText) {
|
||
log.info("检测到过期物品,关闭弹窗");
|
||
await sleep(500);
|
||
await click(980, 750);
|
||
}
|
||
await sleep(50);
|
||
}
|