mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-16 03:33:25 +08:00
[AutoLeyLineOutcrop]修复潜在的已释放对象访问问题 (#2161)
* [AutoLeyLineOutcrop]修复潜在的已释放对象访问问题 * update manifest.json
This commit is contained in:
@@ -525,13 +525,15 @@ async function openOutcrop(targetPath) {
|
||||
keyPress("F");
|
||||
|
||||
while (Date.now() - startTime < 5000) {
|
||||
captureRegion = captureGameRegion();
|
||||
if (recognizeFightText(captureRegion)) {
|
||||
recognized = true;
|
||||
let captureRegion = captureGameRegion();
|
||||
try {
|
||||
if (recognizeFightText(captureRegion)) {
|
||||
recognized = true;
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
captureRegion.dispose();
|
||||
break;
|
||||
}
|
||||
captureRegion.dispose();
|
||||
keyPress("F");
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "全自动地脉花",
|
||||
"version": "4.3.1",
|
||||
"version": "4.3.2",
|
||||
"tags": ["地脉花"],
|
||||
"bgi_version": "0.44.7",
|
||||
"description": "基于OCR图像识别的全自动刷取地脉花。\n💡更多信息请查看在线手册:https://hcnsvf0s8d0s.feishu.cn/wiki/Tb1twpThLi7UlykqcYOcuccTnjJ \n\n----------注意事项----------\n●仅支持BetterGI 0.44.7 及以上版本!\n●部分地脉花因特殊原因不支持全自动,具体的点位请在手册中查看。\n●树脂使用的优先级:2倍原粹树脂 > 浓缩树脂 > 原粹树脂。\n●运行时会传送到七天神像设置中设置的七天神像,需要关闭七天神像设置中的“是否就近七天神像恢复血量”,并指定七天神像。\n●战斗策略注意调度器设置中地图追踪行走配置里的“允许在JsSpript中使用”和“覆盖JS中的自动战斗配置”,只有在都打开的情况下脚本才会使用下面的战斗配置,否则会使用独立任务中的战斗策略。战斗超时时间不能大于脚本自定义配置中的时间。\n\n如果遇到问题,请先参照手册中的方法进行解决。",
|
||||
|
||||
@@ -43,13 +43,14 @@ this.clickWithVerification = async function(x, y, targetText, maxRetries = 20) {
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
this.verifyRewardPage = async function() {
|
||||
let captureRegion = null;
|
||||
|
||||
try {
|
||||
let captureRegion = captureGameRegion();
|
||||
captureRegion = captureGameRegion();
|
||||
|
||||
// 使用OCR识别上半区域
|
||||
let ocrRo = RecognitionObject.Ocr(0, 0, captureRegion.width, captureRegion.height / 2);
|
||||
let textList = captureRegion.findMulti(ocrRo);
|
||||
captureRegion.dispose();
|
||||
|
||||
let isValid = false;
|
||||
if (textList && textList.count > 0) {
|
||||
@@ -74,17 +75,24 @@ this.verifyRewardPage = async function() {
|
||||
} catch (error) {
|
||||
log.error(`验证奖励界面失败: ${error.message}`);
|
||||
return false;
|
||||
} finally {
|
||||
if (captureRegion) {
|
||||
captureRegion.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查原粹树脂是否耗尽(通过OCR识别"补充"文字)
|
||||
* 如果原粹树脂耗尽,第一个按钮会变成"补充"按钮
|
||||
* @param {ImageRegion} captureRegion - 截图区域
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function checkOriginalResinEmpty(captureRegion) {
|
||||
async function checkOriginalResinEmpty() {
|
||||
let captureRegion = null;
|
||||
|
||||
try {
|
||||
captureRegion = captureGameRegion();
|
||||
|
||||
// 使用OCR识别"补充"文字
|
||||
let ocrRo = RecognitionObject.Ocr(0, 0, captureRegion.width, captureRegion.height);
|
||||
let textList = captureRegion.findMulti(ocrRo);
|
||||
@@ -103,17 +111,24 @@ async function checkOriginalResinEmpty(captureRegion) {
|
||||
} catch (error) {
|
||||
log.error(`检查原粹树脂状态失败: ${error.message}`);
|
||||
return false;
|
||||
} finally {
|
||||
if (captureRegion) {
|
||||
captureRegion.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找并排序所有使用按钮(通过OCR识别"使用"文字)
|
||||
* 注意:如果原粹树脂耗尽,第一个位置是"补充"按钮,不会被识别为"使用"按钮
|
||||
* @param {ImageRegion} captureRegion - 截图区域
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
async function findAndSortUseButtons(captureRegion) {
|
||||
async function findAndSortUseButtons() {
|
||||
let captureRegion = null;
|
||||
|
||||
try {
|
||||
captureRegion = captureGameRegion();
|
||||
|
||||
// 使用OCR识别所有"使用"文字
|
||||
let ocrRo = RecognitionObject.Ocr(0, 0, captureRegion.width, captureRegion.height);
|
||||
let textList = captureRegion.findMulti(ocrRo);
|
||||
@@ -170,18 +185,25 @@ async function findAndSortUseButtons(captureRegion) {
|
||||
} catch (error) {
|
||||
log.error(`查找使用按钮失败: ${error.message}`);
|
||||
return [];
|
||||
} finally {
|
||||
if (captureRegion) {
|
||||
captureRegion.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析树脂选项并决定使用哪个
|
||||
* @param {ImageRegion} captureRegion - 截图区域
|
||||
* @param {Array} sortedButtons - 排序后的使用按钮数组
|
||||
* @param {boolean} isOriginalResinEmpty - 原粹树脂是否耗尽
|
||||
* @returns {Promise<Object|null>}
|
||||
*/
|
||||
async function analyzeResinOptions(captureRegion, sortedButtons, isOriginalResinEmpty) {
|
||||
async function analyzeResinOptions(sortedButtons, isOriginalResinEmpty) {
|
||||
let captureRegion = null;
|
||||
|
||||
try {
|
||||
captureRegion = captureGameRegion();
|
||||
|
||||
// OCR识别整个界面的文本
|
||||
let ocrRo = RecognitionObject.Ocr(0, 0, captureRegion.width, captureRegion.height);
|
||||
let textList = captureRegion.findMulti(ocrRo);
|
||||
@@ -287,7 +309,7 @@ async function analyzeResinOptions(captureRegion, sortedButtons, isOriginalResin
|
||||
if (hasDoubleReward && (hasOriginalResin20 || hasOriginalResin40)) {
|
||||
// 如果当前是20个原粹树脂,先尝试切换到40个
|
||||
if (hasOriginalResin20 && !hasOriginalResin40) {
|
||||
let switchSuccess = await trySwitch20To40Resin(captureRegion);
|
||||
let switchSuccess = await trySwitch20To40Resin();
|
||||
if (switchSuccess) {
|
||||
choice = {
|
||||
type: "使用40个原粹树脂(从20切换,双倍产出)",
|
||||
@@ -329,7 +351,7 @@ async function analyzeResinOptions(captureRegion, sortedButtons, isOriginalResin
|
||||
else if (hasOriginalResin20 || hasOriginalResin40) {
|
||||
// 如果当前是20个原粹树脂,先尝试切换到40个
|
||||
if (hasOriginalResin20 && !hasOriginalResin40) {
|
||||
let switchSuccess = await trySwitch20To40Resin(captureRegion);
|
||||
let switchSuccess = await trySwitch20To40Resin();
|
||||
if (switchSuccess) {
|
||||
choice = {
|
||||
type: "使用40个原粹树脂(从20切换)",
|
||||
@@ -363,7 +385,7 @@ async function analyzeResinOptions(captureRegion, sortedButtons, isOriginalResin
|
||||
else if (sortedButtons.length >= 1) {
|
||||
// 尝试切换到40个原粹树脂(如果当前是20个)
|
||||
if (hasOriginalResin20 && !hasOriginalResin40) {
|
||||
let switchSuccess = await trySwitch20To40Resin(captureRegion);
|
||||
let switchSuccess = await trySwitch20To40Resin();
|
||||
choice = {
|
||||
type: switchSuccess ? "默认使用40个原粹树脂(从20切换)" : "默认使用20个原粹树脂",
|
||||
button: sortedButtons[0],
|
||||
@@ -384,25 +406,35 @@ async function analyzeResinOptions(captureRegion, sortedButtons, isOriginalResin
|
||||
} catch (error) {
|
||||
log.error(`分析树脂选项失败: ${error.message}`);
|
||||
return null;
|
||||
} finally {
|
||||
if (captureRegion) {
|
||||
captureRegion.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试将20个原粹树脂切换到40个原粹树脂
|
||||
* @param {ImageRegion} captureRegion - 截图区域
|
||||
* @returns {Promise<boolean>} 是否成功切换
|
||||
*/
|
||||
async function trySwitch20To40Resin(captureRegion) {
|
||||
async function trySwitch20To40Resin() {
|
||||
let switchButtonIcon = null;
|
||||
let switchButtonRo = null;
|
||||
let currentCaptureRegion = null;
|
||||
let newCaptureRegion = null;
|
||||
|
||||
try {
|
||||
log.info("检测到20个原粹树脂,尝试切换到40个");
|
||||
|
||||
currentCaptureRegion = captureGameRegion();
|
||||
|
||||
// 检测切换按钮
|
||||
const switchButtonIcon = file.ReadImageMatSync("RecognitionObject/switch_button.png");
|
||||
const switchButtonRo = RecognitionObject.TemplateMatch(switchButtonIcon);
|
||||
switchButtonIcon = file.ReadImageMatSync("RecognitionObject/switch_button.png");
|
||||
switchButtonRo = RecognitionObject.TemplateMatch(switchButtonIcon);
|
||||
switchButtonRo.threshold = 0.7; // 设置合适的阈值
|
||||
|
||||
// 查找切换按钮
|
||||
let switchButtonPos = captureRegion.find(switchButtonRo);
|
||||
let switchButtonPos = currentCaptureRegion.find(switchButtonRo);
|
||||
|
||||
if (!switchButtonPos || switchButtonPos.isEmpty()) {
|
||||
log.info("未找到切换按钮(树脂不足40或按钮不可用),保持使用20个原粹树脂");
|
||||
@@ -415,10 +447,9 @@ async function trySwitch20To40Resin(captureRegion) {
|
||||
await sleep(800);
|
||||
|
||||
// 验证是否切换成功
|
||||
let newCaptureRegion = captureGameRegion();
|
||||
newCaptureRegion = captureGameRegion();
|
||||
let ocrRo = RecognitionObject.Ocr(0, 0, newCaptureRegion.width, newCaptureRegion.height);
|
||||
let textList = newCaptureRegion.findMulti(ocrRo);
|
||||
newCaptureRegion.dispose();
|
||||
|
||||
if (textList && textList.count > 0) {
|
||||
for (let i = 0; i < textList.count; i++) {
|
||||
@@ -437,6 +468,17 @@ async function trySwitch20To40Resin(captureRegion) {
|
||||
} catch (error) {
|
||||
log.error(`切换树脂数量失败: ${error.message}`);
|
||||
return false;
|
||||
} finally {
|
||||
if (currentCaptureRegion) {
|
||||
currentCaptureRegion.dispose();
|
||||
}
|
||||
if (newCaptureRegion) {
|
||||
newCaptureRegion.dispose();
|
||||
}
|
||||
if (switchButtonIcon) {
|
||||
switchButtonIcon.dispose();
|
||||
}
|
||||
switchButtonRo = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +515,7 @@ this.ensureExitRewardPage = async function() {
|
||||
attempts++;
|
||||
|
||||
// 检测是否在奖励界面
|
||||
let isInRewardPage = await verifyRewardPage();
|
||||
let isInRewardPage = await this.verifyRewardPage();
|
||||
|
||||
if (!isInRewardPage) {
|
||||
log.info("已确认不在奖励界面");
|
||||
@@ -510,7 +552,7 @@ this.attemptReward = async function (retryCount = 0) {
|
||||
await sleep(800);
|
||||
|
||||
// 步骤1: 验证是否在奖励界面
|
||||
if (!await verifyRewardPage()) {
|
||||
if (!await this.verifyRewardPage()) {
|
||||
log.warn("当前不在奖励界面,尝试重试");
|
||||
await genshin.returnMainUi();
|
||||
await sleep(1000);
|
||||
@@ -518,32 +560,41 @@ this.attemptReward = async function (retryCount = 0) {
|
||||
return await this.attemptReward(++retryCount);
|
||||
}
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let isOriginalResinEmpty = false;
|
||||
let sortedButtons = [];
|
||||
let resinChoice = null;
|
||||
|
||||
// 步骤2: 检查原粹树脂是否耗尽(通过"补充"按钮)
|
||||
let isOriginalResinEmpty = await checkOriginalResinEmpty(captureRegion);
|
||||
|
||||
// 步骤3: 识别所有使用按钮并排序
|
||||
let sortedButtons = await findAndSortUseButtons(captureRegion);
|
||||
|
||||
if (sortedButtons.length === 0) {
|
||||
log.error("未找到任何使用按钮");
|
||||
captureRegion.dispose();
|
||||
try {
|
||||
// 步骤2: 检查原粹树脂是否耗尽(通过"补充"按钮)
|
||||
isOriginalResinEmpty = await checkOriginalResinEmpty();
|
||||
|
||||
// 步骤3: 识别所有使用按钮并排序
|
||||
sortedButtons = await findAndSortUseButtons();
|
||||
|
||||
if (sortedButtons.length === 0) {
|
||||
log.error("未找到任何使用按钮");
|
||||
keyPress("VK_ESCAPE");
|
||||
await sleep(500);
|
||||
await this.ensureExitRewardPage();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 步骤4: 根据原粹树脂状态调整决策逻辑
|
||||
resinChoice = await analyzeResinOptions(sortedButtons, isOriginalResinEmpty);
|
||||
|
||||
if (!resinChoice) {
|
||||
// 已在 analyzeResinOptions 中输出详细错误信息,这里不再重复
|
||||
keyPress("VK_ESCAPE");
|
||||
await sleep(500);
|
||||
await this.ensureExitRewardPage();
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
log.error(`处理奖励界面时出错: ${error.message}`);
|
||||
keyPress("VK_ESCAPE");
|
||||
await sleep(500);
|
||||
await ensureExitRewardPage();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 步骤4: 根据原粹树脂状态调整决策逻辑
|
||||
let resinChoice = await analyzeResinOptions(captureRegion, sortedButtons, isOriginalResinEmpty);
|
||||
|
||||
if (!resinChoice) {
|
||||
// 已在 analyzeResinOptions 中输出详细错误信息,这里不再重复
|
||||
captureRegion.dispose();
|
||||
keyPress("VK_ESCAPE");
|
||||
await sleep(500);
|
||||
await ensureExitRewardPage();
|
||||
await this.ensureExitRewardPage();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -557,13 +608,11 @@ this.attemptReward = async function (retryCount = 0) {
|
||||
await switchBackToCombatTeam();
|
||||
}
|
||||
|
||||
captureRegion.dispose();
|
||||
|
||||
// 等待领奖动画/道具到账
|
||||
await sleep(1200);
|
||||
|
||||
// 确保完全退出奖励界面
|
||||
await ensureExitRewardPage();
|
||||
await this.ensureExitRewardPage();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -59,8 +59,9 @@ async function() {
|
||||
await sleep(2000);
|
||||
|
||||
// 浓缩树脂识别
|
||||
let Condensed = captureGameRegion().find(CondensedRo);
|
||||
Condensed.dispose();
|
||||
let condensedCaptureRegion = captureGameRegion();
|
||||
let Condensed = condensedCaptureRegion.find(CondensedRo);
|
||||
condensedCaptureRegion.dispose();
|
||||
let Isfive = false;
|
||||
if (Condensed.isExist()) {
|
||||
log.info("识别到浓缩树脂");
|
||||
|
||||
Reference in New Issue
Block a user