mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-03 06:35:14 +08:00
[全自动地脉] (#2485)
* feat(树脂): 1.树脂耗尽模式基础上新增==>刷取次数取小值<==功能 2.优化原粹树脂识别速度 * feat(AutoLeyLineOutcrop): 添加最小替换次数功能 * feat(physical): 添加运行次数统计和OCR识别区域优化 * refactor: 将info日志级别调整为debug级别 * refactor: 调整操作延迟时间从800ms到1000ms * refactor: 优化模板匹配配置和错误信息输出 * fix: 修复错误处理和通知设置引用问题 * refactor: 修改变量声明为let * refactor: 优化区域对象创建和资源释放 * fix(utils): 修改原粹树脂识别函数的默认参数 - 将 opToMainUi 参数的默认值从 true 改为 false - 确保函数在不切换到主界面的情况下也能正常执行 - 避免不必要的界面跳转提升用户体验 * fix(utils): 修复图像识别逻辑中的区域查找问题 - 修正了 captureGameRegion 的调用方式,确保正确获取游戏区域 - 更新了模板匹配按钮查找逻辑,使用 region.find 替代 captureGameRegion().find - 添加了资源释放逻辑,确保 regionA 在使用后正确 Dispose - 移除了重复和注释掉的代码,提升代码可读性 - 保留了错误处理机制,确保路径错误时能正确抛出异常并记录日志 * fix(utils): 调整资源释放逻辑以防止内存泄漏 - 将 region.Dispose() 移至 await sleep(ms) 之后确保区域对象使用后正确释放 - 统一所有图像识别后的资源清理操作顺序 - 避免因提前释放导致的潜在空引用异常 - 确保每次识别操作结束后及时回收内存资源 - 优化错误处理流程中的资源管理时机 - 提高脚本运行稳定性与性能表现
This commit is contained in:
@@ -79,6 +79,7 @@
|
||||
## 更新日志
|
||||
### 4.4
|
||||
- 新增树脂耗尽模式
|
||||
- 新增树脂耗尽模式下刷取次数取小值
|
||||
- 新增更新提醒
|
||||
- 新增一条龙模式
|
||||
- BGI最低版本要求改为0.52.0
|
||||
|
||||
BIN
repo/js/AutoLeyLineOutcrop/assets/icon/200.png
Normal file
BIN
repo/js/AutoLeyLineOutcrop/assets/icon/200.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
repo/js/AutoLeyLineOutcrop/assets/icon/add_button.jpg
Normal file
BIN
repo/js/AutoLeyLineOutcrop/assets/icon/add_button.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 835 B |
BIN
repo/js/AutoLeyLineOutcrop/assets/icon/yue.png
Normal file
BIN
repo/js/AutoLeyLineOutcrop/assets/icon/yue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -17,9 +17,9 @@ let recheckCount = 0; // 树脂重新检查次数(防止无限递归)
|
||||
const MAX_RECHECK_COUNT = 3; // 最大重新检查次数
|
||||
let consecutiveFailureCount = 0; // 连续战斗失败次数
|
||||
const MAX_CONSECUTIVE_FAILURES = 5; // 最大连续失败次数,超过后终止脚本
|
||||
const ocrRegion1 = { x: 800, y: 200, width: 300, height: 100 }; // 中心区域
|
||||
const ocrRegion2 = { x: 0, y: 200, width: 300, height: 300 }; // 追踪任务区域
|
||||
const ocrRegion3 = { x: 1200, y: 520, width: 300, height: 300 }; // 拾取区域
|
||||
const ocrRegion1 = {x: 800, y: 200, width: 300, height: 100}; // 中心区域
|
||||
const ocrRegion2 = {x: 0, y: 200, width: 300, height: 300}; // 追踪任务区域
|
||||
const ocrRegion3 = {x: 1200, y: 520, width: 300, height: 300}; // 拾取区域
|
||||
|
||||
// 预定义识别对象
|
||||
const openRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/icon/open.png"));
|
||||
@@ -37,22 +37,20 @@ const ocrRoThis = RecognitionObject.ocrThis;
|
||||
(async function () {
|
||||
try {
|
||||
await runLeyLineOutcropScript();
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
// 全局错误捕获,记录并发送错误日志
|
||||
log.error("出错了: {error}", error.message);
|
||||
if (isNotification) {
|
||||
notification.error(`出错了: ${error.message}`);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
// 确保退出奖励界面(如果在奖励界面)
|
||||
try {
|
||||
await ensureExitRewardPage();
|
||||
} catch (exitError) {
|
||||
log.warn(`退出奖励界面时出错: ${exitError.message}`);
|
||||
}
|
||||
|
||||
|
||||
if (!marksStatus) {
|
||||
// 任何时候都确保自定义标记处于打开状态
|
||||
await openCustomMarks();
|
||||
@@ -68,10 +66,10 @@ const ocrRoThis = RecognitionObject.ocrThis;
|
||||
async function runLeyLineOutcropScript() {
|
||||
// 初始化加载配置和设置并校验
|
||||
initialize();
|
||||
|
||||
|
||||
// 处理树脂耗尽模式(如果开启)
|
||||
let runTimesValue = await handleResinExhaustionMode();
|
||||
if(runTimesValue <= 0) {
|
||||
if (runTimesValue <= 0) {
|
||||
throw new Error("树脂耗尽,脚本将结束运行");
|
||||
}
|
||||
|
||||
@@ -79,7 +77,7 @@ async function runLeyLineOutcropScript() {
|
||||
|
||||
// 执行地脉花挑战
|
||||
await runLeyLineChallenges();
|
||||
|
||||
|
||||
// 如果是树脂耗尽模式,执行完毕后再次检查是否还有树脂
|
||||
if (settings.isResinExhaustionMode) {
|
||||
await recheckResinAndContinue();
|
||||
@@ -102,13 +100,14 @@ async function initialize() {
|
||||
"loadSettings.js",
|
||||
"processLeyLineOutcrop.js",
|
||||
"recognizeTextInRegion.js",
|
||||
"physical.js",
|
||||
"calCountByResin.js"
|
||||
];
|
||||
];
|
||||
for (const fileName of utils) {
|
||||
eval(file.readTextSync(`utils/${fileName}`));
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(`JS文件缺失: ${error.message}`);
|
||||
throw new Error(`JS文件缺失: ${error.message}`);
|
||||
}
|
||||
// 2. 加载配置文件
|
||||
try {
|
||||
@@ -169,17 +168,17 @@ async function handleResinExhaustionMode() {
|
||||
if (!settings.isResinExhaustionMode) {
|
||||
return settings.timesValue;
|
||||
}
|
||||
|
||||
|
||||
log.info("树脂耗尽模式已开启,开始统计可刷取次数");
|
||||
|
||||
|
||||
try {
|
||||
// 调用树脂统计函数
|
||||
const resinResult = await calCountByResin();
|
||||
|
||||
|
||||
if (!resinResult || typeof resinResult.count !== 'number') {
|
||||
throw new Error("树脂统计返回结果无效");
|
||||
}
|
||||
|
||||
|
||||
// 检查统计到的次数是否有效
|
||||
if (resinResult.count <= 0) {
|
||||
log.warn("统计到的可刷取次数为0,脚本将不会执行任何刷取操作");
|
||||
@@ -187,27 +186,32 @@ async function handleResinExhaustionMode() {
|
||||
notification.send("树脂耗尽模式:统计到的可刷取次数为0,脚本将结束运行");
|
||||
}
|
||||
}
|
||||
|
||||
// 使用统计到的次数替换设置中的刷取次数
|
||||
settings.timesValue = resinResult.count;
|
||||
|
||||
if (physical.OpenModeCountMin) {
|
||||
settings.timesValue = Math.min(resinResult.count, settings.timesValue);
|
||||
log.info(`当前开启模式刷取数量: {key}`, settings.timesValue);
|
||||
} else {
|
||||
// 使用统计到的次数替换设置中的刷取次数
|
||||
settings.timesValue = resinResult.count;
|
||||
}
|
||||
|
||||
physical.NeedRunsCount = settings.timesValue;
|
||||
log.info(`树脂统计成功:`);
|
||||
log.info(` 原粹树脂可刷取: ${resinResult.originalResinTimes} 次`);
|
||||
log.info(` 浓缩树脂可刷取: ${resinResult.condensedResinTimes} 次`);
|
||||
log.info(` 须臾树脂可刷取: ${resinResult.transientResinTimes} 次${settings.useTransientResin ? '' : '(未开启使用)'}`);
|
||||
log.info(` 脆弱树脂可刷取: ${resinResult.fragileResinTimes} 次${settings.useFragileResin ? '' : '(未开启使用)'}`);
|
||||
log.info(` 总计可刷取次数: ${resinResult.count} 次`);
|
||||
|
||||
log.info(` 总计可刷取次数: {count} 次,最小替换:{key}`, (physical.OpenModeCountMin ? settings.timesValue : resinResult.count), (physical.OpenModeCountMin ? "开启" : "未开启"));
|
||||
|
||||
// 发送通知
|
||||
if (isNotification) {
|
||||
const notificationText =
|
||||
const notificationText =
|
||||
`全自动地脉花脚本已启用树脂耗尽模式\n\n` +
|
||||
`树脂统计结果(当前可刷取次数):\n` +
|
||||
`原粹树脂: ${resinResult.originalResinTimes} 次\n` +
|
||||
`浓缩树脂: ${resinResult.condensedResinTimes} 次\n` +
|
||||
`须臾树脂: ${resinResult.transientResinTimes} 次${settings.useTransientResin ? '' : '(未开启)'}\n` +
|
||||
`脆弱树脂: ${resinResult.fragileResinTimes} 次${settings.useFragileResin ? '' : '(未开启)'}\n\n` +
|
||||
`总计可刷取: ${resinResult.count} 次\n`;
|
||||
`总计可刷取: ${physical.OpenModeCountMin ? settings.timesValue : resinResult.count} 次\n最小替换:${(physical.OpenModeCountMin ? "开启" : "未开启")}\n`;
|
||||
notification.send(notificationText);
|
||||
}
|
||||
|
||||
@@ -216,7 +220,7 @@ async function handleResinExhaustionMode() {
|
||||
// 统计失败,使用设置中的刷取次数
|
||||
log.error(`树脂统计失败: ${error.message}`);
|
||||
log.warn(`将使用设置中的刷取次数: ${settings.timesValue}`);
|
||||
|
||||
|
||||
if (isNotification) {
|
||||
notification.send(`树脂耗尽模式:统计失败,将使用设置中的刷取次数 ${settings.timesValue} 次\n错误信息: ${error.message}`);
|
||||
}
|
||||
@@ -231,7 +235,14 @@ async function handleResinExhaustionMode() {
|
||||
async function recheckResinAndContinue() {
|
||||
// 递归深度检查,防止无限循环
|
||||
recheckCount++;
|
||||
|
||||
if (physical.OpenModeCountMin) {
|
||||
physical.AlreadyRunsCount++;
|
||||
if (physical.NeedRunsCount<=physical.AlreadyRunsCount){
|
||||
log.info(`[已开启取小值]树脂耗尽模式:任务已完成,已经运行{count}次`,physical.AlreadyRunsCount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (recheckCount > MAX_RECHECK_COUNT) {
|
||||
log.warn(`已达到最大重新检查次数限制 (${MAX_RECHECK_COUNT} 次),停止继续检查`);
|
||||
if (isNotification) {
|
||||
@@ -239,27 +250,27 @@ async function recheckResinAndContinue() {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
log.info("=".repeat(50));
|
||||
log.info(`树脂耗尽模式:任务已完成,开始检查树脂状态...`);
|
||||
log.info("=".repeat(50));
|
||||
|
||||
|
||||
try {
|
||||
// 重新统计树脂
|
||||
const resinResult = await calCountByResin();
|
||||
|
||||
|
||||
if (!resinResult || typeof resinResult.count !== 'number') {
|
||||
log.warn("树脂统计返回结果无效,结束运行");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
log.info(`树脂检查结果:`);
|
||||
log.info(` 原粹树脂可刷取: ${resinResult.originalResinTimes} 次`);
|
||||
log.info(` 浓缩树脂可刷取: ${resinResult.condensedResinTimes} 次`);
|
||||
log.info(` 须臾树脂可刷取: ${resinResult.transientResinTimes} 次${settings.useTransientResin ? '' : '(未开启使用)'}`);
|
||||
log.info(` 脆弱树脂可刷取: ${resinResult.fragileResinTimes} 次${settings.useFragileResin ? '' : '(未开启使用)'}`);
|
||||
log.info(` 总计可刷取次数: ${resinResult.count} 次`);
|
||||
|
||||
|
||||
// 安全检查:如果检测到的次数异常多,可能是识别错误
|
||||
if (resinResult.count > 50) {
|
||||
log.warn(`检测到异常的可刷取次数 (${resinResult.count}),为安全起见停止运行`);
|
||||
@@ -268,23 +279,23 @@ async function recheckResinAndContinue() {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 如果还有树脂可用,继续执行
|
||||
if (resinResult.count > 0) {
|
||||
log.info(`检测到还有 ${resinResult.count} 次可刷取,继续执行地脉花挑战...`);
|
||||
log.info(`(这是第 ${recheckCount} 次额外检查并继续执行)`);
|
||||
|
||||
|
||||
if (isNotification) {
|
||||
notification.send(`树脂耗尽模式:检测到还有 ${resinResult.count} 次可刷取,继续执行(第 ${recheckCount} 次额外执行)`);
|
||||
}
|
||||
|
||||
|
||||
// 重置运行次数并更新目标次数
|
||||
currentRunTimes = 0;
|
||||
settings.timesValue = resinResult.count;
|
||||
|
||||
|
||||
// 递归调用继续执行地脉花挑战和重新检查
|
||||
await runLeyLineChallenges();
|
||||
|
||||
|
||||
// 执行完后再次检查(递归)
|
||||
await recheckResinAndContinue();
|
||||
} else {
|
||||
@@ -333,7 +344,7 @@ async function prepareForLeyLineRun() {
|
||||
setGameMetrics(1920, 1080, 1); // 看起来没什么用
|
||||
// 1. 开局传送到七天神像
|
||||
if (!oneDragonMode) {
|
||||
await genshin.tpToStatueOfTheSeven();
|
||||
await genshin.tpToStatueOfTheSeven();
|
||||
}
|
||||
|
||||
// 2. 切换战斗队伍
|
||||
@@ -425,7 +436,7 @@ async function loadNodeData() {
|
||||
try {
|
||||
const nodeDataText = await file.readText("LeyLineOutcropData.json");
|
||||
const rawData = JSON.parse(nodeDataText);
|
||||
|
||||
|
||||
// 适配数据结构:将原始数据转换为代码期望的格式
|
||||
return adaptNodeData(rawData);
|
||||
} catch (error) {
|
||||
@@ -444,7 +455,7 @@ function adaptNodeData(rawData) {
|
||||
node: [],
|
||||
indexes: rawData.indexes
|
||||
};
|
||||
|
||||
|
||||
// 添加传送点,设置type为"teleport"
|
||||
if (rawData.teleports) {
|
||||
for (const teleport of rawData.teleports) {
|
||||
@@ -456,7 +467,7 @@ function adaptNodeData(rawData) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 添加地脉花节点,设置type为"blossom"
|
||||
if (rawData.blossoms) {
|
||||
for (const blossom of rawData.blossoms) {
|
||||
@@ -468,13 +479,13 @@ function adaptNodeData(rawData) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 根据edges构建next和prev关系
|
||||
if (rawData.edges) {
|
||||
for (const edge of rawData.edges) {
|
||||
const sourceNode = adaptedData.node.find(node => node.id === edge.source);
|
||||
const targetNode = adaptedData.node.find(node => node.id === edge.target);
|
||||
|
||||
|
||||
if (sourceNode && targetNode) {
|
||||
sourceNode.next.push({
|
||||
target: edge.target,
|
||||
@@ -484,9 +495,9 @@ function adaptNodeData(rawData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log.debug(`适配数据完成:传送点 ${rawData.teleports ? rawData.teleports.length : 0} 个,地脉花 ${rawData.blossoms ? rawData.blossoms.length : 0} 个,边缘 ${rawData.edges ? rawData.edges.length : 0} 个`);
|
||||
|
||||
|
||||
return adaptedData;
|
||||
}
|
||||
|
||||
@@ -532,7 +543,7 @@ function findPathsToTarget(nodeData, targetNode) {
|
||||
|
||||
/**
|
||||
* 如果需要,尝试查找反向路径(从目标节点的前置节点到传送点再到目标)
|
||||
* @param {Object} nodeData - 节点数据
|
||||
* @param {Object} nodeData - 节点数据
|
||||
* @param {Object} targetNode - 目标节点
|
||||
* @param {Object} nodeMap - 节点映射
|
||||
* @param {Array} existingPaths - 已找到的路径
|
||||
@@ -628,13 +639,13 @@ async function executePath(path) {
|
||||
const routePath = path.routes[path.routes.length - 1];
|
||||
const targetPath = routePath.replace('assets/pathing/', 'assets/pathing/target/').replace('-rerun', '');
|
||||
await processLeyLineOutcrop(settings.timeout, targetPath);
|
||||
|
||||
|
||||
// 尝试领取奖励,如果失败则抛出异常停止执行
|
||||
const rewardSuccess = await attemptReward();
|
||||
if (!rewardSuccess) {
|
||||
throw new Error("无法领取奖励,树脂不足或其他原因");
|
||||
}
|
||||
|
||||
|
||||
// 成功完成地脉花挑战,重置连续失败计数器
|
||||
consecutiveFailureCount = 0;
|
||||
}
|
||||
@@ -677,14 +688,14 @@ async function handleNoStrategyFound() {
|
||||
log.error("未找到对应的地脉花策略,请再次运行脚本");
|
||||
log.error("如果仍然不行,请截图{1}游戏界面,并反馈给作者!", "*完整的*");
|
||||
log.error("完整的游戏界面!完整的游戏界面!完整的游戏界面!");
|
||||
|
||||
|
||||
// 确保退出奖励界面 TODO: 可能会影响debug,先不执行ensureExitRewardPage
|
||||
// try {
|
||||
// await ensureExitRewardPage();
|
||||
// } catch (exitError) {
|
||||
// log.warn(`退出奖励界面时出错: ${exitError.message}`);
|
||||
// }
|
||||
|
||||
|
||||
if (isNotification) {
|
||||
notification.error("未找到对应的地脉花策略");
|
||||
await genshin.returnMainUi();
|
||||
@@ -789,7 +800,7 @@ async function autoFight(timeout) {
|
||||
logFightResult = fightResult ? "成功" : "失败";
|
||||
log.info(`战斗结束,战斗结果:${logFightResult}`);
|
||||
cts.cancel();
|
||||
|
||||
|
||||
try {
|
||||
await fightTask;
|
||||
} catch (error) {
|
||||
@@ -800,7 +811,7 @@ async function autoFight(timeout) {
|
||||
log.warn(`战斗任务结束时出现异常: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return fightResult;
|
||||
}
|
||||
|
||||
@@ -993,7 +1004,7 @@ async function adjustViewForReward(boxIconRo, token) {
|
||||
captureRegion.dispose();
|
||||
if (!iconRes.isExist()) {
|
||||
log.warn("未找到图标,等待一下");
|
||||
await sleep(1000);
|
||||
await sleep(1000);
|
||||
continue; // 没有找到图标等一秒再继续
|
||||
// throw new Error('未找到图标,没有地脉花');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "全自动地脉花",
|
||||
"version": "4.4.6",
|
||||
"version": "4.4.7",
|
||||
"tags": ["地脉花"],
|
||||
"bgi_version": "0.52.0",
|
||||
"description": "基于OCR图像识别的全自动刷取地脉花。\n💡更多信息请查看README! \n\n----------注意事项----------\n●仅支持BetterGI 0.52.0 及以上版本!\n●部分地脉花因特殊原因不支持全自动,具体的点位请在手册中查看。\n●树脂使用的优先级:2倍原粹树脂 > 浓缩树脂 > 原粹树脂。\n●运行时会传送到七天神像设置中设置的七天神像,需要关闭七天神像设置中的“是否就近七天神像恢复血量”,并指定七天神像。\n●战斗策略注意调度器设置中地图追踪行走配置里的“允许在JsSpript中使用”和“覆盖JS中的自动战斗配置”,只有在都打开的情况下脚本才会使用下面的战斗配置,否则会使用独立任务中的战斗策略。战斗超时时间不能大于脚本自定义配置中的时间。\n\n如果遇到问题,请先参照README中的方法进行解决。",
|
||||
@@ -33,6 +33,10 @@
|
||||
{
|
||||
"name": "羊汪汪",
|
||||
"links": "https://github.com/ColinXHL"
|
||||
},
|
||||
{
|
||||
"name": "云端客",
|
||||
"links": "https://github.com/Kirito520Asuna"
|
||||
}
|
||||
],
|
||||
"settings_ui": "settings.json",
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
],
|
||||
"default": "稻妻"
|
||||
},
|
||||
{
|
||||
"name": "isResinExhaustionMode",
|
||||
"type": "checkbox",
|
||||
"label": "树脂耗尽模式\n开启后会自动统计所有可用树脂并计算可刷取次数,替换上方设置的刷取次数\n注意:请同时设置树脂刷取次数,将在统计失败时使用"
|
||||
},
|
||||
{
|
||||
"name": "openModeCountMin",
|
||||
"type": "checkbox",
|
||||
"label": "刷取次数取小值\n开启后树脂耗尽模式中计算可刷取次数,和上方设置的刷取次数取小值"
|
||||
},
|
||||
{
|
||||
"name": "count",
|
||||
"type": "input-text",
|
||||
@@ -77,11 +87,6 @@
|
||||
"type": "checkbox",
|
||||
"label": "一条龙模式\n开启后,会跳过开始的前往七天神像以及强制更新"
|
||||
},
|
||||
{
|
||||
"name": "isResinExhaustionMode",
|
||||
"type": "checkbox",
|
||||
"label": "树脂耗尽模式\n开启后会自动统计所有可用树脂并计算可刷取次数,替换上方设置的刷取次数\n注意:请同时设置树脂刷取次数,将在统计失败时使用"
|
||||
},
|
||||
{
|
||||
"name": "isGoToSynthesizer",
|
||||
"type": "select",
|
||||
|
||||
@@ -17,20 +17,20 @@ const RESIN_ICONS = {
|
||||
|
||||
// 普通数字识别对象(1-4)
|
||||
const NUMBER_ICONS = [
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num1.png")), value: 1 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num2.png")), value: 2 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num3.png")), value: 3 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num4.png")), value: 4 }
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num1.png")), value: 1},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num2.png")), value: 2},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num3.png")), value: 3},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num4.png")), value: 4}
|
||||
];
|
||||
|
||||
// 白色数字识别对象(0-5,用于浓缩树脂)
|
||||
const WHITE_NUMBER_ICONS = [
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num0_white.png")), value: 0 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num1_white.png")), value: 1 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num2_white.png")), value: 2 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num3_white.png")), value: 3 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num4_white.png")), value: 4 },
|
||||
{ ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num5_white.png")), value: 5 }
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num0_white.png")), value: 0},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num1_white.png")), value: 1},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num2_white.png")), value: 2},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num3_white.png")), value: 3},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num4_white.png")), value: 4},
|
||||
{ro: RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/num5_white.png")), value: 5}
|
||||
];
|
||||
|
||||
// 配置常量
|
||||
@@ -39,19 +39,19 @@ const CONFIG = {
|
||||
SLEEP_INTERVAL: 500, // 循环间隔时间(毫秒)
|
||||
UI_DELAY: 1500, // UI操作延迟时间(毫秒)
|
||||
MAP_ZOOM_LEVEL: 6, // 地图缩放级别
|
||||
|
||||
|
||||
// 点击坐标
|
||||
COORDINATES: {
|
||||
MAP_SWITCH: { x: 1840, y: 1020 }, // 地图右下角切换按钮
|
||||
MONDSTADT: { x: 1420, y: 180 }, // 蒙德选择按钮
|
||||
AVOID_SELECTION: { x: 1090, y: 450 } // 避免选中效果的点击位置
|
||||
MAP_SWITCH: {x: 1840, y: 1020}, // 地图右下角切换按钮
|
||||
MONDSTADT: {x: 1420, y: 180}, // 蒙德选择按钮
|
||||
AVOID_SELECTION: {x: 1090, y: 450} // 避免选中效果的点击位置
|
||||
},
|
||||
|
||||
|
||||
// OCR识别区域配置
|
||||
OCR_REGIONS: {
|
||||
ORIGINAL_RESIN: { width: 200, height: 40 },
|
||||
CONDENSED_RESIN: { width: 90, height: 40 },
|
||||
OTHER_RESIN: { width: 0, height: 60 } // width会根据图标宽度动态设置
|
||||
ORIGINAL_RESIN: {width: 200, height: 40},
|
||||
CONDENSED_RESIN: {width: 90, height: 40},
|
||||
OTHER_RESIN: {width: 0, height: 60} // width会根据图标宽度动态设置
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ let resinCounts = {
|
||||
*/
|
||||
async function recognizeImage(recognitionObject, timeout = CONFIG.RECOGNITION_TIMEOUT) {
|
||||
const startTime = Date.now();
|
||||
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
try {
|
||||
// 直接链式调用,不保存gameRegion变量,避免内存管理问题
|
||||
@@ -86,7 +86,7 @@ async function recognizeImage(recognitionObject, timeout = CONFIG.RECOGNITION_TI
|
||||
}
|
||||
await sleep(CONFIG.SLEEP_INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
log.warn(`经过多次尝试,仍然无法识别图像`);
|
||||
return null;
|
||||
}
|
||||
@@ -143,10 +143,10 @@ async function recognizeWhiteNumberByImage(ocrRegion) {
|
||||
* @returns {boolean} 是否在区域内
|
||||
*/
|
||||
function isPointInRegion(point, region) {
|
||||
return point.x >= region.x &&
|
||||
point.x <= region.x + region.width &&
|
||||
point.y >= region.y &&
|
||||
point.y <= region.y + region.height;
|
||||
return point.x >= region.x &&
|
||||
point.x <= region.x + region.width &&
|
||||
point.y >= region.y &&
|
||||
point.y <= region.y + region.height;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,17 +162,17 @@ async function recognizeNumberByOCR(ocrRegion, pattern) {
|
||||
const ocrRo = RecognitionObject.ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height);
|
||||
captureRegion = captureGameRegion();
|
||||
resList = captureRegion.findMulti(ocrRo);
|
||||
|
||||
|
||||
if (!resList || resList.length === 0) {
|
||||
log.warn("OCR未识别到任何文本");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
for (const res of resList) {
|
||||
if (!res || !res.text) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const numberMatch = res.text.match(pattern);
|
||||
if (numberMatch) {
|
||||
const number = parseInt(numberMatch[1] || numberMatch[0]);
|
||||
@@ -201,7 +201,26 @@ async function recognizeNumberByOCR(ocrRegion, pattern) {
|
||||
* 统计原粹树脂数量
|
||||
* @returns {number} 原粹树脂数量
|
||||
*/
|
||||
async function countOriginalResin() {
|
||||
/**
|
||||
* 统计原粹树脂数量
|
||||
* @returns {number} 原粹树脂数量
|
||||
*/
|
||||
async function countOriginalResin(tryOriginalMode,opToMainUi) {
|
||||
if (tryOriginalMode) {
|
||||
log.info("尝试使用原始模式");
|
||||
return await countOriginalResinBackup()
|
||||
} else {
|
||||
let ocrPhysical = await physical.ocrPhysical(opToMainUi);
|
||||
await sleep(600)
|
||||
if (ocrPhysical && ocrPhysical.ok) {
|
||||
return ocrPhysical.remainder;
|
||||
} else {
|
||||
throw new Error("ocrPhysical error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function countOriginalResinBackup() {
|
||||
const originalResin = await recognizeImage(RESIN_ICONS.ORIGINAL);
|
||||
if (!originalResin) {
|
||||
log.warn(`未找到原粹树脂图标`);
|
||||
@@ -269,7 +288,7 @@ async function countCondensedResin() {
|
||||
// OCR识别整个界面的文本
|
||||
let ocrRo = RecognitionObject.Ocr(0, 0, captureRegion.width, captureRegion.height);
|
||||
textList = captureRegion.findMulti(ocrRo);
|
||||
|
||||
|
||||
for (const res of textList) {
|
||||
if (res.text.includes("当前拥有")) {
|
||||
const match = res.text.match(/当前拥有\s*([0-5ss])/);
|
||||
@@ -371,20 +390,33 @@ async function openMap() {
|
||||
log.info("打开地图界面");
|
||||
keyPress("M");
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
|
||||
// 切换到国家选择界面
|
||||
click(CONFIG.COORDINATES.MAP_SWITCH.x, CONFIG.COORDINATES.MAP_SWITCH.y);
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
// click(CONFIG.COORDINATES.MAP_SWITCH.x, CONFIG.COORDINATES.MAP_SWITCH.y);
|
||||
// await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
// 选择蒙德
|
||||
click(CONFIG.COORDINATES.MONDSTADT.x, CONFIG.COORDINATES.MONDSTADT.y);
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
// click(CONFIG.COORDINATES.MONDSTADT.x, CONFIG.COORDINATES.MONDSTADT.y);
|
||||
// await sleep(CONFIG.UI_DELAY);
|
||||
// await switchtoCountrySelection(CONFIG.COORDINATES.MONDSTADT.x, CONFIG.COORDINATES.MONDSTADT.y)
|
||||
|
||||
// 设置地图缩放级别,排除识别干扰
|
||||
await genshin.setBigMapZoomLevel(CONFIG.MAP_ZOOM_LEVEL);
|
||||
log.info("地图界面设置完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换到国家选择界面的异步函数
|
||||
* 通过点击指定坐标并等待界面加载来完成切换操作
|
||||
*/
|
||||
async function switchtoCountrySelection(x, y) {
|
||||
// 切换到国家选择界面
|
||||
click(CONFIG.COORDINATES.MAP_SWITCH.x, CONFIG.COORDINATES.MAP_SWITCH.y);
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
click(x, y);
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开补充树脂界面
|
||||
*/
|
||||
@@ -405,7 +437,7 @@ async function openReplenishResinUi() {
|
||||
*/
|
||||
function displayResults(results) {
|
||||
const resultText = `原粹:${results.original} 浓缩:${results.condensed} 须臾:${results.transient} 脆弱:${results.fragile}`;
|
||||
|
||||
|
||||
log.info(`============ 树脂统计结果 ============`);
|
||||
log.info(`原粹树脂数量: ${results.original}`);
|
||||
log.info(`浓缩树脂数量: ${results.condensed}`);
|
||||
@@ -420,42 +452,55 @@ function displayResults(results) {
|
||||
* 统计所有树脂数量的主函数
|
||||
* @returns {Object} 包含所有树脂数量的对象
|
||||
*/
|
||||
this.countAllResin = async function() {
|
||||
this.countAllResin = async function () {
|
||||
try {
|
||||
setGameMetrics(1920, 1080, 1);
|
||||
log.info("开始统计树脂数量");
|
||||
|
||||
|
||||
// 返回主界面
|
||||
await genshin.returnMainUi();
|
||||
let toMainUi=true
|
||||
// await genshin.returnMainUi();
|
||||
// await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
let tryPass = true;
|
||||
try {
|
||||
resinCounts.original = await countOriginalResin(false,toMainUi);
|
||||
} catch (e) {
|
||||
tryPass = false
|
||||
}
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
|
||||
// 打开地图界面统计原粹/浓缩树脂
|
||||
await openMap();
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
log.info("开始统计地图界面中的树脂");
|
||||
resinCounts.original = await countOriginalResin();
|
||||
|
||||
if (!tryPass){
|
||||
// 如果第一次尝试失败,则切换到蒙德
|
||||
await switchtoCountrySelection(CONFIG.COORDINATES.MONDSTADT.x, CONFIG.COORDINATES.MONDSTADT.y)
|
||||
resinCounts.original = await countOriginalResin(!tryPass);
|
||||
}
|
||||
resinCounts.condensed = await countCondensedResin();
|
||||
|
||||
|
||||
// 打开补充树脂界面统计须臾/脆弱树脂
|
||||
await openReplenishResinUi();
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
|
||||
// 点击避免选中效果影响统计
|
||||
click(CONFIG.COORDINATES.AVOID_SELECTION.x, CONFIG.COORDINATES.AVOID_SELECTION.y);
|
||||
await sleep(500);
|
||||
|
||||
|
||||
log.info("开始统计补充树脂界面中的树脂");
|
||||
resinCounts.transient = await countTransientResin();
|
||||
resinCounts.fragile = await countFragileResin();
|
||||
|
||||
|
||||
// 显示结果
|
||||
displayResults(resinCounts);
|
||||
|
||||
|
||||
// 返回主界面
|
||||
await genshin.returnMainUi();
|
||||
await sleep(CONFIG.UI_DELAY);
|
||||
|
||||
|
||||
log.info("树脂统计完成");
|
||||
return {
|
||||
originalResinCount: resinCounts.original,
|
||||
@@ -463,7 +508,7 @@ function displayResults(results) {
|
||||
transientResinCount: resinCounts.transient,
|
||||
fragileResinCount: resinCounts.fragile
|
||||
};
|
||||
|
||||
|
||||
} catch (error) {
|
||||
log.error(`统计树脂数量时发生异常: ${error.message}`);
|
||||
throw error;
|
||||
@@ -480,7 +525,7 @@ function displayResults(results) {
|
||||
* fragileResinTimes: number
|
||||
* }
|
||||
*/
|
||||
this.calCountByResin = async function() {
|
||||
this.calCountByResin = async function () {
|
||||
try {
|
||||
let countResult = await this.countAllResin();
|
||||
let count = 0;
|
||||
@@ -508,7 +553,7 @@ this.calCountByResin = async function() {
|
||||
// 2. 浓缩树脂:每个计算为1次
|
||||
let condensedResinTimes = countResult.condensedResinCount;
|
||||
log.info(`浓缩树脂可刷取次数: ${condensedResinTimes}`);
|
||||
|
||||
|
||||
// 3. 须臾树脂:检查设置是否开启
|
||||
let transientResinTimes = 0;
|
||||
if (settings.useTransientResin) {
|
||||
@@ -517,7 +562,7 @@ this.calCountByResin = async function() {
|
||||
} else {
|
||||
log.info(`须臾树脂未开启使用,跳过计算`);
|
||||
}
|
||||
|
||||
|
||||
// 4. 脆弱树脂:检查设置是否开启
|
||||
let fragileResinTimes = 0;
|
||||
if (settings.useFragileResin) {
|
||||
@@ -526,7 +571,7 @@ this.calCountByResin = async function() {
|
||||
} else {
|
||||
log.info(`脆弱树脂未开启使用,跳过计算`);
|
||||
}
|
||||
|
||||
|
||||
// 计算总次数
|
||||
count = originalResinTimes + condensedResinTimes + transientResinTimes + fragileResinTimes;
|
||||
log.info(`总计可刷取次数: ${count}`);
|
||||
|
||||
252
repo/js/AutoLeyLineOutcrop/utils/physical.js
Normal file
252
repo/js/AutoLeyLineOutcrop/utils/physical.js
Normal file
@@ -0,0 +1,252 @@
|
||||
const commonPath = 'assets/icon/'
|
||||
const commonMap = new Map([
|
||||
['main_ui', {
|
||||
path: `${commonPath}`,
|
||||
name: 'paimon_menu',
|
||||
type: '.png',
|
||||
}],
|
||||
['yue', {
|
||||
path: `${commonPath}`,
|
||||
name: 'yue',
|
||||
type: '.png',
|
||||
}],
|
||||
['200', {
|
||||
path: `${commonPath}`,
|
||||
name: '200',
|
||||
type: '.png',
|
||||
}],
|
||||
['add_button', {
|
||||
path: `${commonPath}`,
|
||||
name: 'add_button',
|
||||
type: '.jpg',
|
||||
}],
|
||||
])
|
||||
//====================================================
|
||||
const genshinJson = {
|
||||
width: 1920,//genshin.width,
|
||||
height: 1080,//genshin.height,
|
||||
}
|
||||
const MinPhysical = settings.minPhysical?parseInt(settings.minPhysical+''):parseInt(20+'')
|
||||
const OpenModeCountMin = settings.openModeCountMin
|
||||
let AlreadyRunsCount=0
|
||||
let NeedRunsCount=0
|
||||
const TemplateOrcJson={x: 1568, y: 16, width: 225, height: 60,}
|
||||
//====================================================
|
||||
/**
|
||||
* 根据键值获取JSON路径
|
||||
* @param {string} key - 要查找的键值
|
||||
* @returns {any} 返回与键值对应的JSON路径值
|
||||
*/
|
||||
function getJsonPath(key) {
|
||||
return commonMap.get(key); // 通过commonMap的get方法获取指定键对应的值
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字符串中提取数字并组合成一个整数
|
||||
* @param {string} str - 包含数字的字符串
|
||||
* @returns {number} - 由字符串中所有数字组合而成的整数
|
||||
*/
|
||||
async function saveOnlyNumber(str) {
|
||||
// 使用正则表达式匹配字符串中的所有数字
|
||||
// \d+ 匹配一个或多个数字
|
||||
// .join('') 将匹配到的数字数组连接成一个字符串
|
||||
// parseInt 将连接后的字符串转换为整数
|
||||
return parseInt(str.match(/\d+/g).join(''));
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别原粹树脂(体力)的函数
|
||||
* @param {boolean} [opToMainUi=false] - 是否操作到主界面
|
||||
* @returns {Promise<Object>} 返回一个包含识别结果的Promise对象
|
||||
* - ok {boolean}: 是否可执行(体力是否足够)
|
||||
* - min {number}: 最小可执行体力值
|
||||
* - remainder {number}: 当前剩余体力值
|
||||
*/
|
||||
async function ocrPhysical(opToMainUi = false) {
|
||||
// 检查是否启用体力识别功能,如果未启用则直接返回默认结果
|
||||
if (!settings.isResinExhaustionMode) {
|
||||
log.info(`===未启用===`)
|
||||
return {
|
||||
ok: true,
|
||||
min: 0,
|
||||
remainder: 0,
|
||||
}
|
||||
}
|
||||
log.info(`===开始识别原粹树脂===`)
|
||||
let ms = 1000 // 定义操作延迟时间(毫秒)
|
||||
if (opToMainUi) {
|
||||
await toMainUi(); // 切换到主界面
|
||||
}
|
||||
//设置最小可执行体力值
|
||||
let minPhysical = MinPhysical
|
||||
//打开地图界面
|
||||
await keyPress('M')
|
||||
await sleep(ms)
|
||||
log.debug(`===[点击+]===`)
|
||||
//点击+ 按钮 x=1264,y=39,width=18,height=19
|
||||
let add_buttonJSON = getJsonPath('add_button');
|
||||
let add_objJson = {
|
||||
path: `${add_buttonJSON.path}${add_buttonJSON.name}${add_buttonJSON.type}`,
|
||||
x: 1264,
|
||||
y: 39,
|
||||
width: genshinJson.width - 1264,
|
||||
height: 60,
|
||||
}
|
||||
let templateMatchAddButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${add_objJson.path}`), add_objJson.x, add_objJson.y, add_objJson.width, add_objJson.height);
|
||||
let regionA = captureGameRegion()
|
||||
// let buttonA = captureGameRegion().find(templateMatchAddButtonRo);
|
||||
let buttonA = region.find(templateMatchAddButtonRo);
|
||||
regionA.Dispose()
|
||||
|
||||
await sleep(ms)
|
||||
if (!buttonA.isExist()) {
|
||||
log.error(`未找到${add_objJson.path}请检查路径是否正确`)
|
||||
throwError(`未找到${add_objJson.path}请检查路径是否正确`)
|
||||
}
|
||||
await buttonA.click()
|
||||
// let add_obj = {
|
||||
// x: 1264,
|
||||
// y: 39,
|
||||
// }
|
||||
// await click(add_obj.x, add_obj.y)
|
||||
await sleep(ms)
|
||||
|
||||
log.debug(`===[定位原粹树脂]===`)
|
||||
//定位月亮
|
||||
let jsonPath = getJsonPath('yue');
|
||||
let tmJson = {
|
||||
path: `${jsonPath.path}${jsonPath.name}${jsonPath.type}`,
|
||||
x: TemplateOrcJson.x,
|
||||
y: TemplateOrcJson.y,
|
||||
width: TemplateOrcJson.width,
|
||||
height: TemplateOrcJson.height,
|
||||
}
|
||||
let templateMatchButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${tmJson.path}`), tmJson.x, tmJson.y, tmJson.width, tmJson.height);
|
||||
let region =captureGameRegion()
|
||||
// let button = captureGameRegion().find(templateMatchButtonRo);
|
||||
let button = region.find(templateMatchButtonRo);
|
||||
region.Dispose()
|
||||
await sleep(ms)
|
||||
if (!button.isExist()) {
|
||||
log.error(`${tmJson.path} 匹配异常`)
|
||||
throwError(`${tmJson.path} 匹配异常`)
|
||||
}
|
||||
|
||||
log.debug(`===[定位/200]===`)
|
||||
//定位200
|
||||
let jsonPath2 = getJsonPath('200');
|
||||
let tmJson2 = {
|
||||
path: `${jsonPath2.path}${jsonPath2.name}${jsonPath2.type}`,
|
||||
x: TemplateOrcJson.x,
|
||||
y: TemplateOrcJson.y,
|
||||
width: TemplateOrcJson.width,
|
||||
height: TemplateOrcJson.height,
|
||||
}
|
||||
let templateMatchButtonRo2 = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`${tmJson2.path}`), tmJson2.x, tmJson2.y, tmJson2.width, tmJson2.height);
|
||||
let region2 = captureGameRegion()
|
||||
let button2 = region2.find(templateMatchButtonRo2);
|
||||
region2.Dispose()
|
||||
|
||||
await sleep(ms)
|
||||
if (!button2.isExist()) {
|
||||
log.error(`${tmJson2.path} 匹配异常`)
|
||||
throwError(`${tmJson2.path} 匹配异常`)
|
||||
}
|
||||
|
||||
log.debug(`===[识别原粹树脂]===`)
|
||||
//识别体力 x=1625,y=31,width=79,height=30 / x=1689,y=35,width=15,height=26
|
||||
let ocr_obj = {
|
||||
// x: 1623,
|
||||
x: button.x + button.width-20,
|
||||
// y: 32,
|
||||
y: button.y,
|
||||
// width: 61,
|
||||
width: Math.abs(button2.x - button.x - button.width+20),
|
||||
height: button2.height
|
||||
}
|
||||
|
||||
log.debug(`ocr_obj: x={x},y={y},width={width},height={height}`, ocr_obj.x, ocr_obj.y, ocr_obj.width, ocr_obj.height)
|
||||
|
||||
try {
|
||||
let recognitionObjectOcr = RecognitionObject.Ocr(ocr_obj.x, ocr_obj.y, ocr_obj.width, ocr_obj.height);
|
||||
let region3 = captureGameRegion()
|
||||
let res = region3.find(recognitionObjectOcr);
|
||||
region3.Dispose()
|
||||
|
||||
log.info(`[OCR原粹树脂]识别结果: ${res.text}, 原始坐标: x=${res.x}, y=${res.y},width:${res.width},height:${res.height}`);
|
||||
let remainder = await saveOnlyNumber(res.text)
|
||||
let execute = (remainder - minPhysical) >= 0
|
||||
log.info(`最小可执行原粹树脂:{min},原粹树脂:{key}`, minPhysical, remainder,)
|
||||
|
||||
await keyPress('VK_ESCAPE')
|
||||
return {
|
||||
ok: execute,
|
||||
min: minPhysical,
|
||||
remainder: remainder,
|
||||
}
|
||||
} catch (e) {
|
||||
throwError(`识别失败,err:${e.message}`)
|
||||
} finally {
|
||||
if (opToMainUi) {
|
||||
await toMainUi(); // 切换到主界面
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 抛出错误函数
|
||||
* 该函数用于显示错误通知并抛出错误对象
|
||||
* @param {string} msg - 错误信息,将用于通知和错误对象
|
||||
*/
|
||||
function throwError(msg) {
|
||||
// 使用notification组件显示错误通知
|
||||
// notification.error(`${msg}`);
|
||||
if (setting.isNotification) {
|
||||
notification.error(`${msg}`);
|
||||
}
|
||||
// 抛出一个包含错误信息的Error对象
|
||||
throw new Error(`${msg}`);
|
||||
}
|
||||
|
||||
// 判断是否在主界面的函数
|
||||
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 = 300
|
||||
let index = 1
|
||||
await sleep(ms);
|
||||
while (!isInMainUI()) {
|
||||
await sleep(ms);
|
||||
await genshin.returnMainUi(); // 如果未启用,则返回游戏主界面
|
||||
await sleep(ms);
|
||||
if (index > 3) {
|
||||
throwError(`多次尝试返回主界面失败`);
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.physical = {
|
||||
ocrPhysical,
|
||||
MinPhysical,
|
||||
OpenModeCountMin,
|
||||
AlreadyRunsCount,
|
||||
NeedRunsCount,
|
||||
}
|
||||
Reference in New Issue
Block a user