mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-28 23:09:50 +08:00
main-asn (#3156)
* 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确保资源被正确释放 - 更新了提醒消息文本,明确标识阈值设置参数
This commit is contained in:
@@ -511,6 +511,9 @@ ActivitySwitchNotice/
|
||||
|
||||
## 版本历史
|
||||
|
||||
### 0.1.5 (2026-04-24)
|
||||
|
||||
- 新增圣遗物剩余空间检测提醒
|
||||
### 0.1.4 (2026-04-23)
|
||||
|
||||
- 单例模式 配置唯一实例
|
||||
|
||||
BIN
repo/js/ActivitySwitchNotice/assets/holyRelics.jpg
Normal file
BIN
repo/js/ActivitySwitchNotice/assets/holyRelics.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1,9 +1,12 @@
|
||||
import {checkHolyRelicsKey} from "./utils/HolyRelics";
|
||||
|
||||
let manifest = {};
|
||||
let manifest_json = "manifest.json";
|
||||
let configSettings = undefined
|
||||
import {mapMission} from "./utils/mapMission"
|
||||
import {dailyCommissionMain,campaignAreaMain} from "./utils/campaignArea"
|
||||
import {activityMain} from "./utils/activity"
|
||||
import {toMainUi,isInMainUI} from "./utils/tool"
|
||||
/**
|
||||
* 初始化设置函数
|
||||
* 从配置文件中读取设置信息并返回
|
||||
@@ -105,35 +108,6 @@ async function init() {
|
||||
log.debug("main 初始化完成");
|
||||
}
|
||||
|
||||
// 判断是否在主界面的函数
|
||||
const isInMainUI = () => {
|
||||
let captureRegion = captureGameRegion();
|
||||
let res = captureRegion.Find(RecognitionObject.TemplateMatch(
|
||||
file.ReadImageMatSync("assets/paimon_menu.png"),
|
||||
0,
|
||||
0,
|
||||
640,
|
||||
216
|
||||
));
|
||||
captureRegion.dispose();
|
||||
return !res.isEmpty();
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
(async function () {
|
||||
await init();
|
||||
if (settings.toMainUi) {
|
||||
@@ -159,6 +133,28 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
const checkHolyRelic=settings.checkHolyRelic||false
|
||||
if (checkHolyRelic) {
|
||||
const DEFAULT_THRESHOLD = 400
|
||||
const raw = settings.holyRelicsDiffCountThreshold
|
||||
let threshold = DEFAULT_THRESHOLD
|
||||
try {
|
||||
const digits = ('' + (raw ?? '')).replace(/[^0-9]/g, '').trim()
|
||||
const parsed = digits ? parseInt(digits, 10) : NaN
|
||||
threshold = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_THRESHOLD
|
||||
if (!Number.isFinite(parsed)) {
|
||||
log.warn(`圣遗物剩余空间阈值格式错误,默认 ${DEFAULT_THRESHOLD}`)
|
||||
}
|
||||
} catch (e) {
|
||||
log.warn(`圣遗物剩余空间阈值解析异常,默认 ${DEFAULT_THRESHOLD}: ${e.message}`)
|
||||
}
|
||||
try {
|
||||
await checkHolyRelicsKey(threshold)
|
||||
}finally {
|
||||
await toMainUi()
|
||||
}
|
||||
}
|
||||
|
||||
let openKey = true
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "活动期限/周本通知器",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.5",
|
||||
"description": "",
|
||||
"settings_ui": "settings.json",
|
||||
"main": "main.js",
|
||||
|
||||
@@ -98,6 +98,33 @@
|
||||
"label": "打开冒险之证按键(不填,默认:F1)",
|
||||
"default": "F1"
|
||||
},
|
||||
{
|
||||
"name": "openBagKey",
|
||||
"type": "input-text",
|
||||
"label": "打开背包按键(不填,默认:B)",
|
||||
"default": "B"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
{
|
||||
"name": "checkHolyRelic",
|
||||
"type": "checkbox",
|
||||
"label": "启用圣遗物空间提醒",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "holyRelicsDiffCountThreshold",
|
||||
"type": "input-text",
|
||||
"label": "圣遗物剩余空间阈值",
|
||||
"default": "400"
|
||||
},
|
||||
{
|
||||
"type": "separator"
|
||||
},
|
||||
|
||||
59
repo/js/ActivitySwitchNotice/utils/HolyRelics.js
Normal file
59
repo/js/ActivitySwitchNotice/utils/HolyRelics.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import {toMainUi, openBag, findImgAndClick, OcrFind, findText} from "./tool";
|
||||
import {sendText} from "./notice"
|
||||
|
||||
/**
|
||||
* 检查圣遗物背包中剩余空间是否达到阈值,如果达到阈值则发送提醒
|
||||
* @param {number} threshold - 圣遗物数量差阈值,默认为400
|
||||
*/
|
||||
export async function checkHolyRelicsKey(threshold = 400) {
|
||||
const ms = 300
|
||||
log.info("开始圣遗物数量检查") // 记录开始检查圣遗物数量
|
||||
// const threshold = settings.threshold || 100 // 注释掉的阈值设置代码
|
||||
await openBag() // 打开背包
|
||||
await sleep(ms)
|
||||
const textFind = await findText("圣遗物"); // 查找"圣遗物"文本
|
||||
log.debug("textFind:" + textFind) // 记录查找结果
|
||||
if (textFind === null) { // 如果未找到"圣遗物"文本
|
||||
await sleep(ms) // 等待1秒
|
||||
log.info("进入圣遗物背包") // 记录准备进入圣遗物背包
|
||||
// 点击圣遗物背包
|
||||
const clicked = await findImgAndClick('assets/holyRelics.jpg')
|
||||
if (!clicked) {
|
||||
log.error("未能点击进入圣遗物背包,终止检查")
|
||||
return
|
||||
} // 通过图片点击进入圣遗物背包
|
||||
}
|
||||
log.info("已进入圣遗物背包") // 记录已进入圣遗物背包
|
||||
await sleep(ms)
|
||||
const OcrText = await OcrFind(1612, 34, 192, 31); // 使用OCR识别指定区域的文本
|
||||
if (!(OcrText?.text)) { // 如果OCR识别失败
|
||||
log.error("识别异常") // 记录错误信息
|
||||
return // 返回,终止函数执行
|
||||
}
|
||||
const text = OcrText.text.trim() // 去除识别文本的前后空格
|
||||
const HolyRelics = text.replace(/[^0-9/]/g, '') // 只保留数字和斜杠
|
||||
const strings = HolyRelics.split('/', 2); // 按斜杠分割字符串
|
||||
if (strings.length < 2) {
|
||||
log.error(`圣遗物数量解析失败,OCR 原始文本:${text}`)
|
||||
return
|
||||
}
|
||||
const count = parseInt(strings[0], 10);// 解析当前数量
|
||||
const total = parseInt(strings[1], 10);// 解析总容量
|
||||
if (!Number.isFinite(count) || !Number.isFinite(total)) {
|
||||
log.error(`圣遗物数量解析异常,count=${count}, total=${total}, 原文本:${text}`)
|
||||
return
|
||||
}
|
||||
const diff = total - count // 计算剩余空间数量
|
||||
|
||||
log.debug(`text:${text}`) // 记录原始识别文本
|
||||
log.debug(`HolyRelics:${HolyRelics}`) // 记录处理后的文本
|
||||
log.debug(`count:${count}`) // 记录当前数量
|
||||
log.debug(`total:${total}`) // 记录总容量
|
||||
log.debug(`diff:${diff}`) // 记录剩余空间数量
|
||||
|
||||
if (diff <= threshold) { // 如果剩余空间小于等于阈值
|
||||
log.info(`背包圣遗物数量:${count}/${total},相差${diff}个,<=${threshold}个,提醒清理`) // 记录需要清理的信息
|
||||
// 发送提醒消息
|
||||
await sendText(`背包圣遗物 剩余空间不足(设置阈值):${threshold},剩余:${diff},请前往清理!`, "背包圣遗物剩余空间检查") // 发送提醒文本
|
||||
}
|
||||
}
|
||||
@@ -464,7 +464,7 @@ async function init() {
|
||||
/**
|
||||
* 活动主函数:扫描所有活动页面,识别剩余时间,最后统一发送通知
|
||||
*/
|
||||
async function activityMain(newActivityNotice = true) {
|
||||
export async function activityMain(newActivityNotice = true) {
|
||||
await init();
|
||||
const ms = 1000;
|
||||
await sleep(ms);
|
||||
@@ -781,9 +781,4 @@ async function init() {
|
||||
}
|
||||
}
|
||||
|
||||
// this.activityUtil = {
|
||||
// // config,
|
||||
// activityMain,
|
||||
// // OcrRemainingTime,
|
||||
// }
|
||||
export {activityMain}
|
||||
// export {activityMain}
|
||||
|
||||
@@ -35,7 +35,7 @@ const xyConfig = {
|
||||
* @param {Object} ocrRegion - OCR识别区域配置,默认为ocrRegionConfig.dailyCommission
|
||||
* @returns {Object} 返回包含每日委托和体力使用情况的对象
|
||||
*/
|
||||
async function ocrDailyCommission(ocrRegion = ocrRegionConfig.dailyCommission) {
|
||||
export async function ocrDailyCommission(ocrRegion = ocrRegionConfig.dailyCommission) {
|
||||
let captureRegion = captureGameRegion(); // 获取游戏区域截图
|
||||
try {
|
||||
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height); // 创建OCR识别对象
|
||||
@@ -74,7 +74,7 @@ async function ocrDailyCommission(ocrRegion = ocrRegionConfig.dailyCommission) {
|
||||
* @returns {Object} 返回包含周计数信息的JSON对象,包含text、total和count属性
|
||||
* @throws {Error} 当OCR识别失败时抛出错误
|
||||
*/
|
||||
async function ocrWeeklyCount(ocrRegion = ocrRegionConfig.weeklyCount) {
|
||||
export async function ocrWeeklyCount(ocrRegion = ocrRegionConfig.weeklyCount) {
|
||||
let captureRegion = captureGameRegion(); // 获取游戏区域截图
|
||||
try {
|
||||
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height); // 创建OCR识别对象
|
||||
@@ -104,37 +104,12 @@ async function ocrWeeklyCount(ocrRegion = ocrRegionConfig.weeklyCount) {
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 获取当前日期的星期信息
|
||||
// * @param {boolean} [calibrationGameRefreshTime=true] 是否进行游戏刷新时间校准
|
||||
// * @returns {Object} 返回包含星期数字和星期名称的对象
|
||||
// */
|
||||
// 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
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* 执行秘境征讨剩余次数提醒的主函数
|
||||
* 该函数会在每周日执行,检查秘境征讨的剩余次数并发送提醒
|
||||
*/
|
||||
async function campaignAreaMain(openKey = true) {
|
||||
export async function campaignAreaMain(openKey = true) {
|
||||
// 获取当前星期信息
|
||||
let dayOfWeek = await getDayOfWeek();
|
||||
// 如果不是周日(0代表周日),则直接返回
|
||||
@@ -184,7 +159,7 @@ async function campaignAreaMain(openKey = true) {
|
||||
* @param {boolean} openKey - 是否开启热键功能,默认为true
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function dailyCommissionMain(openKey = true) {
|
||||
export async function dailyCommissionMain(openKey = true) {
|
||||
// 获取当前星期信息
|
||||
let dayOfWeek = await getDayOfWeek();
|
||||
// 如果不是周日(0代表周日),
|
||||
@@ -213,12 +188,7 @@ async function dailyCommissionMain(openKey = true) {
|
||||
}
|
||||
}
|
||||
|
||||
// this.campaignAreaUtil = {
|
||||
// export {
|
||||
// campaignAreaMain,
|
||||
// dailyCommissionMain,
|
||||
// }
|
||||
|
||||
export {
|
||||
campaignAreaMain,
|
||||
dailyCommissionMain,
|
||||
}
|
||||
// }
|
||||
@@ -12,7 +12,7 @@ const ocrRegionConfig = {
|
||||
* @param {Object} [regionConfig=ocrRegionConfig.mapMission] - OCR识别区域配置对象,包含x、y、width、height属性
|
||||
* @returns {Promise<Array<Object>>} 返回识别结果数组,每个元素包含ok(boolean)和text(string)属性
|
||||
*/
|
||||
async function ocrMapMission(missionNameList = [], regionConfig = ocrRegionConfig.mapMission) {
|
||||
export async function ocrMapMission(missionNameList = [], regionConfig = ocrRegionConfig.mapMission) {
|
||||
let jsonList = [];
|
||||
let region = null;
|
||||
|
||||
@@ -69,13 +69,13 @@ async function ocrMapMission(missionNameList = [], regionConfig = ocrRegionConfi
|
||||
|
||||
//伴月纪闻任务待完成
|
||||
// 通过地图识别任务
|
||||
async function openMap() {
|
||||
export async function openMap() {
|
||||
const key = settings.mapKey || 'M'
|
||||
await sleep(200)
|
||||
await keyPress(key)
|
||||
}
|
||||
|
||||
async function mapMission(list = [], toOpenMap = true) {
|
||||
export async function mapMission(list = [], toOpenMap = true) {
|
||||
let ms = 600
|
||||
if (toOpenMap) {
|
||||
await openMap();
|
||||
@@ -95,14 +95,9 @@ async function mapMission(list = [], toOpenMap = true) {
|
||||
await sendText(text, `UID:${uid}\n地图任务`)
|
||||
}
|
||||
|
||||
// this.mapUtil = {
|
||||
|
||||
// export {
|
||||
// mapMission,
|
||||
// ocrMapMission,
|
||||
// openMap,
|
||||
// }
|
||||
|
||||
export {
|
||||
mapMission,
|
||||
ocrMapMission,
|
||||
openMap,
|
||||
}
|
||||
// }
|
||||
@@ -11,10 +11,14 @@ const NoticeMap = new Map([
|
||||
['独立通知', [{type: NoticeType.independence}]],
|
||||
['独立通知和BGI通知', [{type: NoticeType.independence}, {type: NoticeType.bgi}]],
|
||||
])
|
||||
const configNotice = {
|
||||
let configNotice = {
|
||||
noticeList: NoticeMap.get(settings.noticeType),
|
||||
}
|
||||
|
||||
async function buildConfigNotice() {
|
||||
configNotice = {
|
||||
noticeList: NoticeMap.get(settings.noticeType),
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 发送通知的异步函数
|
||||
* @param {Map} map - 包含通知内容键值对的Map对象
|
||||
@@ -23,7 +27,7 @@ const configNotice = {
|
||||
*/
|
||||
async function sendNotice(map = new Map(), title, noNotice = false) {
|
||||
log.debug(`sendNotice: map.size=${map.size}, noNotice=${noNotice}`);
|
||||
|
||||
await buildConfigNotice()
|
||||
// 如果设置了不发送通知且map为空,则记录日志并返回
|
||||
if ((map.size <= 0) || noNotice) {
|
||||
log.debug(`if sendNotice: map.size=${map.size}, noNotice=${noNotice}`);
|
||||
@@ -67,6 +71,7 @@ async function sendText(noticeText, title, noNotice = false) {
|
||||
log.info(`sendText 无通知内容`) // 记录日志信息
|
||||
return // 直接返回,不执行后续操作
|
||||
}
|
||||
await buildConfigNotice()
|
||||
// 构建通知文本,如果有标题则先添加标题
|
||||
let text = title ? title + "\n======\n" : "\n"
|
||||
// 添加通知内容
|
||||
|
||||
@@ -1,3 +1,54 @@
|
||||
/**
|
||||
* 通用找文本(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 目标文本(单个文本)
|
||||
@@ -13,7 +64,7 @@
|
||||
* @returns
|
||||
* - RecognitionResult | null
|
||||
*/
|
||||
async function findTextAndClick(
|
||||
export async function findTextAndClick(
|
||||
text,
|
||||
x = 0,
|
||||
y = 0,
|
||||
@@ -54,12 +105,177 @@ async function findTextAndClick(
|
||||
|
||||
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} 返回包含星期数字和星期名称的对象
|
||||
*/
|
||||
async function getDayOfWeek(calibrationGameRefreshTime = true) {
|
||||
export async function getDayOfWeek(calibrationGameRefreshTime = true) {
|
||||
// 获取当前日期对象
|
||||
let today = new Date();//4点刷新 所以要减去4小时
|
||||
if (calibrationGameRefreshTime) {
|
||||
@@ -79,4 +295,56 @@ async function getDayOfWeek(calibrationGameRefreshTime = true) {
|
||||
dayOfWeek: weekDay
|
||||
}
|
||||
}
|
||||
export { findTextAndClick,getDayOfWeek}
|
||||
|
||||
// 判断是否在主界面的函数
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/*
|
||||
const commonPath = 'assets/'
|
||||
const commonMap = new Map([
|
||||
['main_ui', {
|
||||
@@ -11,16 +12,17 @@ const genshinJson = {
|
||||
height: 1080,//genshin.height,
|
||||
}
|
||||
|
||||
/**
|
||||
/!**
|
||||
* 根据键值获取JSON路径
|
||||
* @param {string} key - 要查找的键值
|
||||
* @returns {any} 返回与键值对应的JSON路径值
|
||||
*/
|
||||
*!/
|
||||
function getJsonPath(key) {
|
||||
return commonMap.get(key); // 通过commonMap的get方法获取指定键对应的值
|
||||
}
|
||||
|
||||
function saveOnlyNumber(str) {
|
||||
*/
|
||||
import {toMainUi,isInMainUI} from "./tool"
|
||||
export function saveOnlyNumber(str) {
|
||||
str = str ? str : '';
|
||||
// 使用正则表达式匹配字符串中的所有数字
|
||||
// \d+ 匹配一个或多个数字
|
||||
@@ -29,7 +31,7 @@ function saveOnlyNumber(str) {
|
||||
return parseInt(str.match(/\d+/g).join(''));
|
||||
}
|
||||
|
||||
async function ocrUID() {
|
||||
export async function ocrUID() {
|
||||
let uid_json = {
|
||||
x: 1683,
|
||||
y: 1051,
|
||||
@@ -57,41 +59,7 @@ async function ocrUID() {
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否在主界面的函数
|
||||
const isInMainUI = () => {
|
||||
// let name = '主界面'
|
||||
let main_ui = getJsonPath('main_ui');
|
||||
// 定义识别对象
|
||||
let paimonMenuRo = RecognitionObject.TemplateMatch(
|
||||
file.ReadImageMatSync(`${main_ui.path}${main_ui.name}${main_ui.type}`),
|
||||
0,
|
||||
0,
|
||||
genshinJson.width / 3.0,
|
||||
genshinJson.width / 5.0
|
||||
);
|
||||
let captureRegion = captureGameRegion();
|
||||
let res = captureRegion.find(paimonMenuRo);
|
||||
captureRegion.Dispose()
|
||||
return !res.isEmpty();
|
||||
};
|
||||
|
||||
async function toMainUi() {
|
||||
let ms = 1000
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function compareUid(UID = settings.uid) {
|
||||
export async function compareUid(UID = settings.uid) {
|
||||
let uid = await ocrUID()
|
||||
let setUid = 0
|
||||
try {
|
||||
@@ -106,7 +74,7 @@ async function compareUid(UID = settings.uid) {
|
||||
return compare
|
||||
}
|
||||
|
||||
async function checkUid() {
|
||||
export async function checkUid() {
|
||||
let reJson = {
|
||||
inMainUI: false,
|
||||
isUid: false
|
||||
@@ -117,7 +85,7 @@ async function checkUid() {
|
||||
return reJson
|
||||
}
|
||||
|
||||
async function check() {
|
||||
export async function check() {
|
||||
let check = false
|
||||
if (settings.uid) {
|
||||
try {
|
||||
@@ -135,19 +103,12 @@ async function check() {
|
||||
return check
|
||||
}
|
||||
|
||||
// this.uidUtil = {
|
||||
// toMainUi,
|
||||
// isInMainUI,
|
||||
|
||||
// export {
|
||||
// // toMainUi,
|
||||
// // isInMainUI,
|
||||
// checkUid,
|
||||
// ocrUID,
|
||||
// check,
|
||||
// compareUid,
|
||||
// }
|
||||
export {
|
||||
toMainUi,
|
||||
isInMainUI,
|
||||
checkUid,
|
||||
ocrUID,
|
||||
check,
|
||||
compareUid,
|
||||
}
|
||||
// }
|
||||
@@ -164,7 +164,7 @@ export async function pullAccessWsProxyConfig(uid, http_api) {
|
||||
* @param {Array} atList - @用户列表
|
||||
* @returns {Promise<void>} 无返回值
|
||||
*/
|
||||
async function send(wsProxyUrl, wsUrl, wsToken, action, group_id, user_id, textList, atList) {
|
||||
export async function send(wsProxyUrl, wsUrl, wsToken, action, group_id, user_id, textList, atList) {
|
||||
const uid = local.uid
|
||||
// 构建基础JSON对象
|
||||
let json = {
|
||||
@@ -239,7 +239,7 @@ async function send(wsProxyUrl, wsUrl, wsToken, action, group_id, user_id, textL
|
||||
}
|
||||
}
|
||||
|
||||
async function sendText(text) {
|
||||
export async function sendText(text) {
|
||||
await init();
|
||||
let action = configWs.action;
|
||||
let group_id = configWs.group_id;
|
||||
@@ -253,11 +253,7 @@ async function sendText(text) {
|
||||
await send(wsProxyUrl, wsUrl, ws_token, action, group_id, user_id, textList, atList)
|
||||
}
|
||||
|
||||
// this.wsUtil = {
|
||||
// export {
|
||||
// send,
|
||||
// sendText
|
||||
// }
|
||||
export {
|
||||
send,
|
||||
sendText
|
||||
}
|
||||
// }
|
||||
Reference in New Issue
Block a user