mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-04 06:46:19 +08:00
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "纳塔11-呼呼丘-1",
|
||||
"bgi_version": "0.45.0",
|
||||
"type": "collect",
|
||||
"order": 0,
|
||||
"tags": [],
|
||||
"enable_monster_loot_split": false,
|
||||
"map_name": "Teyvat",
|
||||
"map_match_method": "",
|
||||
"items": [],
|
||||
"authors": [],
|
||||
"version": "1.0",
|
||||
"description": "",
|
||||
"last_modified_time": 1754200248662
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"x": 14248.3935546875,
|
||||
"y": 581.4296875,
|
||||
"type": "target",
|
||||
"move_mode": "walk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "纳塔11-呼呼丘-2",
|
||||
"bgi_version": "0.45.0",
|
||||
"type": "collect",
|
||||
"order": 0,
|
||||
"tags": [],
|
||||
"enable_monster_loot_split": false,
|
||||
"map_name": "Teyvat",
|
||||
"map_match_method": "",
|
||||
"items": [],
|
||||
"authors": [],
|
||||
"version": "1.0",
|
||||
"description": "",
|
||||
"last_modified_time": 1754200241832
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"x": 14309.2685546875,
|
||||
"y": 462.38916015625,
|
||||
"type": "target",
|
||||
"move_mode": "walk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "纳塔11-呼呼丘-3",
|
||||
"bgi_version": "0.45.0",
|
||||
"type": "collect",
|
||||
"order": 0,
|
||||
"tags": [],
|
||||
"enable_monster_loot_split": false,
|
||||
"map_name": "Teyvat",
|
||||
"map_match_method": "",
|
||||
"items": [],
|
||||
"authors": [],
|
||||
"version": "1.0",
|
||||
"description": "",
|
||||
"last_modified_time": 1754200188083
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"x": 14390.443359375,
|
||||
"y": 470.20263671875,
|
||||
"type": "target",
|
||||
"move_mode": "walk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "纳塔12-浪浪湾-1",
|
||||
"bgi_version": "0.45.0",
|
||||
"type": "collect",
|
||||
"order": 0,
|
||||
"tags": [],
|
||||
"enable_monster_loot_split": false,
|
||||
"map_name": "Teyvat",
|
||||
"map_match_method": "",
|
||||
"items": [],
|
||||
"authors": [],
|
||||
"version": "1.0",
|
||||
"description": "",
|
||||
"last_modified_time": 1754569850355
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"x": 14799.513671875,
|
||||
"y": 631.3671875,
|
||||
"type": "target",
|
||||
"move_mode": "walk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "纳塔12-浪浪湾-2",
|
||||
"bgi_version": "0.45.0",
|
||||
"type": "collect",
|
||||
"order": 0,
|
||||
"tags": [],
|
||||
"enable_monster_loot_split": false,
|
||||
"map_name": "Teyvat",
|
||||
"map_match_method": "",
|
||||
"items": [],
|
||||
"authors": [],
|
||||
"version": "1.0",
|
||||
"description": "",
|
||||
"last_modified_time": 1754570057671
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"x": 14801.615234375,
|
||||
"y": 740.56103515625,
|
||||
"type": "target",
|
||||
"move_mode": "walk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "纳塔12-浪浪湾-3",
|
||||
"bgi_version": "0.45.0",
|
||||
"type": "collect",
|
||||
"order": 0,
|
||||
"tags": [],
|
||||
"enable_monster_loot_split": false,
|
||||
"map_name": "Teyvat",
|
||||
"map_match_method": "",
|
||||
"items": [],
|
||||
"authors": [],
|
||||
"version": "1.0",
|
||||
"description": "",
|
||||
"last_modified_time": 1754570352636
|
||||
},
|
||||
"positions": [
|
||||
{
|
||||
"id": 1,
|
||||
"x": 14870.0927734375,
|
||||
"y": 807.755859375,
|
||||
"type": "target",
|
||||
"move_mode": "walk"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -118,7 +118,9 @@ async function prepareForLeyLineRun() {
|
||||
await genshin.switchParty(settings.team);
|
||||
}
|
||||
// 3. 关闭自定义标记
|
||||
await closeCustomMarks();
|
||||
if (!settings.useAdventurerHandbook) {
|
||||
await closeCustomMarks();
|
||||
}
|
||||
// 4. 添加自动拾取实时任务
|
||||
// TODO: 个性化拾取策略
|
||||
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "全自动地脉花",
|
||||
"version": "4.1.5",
|
||||
"version": "4.1.6",
|
||||
"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如果遇到问题,请先参照手册中的方法进行解决。",
|
||||
|
||||
@@ -1,134 +1,138 @@
|
||||
/**
|
||||
* 带验证的单击函数
|
||||
* @param {number} x - X坐标
|
||||
* @param {number} y - Y坐标
|
||||
* @param {string} targetText - 需要验证消失的目标文字
|
||||
* @param {number} maxRetries - 最大重试次数,默认为10
|
||||
* @returns {Promise<boolean>} 是否成功
|
||||
*/
|
||||
this.clickWithVerification = async function(x, y, targetText, maxRetries = 20) {
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
keyUp("LBUTTON");
|
||||
click(x, y);
|
||||
await sleep(400);
|
||||
|
||||
// 验证目标文字是否消失
|
||||
let captureRegion = captureGameRegion();
|
||||
let resList = captureRegion.findMulti(ocrRoThis);
|
||||
captureRegion.dispose();
|
||||
let textFound = false;
|
||||
|
||||
if (resList && resList.count > 0) {
|
||||
for (let j = 0; j < resList.count; j++) {
|
||||
if (resList[j].text.includes(targetText)) {
|
||||
textFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果文字消失了,说明点击成功
|
||||
if (!textFound) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
log.warn(`经过${maxRetries}次点击,文字"${targetText}"仍未消失`);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试领取地脉花奖励
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.attemptReward = async function (retryCount = 0) {
|
||||
const MAX_RETRY = 3;
|
||||
if (retryCount >= MAX_RETRY) {
|
||||
throw new Error("超过最大重试次数,领取奖励失败");
|
||||
}
|
||||
|
||||
log.info("开始领取地脉奖励");
|
||||
keyPress("F");
|
||||
await sleep(500);
|
||||
|
||||
// 识别是否为地脉之花界面
|
||||
let captureRegion = captureGameRegion();
|
||||
let resList = captureRegion.findMulti(ocrRoThis); // 使用预定义的ocrRoThis对象
|
||||
captureRegion.dispose();
|
||||
let isValid = false;
|
||||
let condensedResin = null;
|
||||
let originalResin = null;
|
||||
let fragileResin = null;
|
||||
let isResinEmpty = false;
|
||||
let dobuleReward = false;
|
||||
|
||||
if (resList && resList.count > 0) {
|
||||
// 分析识别到的文本
|
||||
for (let i = 0; i < resList.count; i++) {
|
||||
let res = resList[i];
|
||||
if (res.text.includes("浓缩树脂")) {
|
||||
isValid = true;
|
||||
condensedResin = res;
|
||||
} else if (res.text.includes("原粹树脂")) {
|
||||
isValid = true;
|
||||
originalResin = res;
|
||||
} else if (res.text.includes("脆弱树脂") && settings.fragileResin) {
|
||||
isValid = true;
|
||||
fragileResin = res;
|
||||
} else if (res.text.includes("双倍掉落")) {
|
||||
isValid = true;
|
||||
dobuleReward = true;
|
||||
} else {
|
||||
isValid = true;
|
||||
isResinEmpty = true;
|
||||
}
|
||||
} // 处理不同的树脂情况
|
||||
if (originalResin && dobuleReward) {
|
||||
log.info("选择使用原粹树脂,获得双倍产出");
|
||||
await clickWithVerification(
|
||||
Math.round(originalResin.x + originalResin.width / 2) + 400,
|
||||
Math.round(originalResin.y + originalResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (condensedResin) {
|
||||
log.info("选择使用浓缩树脂");
|
||||
await clickWithVerification(
|
||||
Math.round(condensedResin.x + condensedResin.width / 2) + 400,
|
||||
Math.round(condensedResin.y + condensedResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (originalResin) {
|
||||
log.info("选择使用原粹树脂");
|
||||
await clickWithVerification(
|
||||
Math.round(originalResin.x + originalResin.width / 2) + 400,
|
||||
Math.round(originalResin.y + originalResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (fragileResin) {
|
||||
log.info("选择使用脆弱树脂");
|
||||
await clickWithVerification(
|
||||
Math.round(fragileResin.x + fragileResin.width / 2) + 400,
|
||||
Math.round(fragileResin.y + fragileResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (isResinEmpty) {
|
||||
log.error("树脂用完了呢");
|
||||
keyPress("VK_ESCAPE");
|
||||
throw new Error("树脂已用完");
|
||||
}
|
||||
if (settings.friendshipTeam) {
|
||||
log.info("切换回战斗队伍");
|
||||
await sleep(500);
|
||||
const switchSuccess = await switchTeam(settings.team);
|
||||
}
|
||||
}
|
||||
|
||||
// 界面不正确,尝试重试
|
||||
if (!isValid) {
|
||||
log.info("当前界面不是地脉之花界面,重试");
|
||||
await genshin.returnMainUi();
|
||||
await sleep(1000);
|
||||
await autoNavigateToReward();
|
||||
await attemptReward(++retryCount);
|
||||
}
|
||||
/**
|
||||
* 带验证的单击函数
|
||||
* @param {number} x - X坐标
|
||||
* @param {number} y - Y坐标
|
||||
* @param {string} targetText - 需要验证消失的目标文字
|
||||
* @param {number} maxRetries - 最大重试次数,默认为10
|
||||
* @returns {Promise<boolean>} 是否成功
|
||||
*/
|
||||
this.clickWithVerification = async function(x, y, targetText, maxRetries = 20) {
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
keyUp("LBUTTON");
|
||||
click(x, y);
|
||||
await sleep(400);
|
||||
|
||||
// 验证目标文字是否消失
|
||||
let captureRegion = captureGameRegion();
|
||||
let resList = captureRegion.findMulti(ocrRoThis);
|
||||
captureRegion.dispose();
|
||||
let textFound = false;
|
||||
|
||||
if (resList && resList.count > 0) {
|
||||
for (let j = 0; j < resList.count; j++) {
|
||||
if (resList[j].text.includes(targetText)) {
|
||||
textFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果文字消失了,说明点击成功
|
||||
if (!textFound) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
log.warn(`经过${maxRetries}次点击,文字"${targetText}"仍未消失`);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试领取地脉花奖励
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.attemptReward = async function (retryCount = 0) {
|
||||
const MAX_RETRY = 3;
|
||||
if (retryCount >= MAX_RETRY) {
|
||||
throw new Error("超过最大重试次数,领取奖励失败");
|
||||
}
|
||||
|
||||
log.info("开始领取地脉奖励");
|
||||
keyPress("F");
|
||||
await sleep(500);
|
||||
|
||||
// 识别是否为地脉之花界面
|
||||
let captureRegion = captureGameRegion();
|
||||
let resList = captureRegion.findMulti(ocrRoThis); // 使用预定义的ocrRoThis对象
|
||||
captureRegion.dispose();
|
||||
let isValid = false;
|
||||
let condensedResin = null;
|
||||
let originalResin = null;
|
||||
let fragileResin = null;
|
||||
let isResinEmpty = false;
|
||||
let dobuleReward = false;
|
||||
let isOriginalResinEmpty = false;
|
||||
|
||||
if (resList && resList.count > 0) {
|
||||
// 分析识别到的文本
|
||||
for (let i = 0; i < resList.count; i++) {
|
||||
let res = resList[i];
|
||||
if (res.text.includes("浓缩树脂")) {
|
||||
isValid = true;
|
||||
condensedResin = res;
|
||||
} else if (res.text.includes("原粹树脂")) {
|
||||
isValid = true;
|
||||
originalResin = res;
|
||||
} else if (res.text.includes("脆弱树脂") && settings.fragileResin) {
|
||||
isValid = true;
|
||||
fragileResin = res;
|
||||
} else if (res.text.includes("双倍掉落")) {
|
||||
isValid = true;
|
||||
dobuleReward = true;
|
||||
} else if (res.text.includes("补充")){
|
||||
isValid = true;
|
||||
isOriginalResinEmpty = true;
|
||||
} else {
|
||||
isValid = true;
|
||||
isResinEmpty = true;
|
||||
}
|
||||
} // 处理不同的树脂情况
|
||||
if (originalResin && dobuleReward && !isOriginalResinEmpty) {
|
||||
log.info("选择使用原粹树脂,获得双倍产出");
|
||||
await clickWithVerification(
|
||||
Math.round(originalResin.x + originalResin.width / 2) + 400,
|
||||
Math.round(originalResin.y + originalResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (condensedResin) {
|
||||
log.info("选择使用浓缩树脂");
|
||||
await clickWithVerification(
|
||||
Math.round(condensedResin.x + condensedResin.width / 2) + 400,
|
||||
Math.round(condensedResin.y + condensedResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (originalResin && !isOriginalResinEmpty) {
|
||||
log.info("选择使用原粹树脂");
|
||||
await clickWithVerification(
|
||||
Math.round(originalResin.x + originalResin.width / 2) + 400,
|
||||
Math.round(originalResin.y + originalResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (fragileResin) {
|
||||
log.info("选择使用脆弱树脂");
|
||||
await clickWithVerification(
|
||||
Math.round(fragileResin.x + fragileResin.width / 2) + 400,
|
||||
Math.round(fragileResin.y + fragileResin.height / 2),
|
||||
"使用"
|
||||
);
|
||||
} else if (isResinEmpty && isOriginalResinEmpty) {
|
||||
log.error("树脂用完了呢");
|
||||
keyPress("VK_ESCAPE");
|
||||
throw new Error("原粹树脂不足20,无法领取奖励");
|
||||
}
|
||||
if (settings.friendshipTeam) {
|
||||
log.info("切换回战斗队伍");
|
||||
await sleep(500);
|
||||
const switchSuccess = await switchTeam(settings.team);
|
||||
}
|
||||
}
|
||||
|
||||
// 界面不正确,尝试重试
|
||||
if (!isValid) {
|
||||
log.info("当前界面不是地脉之花界面,重试");
|
||||
await genshin.returnMainUi();
|
||||
await sleep(1000);
|
||||
await autoNavigateToReward();
|
||||
await attemptReward(++retryCount);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,75 @@
|
||||
/**
|
||||
* 使用广度优先搜索算法查找从传送点到目标的所有路径
|
||||
* @param {Object} nodeData - 节点数据
|
||||
* @param {Object} targetNode - 目标节点
|
||||
* @param {Object} nodeMap - 节点映射
|
||||
* @returns {Array} 找到的所有可行路径
|
||||
*/
|
||||
this.breadthFirstPathSearch =
|
||||
function (nodeData, targetNode, nodeMap) {
|
||||
// 存储找到的所有有效路径
|
||||
const validPaths = [];
|
||||
|
||||
// 获取所有传送点作为起点
|
||||
const teleportNodes = nodeData.node.filter(node => node.type === "teleport");
|
||||
log.debug(`找到 ${teleportNodes.length} 个传送点作为可能的起点`);
|
||||
|
||||
// 对每个传送点,尝试查找到目标的路径
|
||||
for (const startNode of teleportNodes) {
|
||||
// 初始化队列,每个元素包含 [当前节点, 路径信息]
|
||||
const queue = [[startNode, {
|
||||
startNode: startNode,
|
||||
routes: [],
|
||||
visitedNodes: new Set([startNode.id])
|
||||
}]];
|
||||
|
||||
// 广度优先搜索
|
||||
while (queue.length > 0) {
|
||||
const [currentNode, pathInfo] = queue.shift();
|
||||
|
||||
// 如果已经到达目标节点
|
||||
if (currentNode.id === targetNode.id) {
|
||||
validPaths.push({
|
||||
startNode: pathInfo.startNode,
|
||||
targetNode: targetNode,
|
||||
routes: [...pathInfo.routes]
|
||||
});
|
||||
continue; // 找到一条路径,继续搜索其他可能路径
|
||||
}
|
||||
|
||||
// 检查当前节点的下一个连接
|
||||
if (currentNode.next && currentNode.next.length > 0) {
|
||||
for (const nextRoute of currentNode.next) {
|
||||
const nextNodeId = nextRoute.target;
|
||||
|
||||
// 避免循环
|
||||
if (pathInfo.visitedNodes.has(nextNodeId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const nextNode = nodeMap[nextNodeId];
|
||||
if (!nextNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建新的路径信息
|
||||
const newPathInfo = {
|
||||
startNode: pathInfo.startNode,
|
||||
routes: [...pathInfo.routes, nextRoute.route],
|
||||
visitedNodes: new Set([...pathInfo.visitedNodes, nextNodeId])
|
||||
};
|
||||
|
||||
// 加入队列
|
||||
queue.push([nextNode, newPathInfo]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否存在反向路径
|
||||
const reversePaths = findReversePathsIfNeeded(nodeData, targetNode, nodeMap, validPaths);
|
||||
validPaths.push(...reversePaths);
|
||||
|
||||
log.debug(`共找到 ${validPaths.length} 条有效路径`);
|
||||
return validPaths;
|
||||
/**
|
||||
* 使用广度优先搜索算法查找从传送点到目标的所有路径
|
||||
* @param {Object} nodeData - 节点数据
|
||||
* @param {Object} targetNode - 目标节点
|
||||
* @param {Object} nodeMap - 节点映射
|
||||
* @returns {Array} 找到的所有可行路径
|
||||
*/
|
||||
this.breadthFirstPathSearch =
|
||||
function (nodeData, targetNode, nodeMap) {
|
||||
// 存储找到的所有有效路径
|
||||
const validPaths = [];
|
||||
|
||||
// 获取所有传送点作为起点
|
||||
const teleportNodes = nodeData.node.filter(node => node.type === "teleport");
|
||||
log.debug(`找到 ${teleportNodes.length} 个传送点作为可能的起点`);
|
||||
|
||||
// 对每个传送点,尝试查找到目标的路径
|
||||
for (const startNode of teleportNodes) {
|
||||
// 初始化队列,每个元素包含 [当前节点, 路径信息]
|
||||
const queue = [[startNode, {
|
||||
startNode: startNode,
|
||||
routes: [],
|
||||
visitedNodes: new Set([startNode.id])
|
||||
}]];
|
||||
|
||||
// 广度优先搜索
|
||||
while (queue.length > 0) {
|
||||
const [currentNode, pathInfo] = queue.shift();
|
||||
|
||||
// 如果已经到达目标节点
|
||||
if (currentNode.id === targetNode.id) {
|
||||
validPaths.push({
|
||||
startNode: pathInfo.startNode,
|
||||
targetNode: targetNode,
|
||||
routes: [...pathInfo.routes]
|
||||
});
|
||||
continue; // 找到一条路径,继续搜索其他可能路径
|
||||
}
|
||||
|
||||
// 检查当前节点的下一个连接
|
||||
if (currentNode.next && currentNode.next.length > 0) {
|
||||
for (const nextRoute of currentNode.next) {
|
||||
const nextNodeId = nextRoute.target;
|
||||
|
||||
// 避免循环
|
||||
if (pathInfo.visitedNodes.has(nextNodeId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const nextNode = nodeMap[nextNodeId];
|
||||
if (!nextNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建新的路径信息
|
||||
const newPathInfo = {
|
||||
startNode: pathInfo.startNode,
|
||||
routes: [...pathInfo.routes, nextRoute.route],
|
||||
visitedNodes: new Set([...pathInfo.visitedNodes, nextNodeId])
|
||||
};
|
||||
|
||||
// 加入队列
|
||||
queue.push([nextNode, newPathInfo]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否存在反向路径
|
||||
const reversePaths = findReversePathsIfNeeded(nodeData, targetNode, nodeMap, validPaths);
|
||||
validPaths.push(...reversePaths);
|
||||
|
||||
log.debug(`共找到 ${validPaths.length} 条有效路径`);
|
||||
return validPaths;
|
||||
}
|
||||
@@ -1,158 +1,158 @@
|
||||
/**
|
||||
* 使用节点数据执行路径
|
||||
* @param {Object} position - 位置对象
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.executePathsUsingNodeData = async function (position) {
|
||||
try {
|
||||
const nodeData = await loadNodeData();
|
||||
let currentNodePosition = position;
|
||||
const targetNode = findTargetNodeByPosition(nodeData, currentNodePosition.x, currentNodePosition.y);
|
||||
|
||||
if (!targetNode) {
|
||||
log.error(`未找到与坐标(${currentNodePosition.x}, ${currentNodePosition.y})匹配的目标节点`);
|
||||
return;
|
||||
}
|
||||
log.debug(`找到目标节点: ID ${targetNode.id}, 位置(${targetNode.position.x}, ${targetNode.position.y})`);
|
||||
const paths = findPathsToTarget(nodeData, targetNode);
|
||||
|
||||
if (paths.length === 0) {
|
||||
log.error(`未找到通向目标节点(ID: ${targetNode.id})的路径`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 选择最短的路径执行
|
||||
const optimalPath = selectOptimalPath(paths);
|
||||
log.debug(`选择了含有 ${optimalPath.routes.length} 个路径点的最优路径`);
|
||||
|
||||
// 执行路径
|
||||
await executePath(optimalPath);
|
||||
currentRunTimes++;
|
||||
|
||||
// 如果达到刷取次数上限,退出循环
|
||||
if (currentRunTimes >= settings.timesValue) {
|
||||
return;
|
||||
}
|
||||
let currentNode = targetNode;
|
||||
log.debug(`开始处理节点链,目标节点ID: ${targetNode.id}, next数量: ${targetNode.next ? targetNode.next.length : 'undefined'}`);
|
||||
|
||||
while (currentNode.next && currentRunTimes < settings.timesValue) {
|
||||
log.debug(`当前节点ID: ${currentNode.id}, next数量: ${currentNode.next.length}`);
|
||||
if (currentNode.next.length === 1) { // 获取下一个节点的ID 和 路径,并在节点数据中找到下一个节点
|
||||
const nextNodeId = currentNode.next[0].target;
|
||||
const nextRoute = currentNode.next[0].route;
|
||||
log.debug(`单一路径: 从节点${currentNode.id}到节点${nextNodeId}, 路径: ${nextRoute}`);
|
||||
const nextNode = nodeData.node.find(node => node.id === nextNodeId);
|
||||
|
||||
if (!nextNode) {
|
||||
return;
|
||||
}
|
||||
const pathObject = {
|
||||
startNode: currentNode,
|
||||
targetNode: nextNode,
|
||||
routes: [nextRoute]
|
||||
};
|
||||
|
||||
log.info(`直接执行下一个节点路径: ${nextRoute}`);
|
||||
await executePath(pathObject);
|
||||
|
||||
currentRunTimes++;
|
||||
|
||||
log.info(`完成节点 ID ${nextNodeId}, 已执行 ${currentRunTimes}/${settings.timesValue} 次`); // 更新当前节点为下一个节点,继续检查
|
||||
currentNode = nextNode;
|
||||
currentNodePosition = { x: nextNode.position.x, y: nextNode.position.y };
|
||||
}
|
||||
else if (currentNode.next.length > 1) {
|
||||
// 如果存在分支路线,先打开大地图判断下一个地脉花的位置,然后结合顺序边缘数据选择最优路线
|
||||
log.info("检测到多个分支路线,开始查找下一个地脉花位置");
|
||||
|
||||
// 备份当前地脉花坐标
|
||||
const currentLeyLineX = leyLineX;
|
||||
const currentLeyLineY = leyLineY;
|
||||
|
||||
// 打开大地图
|
||||
await genshin.returnMainUi();
|
||||
keyPress("M");
|
||||
await sleep(1000);
|
||||
|
||||
// 查找下一个地脉花
|
||||
const found = await locateLeyLineOutcrop(settings.leyLineOutcropType);
|
||||
await genshin.returnMainUi();
|
||||
|
||||
if (!found) {
|
||||
log.warn("无法在分支点找到下一个地脉花,退出本次循环");
|
||||
return;
|
||||
}
|
||||
log.info(`找到下一个地脉花,位置: (${leyLineX}, ${leyLineY})`);
|
||||
|
||||
// 直接比较所有分支节点到地脉花的距离,选择最近的路径
|
||||
let selectedRoute = null;
|
||||
let selectedNodeId = null;
|
||||
let closestDistance = Infinity;
|
||||
for (const nextRoute of currentNode.next) {
|
||||
const branchNodeId = nextRoute.target;
|
||||
const branchNode = nodeData.node.find(node => node.id === branchNodeId);
|
||||
|
||||
if (!branchNode) continue;
|
||||
|
||||
const distance = calculate2DDistance(
|
||||
leyLineX, leyLineY,
|
||||
branchNode.position.x, branchNode.position.y
|
||||
);
|
||||
|
||||
log.info(`分支节点ID ${branchNodeId} 到地脉花距离: ${distance.toFixed(2)}`);
|
||||
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
selectedRoute = nextRoute.route;
|
||||
selectedNodeId = branchNodeId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedRoute) {
|
||||
log.error("无法找到合适的路线,终止执行");
|
||||
// 恢复原始坐标
|
||||
leyLineX = currentLeyLineX;
|
||||
leyLineY = currentLeyLineY;
|
||||
return;
|
||||
}
|
||||
const nextNode = nodeData.node.find(node => node.id === selectedNodeId);
|
||||
if (!nextNode) {
|
||||
log.error(`未找到节点ID ${selectedNodeId},终止执行`);
|
||||
// 恢复原始坐标
|
||||
leyLineX = currentLeyLineX;
|
||||
leyLineY = currentLeyLineY;
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`选择路线: ${selectedRoute}, 目标节点ID: ${selectedNodeId}`);
|
||||
|
||||
// 创建路径对象并执行
|
||||
const pathObject = {
|
||||
startNode: currentNode,
|
||||
targetNode: nextNode,
|
||||
routes: [selectedRoute]
|
||||
};
|
||||
await executePath(pathObject);
|
||||
currentRunTimes++;
|
||||
log.info(`完成节点 ID ${selectedNodeId}, 已执行 ${currentRunTimes}/${settings.timesValue} 次`);
|
||||
// 更新当前节点为下一个节点,继续检查
|
||||
currentNode = nextNode;
|
||||
currentNodePosition = { x: nextNode.position.x, y: nextNode.position.y };
|
||||
}
|
||||
else {
|
||||
log.info("当前路线完成,退出循环");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if(error.message.includes("战斗失败")) {
|
||||
log.error("战斗失败,重新寻找地脉花后重试");
|
||||
return;
|
||||
}
|
||||
// 其他错误需要向上传播
|
||||
log.error(`执行路径时出错: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
/**
|
||||
* 使用节点数据执行路径
|
||||
* @param {Object} position - 位置对象
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.executePathsUsingNodeData = async function (position) {
|
||||
try {
|
||||
const nodeData = await loadNodeData();
|
||||
let currentNodePosition = position;
|
||||
const targetNode = findTargetNodeByPosition(nodeData, currentNodePosition.x, currentNodePosition.y);
|
||||
|
||||
if (!targetNode) {
|
||||
log.error(`未找到与坐标(${currentNodePosition.x}, ${currentNodePosition.y})匹配的目标节点`);
|
||||
return;
|
||||
}
|
||||
log.debug(`找到目标节点: ID ${targetNode.id}, 位置(${targetNode.position.x}, ${targetNode.position.y})`);
|
||||
const paths = findPathsToTarget(nodeData, targetNode);
|
||||
|
||||
if (paths.length === 0) {
|
||||
log.error(`未找到通向目标节点(ID: ${targetNode.id})的路径`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 选择最短的路径执行
|
||||
const optimalPath = selectOptimalPath(paths);
|
||||
log.debug(`选择了含有 ${optimalPath.routes.length} 个路径点的最优路径`);
|
||||
|
||||
// 执行路径
|
||||
await executePath(optimalPath);
|
||||
currentRunTimes++;
|
||||
|
||||
// 如果达到刷取次数上限,退出循环
|
||||
if (currentRunTimes >= settings.timesValue) {
|
||||
return;
|
||||
}
|
||||
let currentNode = targetNode;
|
||||
log.debug(`开始处理节点链,目标节点ID: ${targetNode.id}, next数量: ${targetNode.next ? targetNode.next.length : 'undefined'}`);
|
||||
|
||||
while (currentNode.next && currentRunTimes < settings.timesValue) {
|
||||
log.debug(`当前节点ID: ${currentNode.id}, next数量: ${currentNode.next.length}`);
|
||||
if (currentNode.next.length === 1) { // 获取下一个节点的ID 和 路径,并在节点数据中找到下一个节点
|
||||
const nextNodeId = currentNode.next[0].target;
|
||||
const nextRoute = currentNode.next[0].route;
|
||||
log.debug(`单一路径: 从节点${currentNode.id}到节点${nextNodeId}, 路径: ${nextRoute}`);
|
||||
const nextNode = nodeData.node.find(node => node.id === nextNodeId);
|
||||
|
||||
if (!nextNode) {
|
||||
return;
|
||||
}
|
||||
const pathObject = {
|
||||
startNode: currentNode,
|
||||
targetNode: nextNode,
|
||||
routes: [nextRoute]
|
||||
};
|
||||
|
||||
log.info(`直接执行下一个节点路径: ${nextRoute}`);
|
||||
await executePath(pathObject);
|
||||
|
||||
currentRunTimes++;
|
||||
|
||||
log.info(`完成节点 ID ${nextNodeId}, 已执行 ${currentRunTimes}/${settings.timesValue} 次`); // 更新当前节点为下一个节点,继续检查
|
||||
currentNode = nextNode;
|
||||
currentNodePosition = { x: nextNode.position.x, y: nextNode.position.y };
|
||||
}
|
||||
else if (currentNode.next.length > 1) {
|
||||
// 如果存在分支路线,先打开大地图判断下一个地脉花的位置,然后结合顺序边缘数据选择最优路线
|
||||
log.info("检测到多个分支路线,开始查找下一个地脉花位置");
|
||||
|
||||
// 备份当前地脉花坐标
|
||||
const currentLeyLineX = leyLineX;
|
||||
const currentLeyLineY = leyLineY;
|
||||
|
||||
// 打开大地图
|
||||
await genshin.returnMainUi();
|
||||
keyPress("M");
|
||||
await sleep(1000);
|
||||
|
||||
// 查找下一个地脉花
|
||||
const found = await locateLeyLineOutcrop(settings.leyLineOutcropType);
|
||||
await genshin.returnMainUi();
|
||||
|
||||
if (!found) {
|
||||
log.warn("无法在分支点找到下一个地脉花,退出本次循环");
|
||||
return;
|
||||
}
|
||||
log.info(`找到下一个地脉花,位置: (${leyLineX}, ${leyLineY})`);
|
||||
|
||||
// 直接比较所有分支节点到地脉花的距离,选择最近的路径
|
||||
let selectedRoute = null;
|
||||
let selectedNodeId = null;
|
||||
let closestDistance = Infinity;
|
||||
for (const nextRoute of currentNode.next) {
|
||||
const branchNodeId = nextRoute.target;
|
||||
const branchNode = nodeData.node.find(node => node.id === branchNodeId);
|
||||
|
||||
if (!branchNode) continue;
|
||||
|
||||
const distance = calculate2DDistance(
|
||||
leyLineX, leyLineY,
|
||||
branchNode.position.x, branchNode.position.y
|
||||
);
|
||||
|
||||
log.info(`分支节点ID ${branchNodeId} 到地脉花距离: ${distance.toFixed(2)}`);
|
||||
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
selectedRoute = nextRoute.route;
|
||||
selectedNodeId = branchNodeId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedRoute) {
|
||||
log.error("无法找到合适的路线,终止执行");
|
||||
// 恢复原始坐标
|
||||
leyLineX = currentLeyLineX;
|
||||
leyLineY = currentLeyLineY;
|
||||
return;
|
||||
}
|
||||
const nextNode = nodeData.node.find(node => node.id === selectedNodeId);
|
||||
if (!nextNode) {
|
||||
log.error(`未找到节点ID ${selectedNodeId},终止执行`);
|
||||
// 恢复原始坐标
|
||||
leyLineX = currentLeyLineX;
|
||||
leyLineY = currentLeyLineY;
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`选择路线: ${selectedRoute}, 目标节点ID: ${selectedNodeId}`);
|
||||
|
||||
// 创建路径对象并执行
|
||||
const pathObject = {
|
||||
startNode: currentNode,
|
||||
targetNode: nextNode,
|
||||
routes: [selectedRoute]
|
||||
};
|
||||
await executePath(pathObject);
|
||||
currentRunTimes++;
|
||||
log.info(`完成节点 ID ${selectedNodeId}, 已执行 ${currentRunTimes}/${settings.timesValue} 次`);
|
||||
// 更新当前节点为下一个节点,继续检查
|
||||
currentNode = nextNode;
|
||||
currentNodePosition = { x: nextNode.position.x, y: nextNode.position.y };
|
||||
}
|
||||
else {
|
||||
log.info("当前路线完成,退出循环");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if(error.message.includes("战斗失败")) {
|
||||
log.error("战斗失败,重新寻找地脉花后重试");
|
||||
return;
|
||||
}
|
||||
// 其他错误需要向上传播
|
||||
log.error(`执行路径时出错: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +1,69 @@
|
||||
/**
|
||||
* 查找地脉花位置
|
||||
* @param {string} country - 国家名称
|
||||
* @param {string} type - 地脉花类型
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.findLeyLineOutcrop =
|
||||
async function (country, type) {
|
||||
currentFlower = null;
|
||||
await sleep(1000);
|
||||
log.info("开始寻找地脉花");
|
||||
if (!config.mapPositions[country] || config.mapPositions[country].length === 0) {
|
||||
throw new Error(`未找到国家 ${country} 的位置信息`);
|
||||
}
|
||||
|
||||
const positions = config.mapPositions[country];
|
||||
await genshin.moveMapTo(positions[0].x, positions[0].y, country);
|
||||
const found = await locateLeyLineOutcrop(type);
|
||||
await sleep(1000); // 移动后等一下
|
||||
if (found) return;
|
||||
for (let retryCount = 1; retryCount < positions.length; retryCount++) {
|
||||
const position = positions[retryCount];
|
||||
log.info(`第 ${retryCount + 1} 次尝试定位地脉花`);
|
||||
log.info(`移动到位置:(${position.x}, ${position.y}), ${position.name || '未命名位置'}`);
|
||||
await genshin.moveMapTo(position.x, position.y);
|
||||
|
||||
const found = await locateLeyLineOutcrop(type);
|
||||
if (found) return;
|
||||
}
|
||||
|
||||
// 如果到这里还没找到
|
||||
throw new Error("寻找地脉花失败,已达最大重试次数");
|
||||
}
|
||||
|
||||
/**
|
||||
* 在地图上定位地脉花
|
||||
* @param {string} type - 地脉花类型
|
||||
* @returns {Promise<boolean>} 是否找到地脉花
|
||||
*/
|
||||
this.locateLeyLineOutcrop =
|
||||
async function (type) {
|
||||
await sleep(500); // 确保画面稳定
|
||||
await genshin.setBigMapZoomLevel(3.0);
|
||||
|
||||
const iconPath = type === "蓝花(经验书)"
|
||||
? "assets/icon/Blossom_of_Revelation.png"
|
||||
: "assets/icon/Blossom_of_Wealth.png";
|
||||
|
||||
const captureRegion = captureGameRegion();
|
||||
const flowerList = captureRegion.findMulti(RecognitionObject.TemplateMatch(file.ReadImageMatSync(iconPath)));
|
||||
captureRegion.dispose();
|
||||
|
||||
if (flowerList && flowerList.count > 0) {
|
||||
currentFlower = flowerList[0];
|
||||
|
||||
const center = genshin.getPositionFromBigMap();
|
||||
const mapZoomLevel = genshin.getBigMapZoomLevel();
|
||||
const mapScaleFactor = 2.361;
|
||||
|
||||
leyLineX = (960 - currentFlower.x - 25) * mapZoomLevel / mapScaleFactor + center.x;
|
||||
leyLineY = (540 - currentFlower.y - 25) * mapZoomLevel / mapScaleFactor + center.y;
|
||||
|
||||
log.info(`找到地脉花的坐标:(${leyLineX}, ${leyLineY})`);
|
||||
return true;
|
||||
} else {
|
||||
log.warn("未找到地脉花");
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 查找地脉花位置
|
||||
* @param {string} country - 国家名称
|
||||
* @param {string} type - 地脉花类型
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.findLeyLineOutcrop =
|
||||
async function (country, type) {
|
||||
currentFlower = null;
|
||||
await sleep(1000);
|
||||
log.info("开始寻找地脉花");
|
||||
if (!config.mapPositions[country] || config.mapPositions[country].length === 0) {
|
||||
throw new Error(`未找到国家 ${country} 的位置信息`);
|
||||
}
|
||||
|
||||
const positions = config.mapPositions[country];
|
||||
await genshin.moveMapTo(positions[0].x, positions[0].y, country);
|
||||
const found = await locateLeyLineOutcrop(type);
|
||||
await sleep(1000); // 移动后等一下
|
||||
if (found) return;
|
||||
for (let retryCount = 1; retryCount < positions.length; retryCount++) {
|
||||
const position = positions[retryCount];
|
||||
log.info(`第 ${retryCount + 1} 次尝试定位地脉花`);
|
||||
log.info(`移动到位置:(${position.x}, ${position.y}), ${position.name || '未命名位置'}`);
|
||||
await genshin.moveMapTo(position.x, position.y);
|
||||
|
||||
const found = await locateLeyLineOutcrop(type);
|
||||
if (found) return;
|
||||
}
|
||||
|
||||
// 如果到这里还没找到
|
||||
throw new Error("寻找地脉花失败,已达最大重试次数");
|
||||
}
|
||||
|
||||
/**
|
||||
* 在地图上定位地脉花
|
||||
* @param {string} type - 地脉花类型
|
||||
* @returns {Promise<boolean>} 是否找到地脉花
|
||||
*/
|
||||
this.locateLeyLineOutcrop =
|
||||
async function (type) {
|
||||
await sleep(500); // 确保画面稳定
|
||||
await genshin.setBigMapZoomLevel(3.0);
|
||||
|
||||
const iconPath = type === "蓝花(经验书)"
|
||||
? "assets/icon/Blossom_of_Revelation.png"
|
||||
: "assets/icon/Blossom_of_Wealth.png";
|
||||
|
||||
const captureRegion = captureGameRegion();
|
||||
const flowerList = captureRegion.findMulti(RecognitionObject.TemplateMatch(file.ReadImageMatSync(iconPath)));
|
||||
captureRegion.dispose();
|
||||
|
||||
if (flowerList && flowerList.count > 0) {
|
||||
currentFlower = flowerList[0];
|
||||
|
||||
const center = genshin.getPositionFromBigMap();
|
||||
const mapZoomLevel = genshin.getBigMapZoomLevel();
|
||||
const mapScaleFactor = 2.361;
|
||||
|
||||
leyLineX = (960 - currentFlower.x - 25) * mapZoomLevel / mapScaleFactor + center.x;
|
||||
leyLineY = (540 - currentFlower.y - 25) * mapZoomLevel / mapScaleFactor + center.y;
|
||||
|
||||
log.info(`找到地脉花的坐标:(${leyLineX}, ${leyLineY})`);
|
||||
return true;
|
||||
} else {
|
||||
log.warn("未找到地脉花");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -25,14 +25,15 @@ async function (timeout, targetPath, retries = 0) {
|
||||
const result2 = captureRegion.find(ocrRo3);
|
||||
|
||||
// 检查地脉之花状态 - 已完成状态,准备领取奖励
|
||||
if (result2.text.includes("地脉之花")) {
|
||||
log.debug(`地脉花状态:${result2.text}`);
|
||||
if (result2.text.includes("之花")) {
|
||||
log.info("识别到地脉之花,准备领取奖励");
|
||||
await switchToFriendshipTeamIfNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理地脉溢口
|
||||
if (result2.text.includes("地脉溢口")) {
|
||||
if (result2.text.includes("溢口")) {
|
||||
log.info("识别到地脉溢口");
|
||||
keyPress("F");
|
||||
await sleep(300);
|
||||
|
||||
@@ -1,159 +1,159 @@
|
||||
/*
|
||||
代码迁移中,还未完成适配
|
||||
*/
|
||||
|
||||
|
||||
const CondensedRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/Condensed Resin.png"));
|
||||
const FragileRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/Fragile Resin.png"));
|
||||
const TemporaryRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/5.png"));
|
||||
CondensedRo.threshold = 0.70;
|
||||
CondensedRo.Use3Channels = true;
|
||||
FragileRo.threshold = 0.70;
|
||||
FragileRo.Use3Channels = true;
|
||||
|
||||
this.recognitionResin =
|
||||
async function() {
|
||||
let totalRunNum = 0;
|
||||
await genshin.returnMainUi();
|
||||
await sleep(2000);
|
||||
keyPress("m");
|
||||
await sleep(2000);
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let resList = captureRegion.findMulti(RecognitionObject.ocr(1043, 5, 300, 100));
|
||||
captureRegion.dispose();
|
||||
let IsOver = false
|
||||
|
||||
for (let i = 0; i < resList.count; i++) {
|
||||
let resStamina = resList[i];
|
||||
log.info(`第 ${i + 1} 个结果: ${resStamina.text}`);
|
||||
await sleep(2000);
|
||||
|
||||
// 提取/前面的数字
|
||||
const rawText = resStamina.text;
|
||||
const splitResult = rawText.split('/'); // 用/分割字符串
|
||||
|
||||
// 确保分割后得到两部分且第一部分是有效数字
|
||||
if (splitResult.length >= 1) {
|
||||
const staminaValue = parseInt(splitResult[0]); // 只取第一部分
|
||||
|
||||
if (!isNaN(staminaValue)) {
|
||||
log.info(`提取的体力值: ${staminaValue}`);
|
||||
|
||||
if (staminaValue >= 40) {
|
||||
IsOver = true;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
log.warn("无效的数字格式");
|
||||
}
|
||||
} else {
|
||||
log.warn("未找到/分隔符");
|
||||
}
|
||||
|
||||
await sleep(2000)
|
||||
await genshin.returnMainUi();
|
||||
keyPress("b");
|
||||
await sleep(2000);
|
||||
click(1245, 50);
|
||||
await sleep(2000);
|
||||
|
||||
// 浓缩树脂识别
|
||||
let Condensed = captureGameRegion().find(CondensedRo);
|
||||
Condensed.dispose();
|
||||
let Isfive = false;
|
||||
if (Condensed.isExist()) {
|
||||
log.info("识别到浓缩树脂");
|
||||
let CondensedX = Math.round(Condensed.x + Condensed.width / 2 - 20)
|
||||
let Condensedy = Math.round(Condensed.y + Condensed.height / 2 + 60)
|
||||
log.info(`点击坐标: (${CondensedX}, ${Condensedy})`);
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let Condensedres = captureRegion.findMulti(RecognitionObject.ocr(CondensedX, Condensedy, 50, 50));
|
||||
captureRegion.dispose();
|
||||
for (let i = 0; i < Condensedres.count; i++) {
|
||||
let resCondensed = Condensedres[i];
|
||||
log.info(`浓缩树脂: ${resCondensed.text}`);
|
||||
await sleep(2000);
|
||||
if (resCondensed.text == 5) {
|
||||
Isfive = true;
|
||||
log.info("浓缩树脂已满")
|
||||
await sleep(2000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// 脆弱树脂识别
|
||||
let FragileCapture = captureGameRegion();
|
||||
let Fragile = FragileCapture.find(FragileRo);
|
||||
FragileCapture.dispose();
|
||||
if (Fragile.isExist()) {
|
||||
log.info("识别到脆弱树脂");
|
||||
|
||||
let FragileX = Math.round(Fragile.x + Fragile.width / 2 - 20)
|
||||
let Fragiley = Math.round(Fragile.y + Fragile.height / 2 + 60)
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let Fragileres = captureRegion.findMulti(RecognitionObject.ocr(FragileX, Fragiley, 50, 50));
|
||||
captureRegion.dispose();
|
||||
|
||||
if (Fragileres.count === 0) {
|
||||
log.error("OCR识别失败:未能识别到脆弱树脂数量");
|
||||
} else {
|
||||
for (let i = 0; i < Fragileres.count; i++) {
|
||||
let resFragile = Fragileres[i];
|
||||
if (resFragile.text && resFragile.text.trim() !== "") {
|
||||
log.info("脆弱树脂数量: " + resFragile.text);
|
||||
} else {
|
||||
log.warn("OCR识别结果为空或无效");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("未识别到脆弱树脂");
|
||||
await sleep(2000);
|
||||
}
|
||||
// 须臾树脂识别
|
||||
let TemporaryCapture = captureGameRegion();
|
||||
let Temporary = TemporaryCapture.find(TemporaryRo);
|
||||
TemporaryCapture.dispose();
|
||||
let Temporaryres = null;
|
||||
if (Temporary.isExist()) {
|
||||
log.info("识别到须臾树脂");
|
||||
|
||||
let TemporaryX = Math.round(Temporary.x + Temporary.width / 2 - 20)
|
||||
let Temporaryy = Math.round(Temporary.y + Temporary.height / 2 + 40)
|
||||
log.info(`点击坐标: (${TemporaryX}, ${Temporaryy})`);
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
Temporaryres = captureRegion.findMulti(RecognitionObject.ocr(TemporaryX, Temporaryy, 50, 50));
|
||||
captureRegion.dispose();
|
||||
} else {
|
||||
log.info("未识别到须臾树脂");
|
||||
}
|
||||
|
||||
if (Temporaryres && Temporaryres.count === 0) {
|
||||
log.error("OCR识别失败:未能识别到须臾树脂数量");
|
||||
} else {
|
||||
for (let i = 0; i < Temporaryres.count; i++) {
|
||||
let resTemporary = Temporaryres[i];
|
||||
if (resTemporary.text && resTemporary.text.trim() !== "") {
|
||||
log.info("须臾树脂数量: " + resTemporary.text);
|
||||
} else {
|
||||
log.warn("OCR识别结果为空或无效");
|
||||
}
|
||||
await sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 尝试调用任务
|
||||
|
||||
|
||||
if (IsOver && Isfive == true) {
|
||||
log.info("需要前往合成台"); // 输出 true
|
||||
} else {
|
||||
log.info("不需要前往合成台");
|
||||
}
|
||||
}
|
||||
/*
|
||||
代码迁移中,还未完成适配
|
||||
*/
|
||||
|
||||
|
||||
const CondensedRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/Condensed Resin.png"));
|
||||
const FragileRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/Fragile Resin.png"));
|
||||
const TemporaryRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("RecognitionObject/5.png"));
|
||||
CondensedRo.threshold = 0.70;
|
||||
CondensedRo.Use3Channels = true;
|
||||
FragileRo.threshold = 0.70;
|
||||
FragileRo.Use3Channels = true;
|
||||
|
||||
this.recognitionResin =
|
||||
async function() {
|
||||
let totalRunNum = 0;
|
||||
await genshin.returnMainUi();
|
||||
await sleep(2000);
|
||||
keyPress("m");
|
||||
await sleep(2000);
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let resList = captureRegion.findMulti(RecognitionObject.ocr(1043, 5, 300, 100));
|
||||
captureRegion.dispose();
|
||||
let IsOver = false
|
||||
|
||||
for (let i = 0; i < resList.count; i++) {
|
||||
let resStamina = resList[i];
|
||||
log.info(`第 ${i + 1} 个结果: ${resStamina.text}`);
|
||||
await sleep(2000);
|
||||
|
||||
// 提取/前面的数字
|
||||
const rawText = resStamina.text;
|
||||
const splitResult = rawText.split('/'); // 用/分割字符串
|
||||
|
||||
// 确保分割后得到两部分且第一部分是有效数字
|
||||
if (splitResult.length >= 1) {
|
||||
const staminaValue = parseInt(splitResult[0]); // 只取第一部分
|
||||
|
||||
if (!isNaN(staminaValue)) {
|
||||
log.info(`提取的体力值: ${staminaValue}`);
|
||||
|
||||
if (staminaValue >= 40) {
|
||||
IsOver = true;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
log.warn("无效的数字格式");
|
||||
}
|
||||
} else {
|
||||
log.warn("未找到/分隔符");
|
||||
}
|
||||
|
||||
await sleep(2000)
|
||||
await genshin.returnMainUi();
|
||||
keyPress("b");
|
||||
await sleep(2000);
|
||||
click(1245, 50);
|
||||
await sleep(2000);
|
||||
|
||||
// 浓缩树脂识别
|
||||
let Condensed = captureGameRegion().find(CondensedRo);
|
||||
Condensed.dispose();
|
||||
let Isfive = false;
|
||||
if (Condensed.isExist()) {
|
||||
log.info("识别到浓缩树脂");
|
||||
let CondensedX = Math.round(Condensed.x + Condensed.width / 2 - 20)
|
||||
let Condensedy = Math.round(Condensed.y + Condensed.height / 2 + 60)
|
||||
log.info(`点击坐标: (${CondensedX}, ${Condensedy})`);
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let Condensedres = captureRegion.findMulti(RecognitionObject.ocr(CondensedX, Condensedy, 50, 50));
|
||||
captureRegion.dispose();
|
||||
for (let i = 0; i < Condensedres.count; i++) {
|
||||
let resCondensed = Condensedres[i];
|
||||
log.info(`浓缩树脂: ${resCondensed.text}`);
|
||||
await sleep(2000);
|
||||
if (resCondensed.text == 5) {
|
||||
Isfive = true;
|
||||
log.info("浓缩树脂已满")
|
||||
await sleep(2000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// 脆弱树脂识别
|
||||
let FragileCapture = captureGameRegion();
|
||||
let Fragile = FragileCapture.find(FragileRo);
|
||||
FragileCapture.dispose();
|
||||
if (Fragile.isExist()) {
|
||||
log.info("识别到脆弱树脂");
|
||||
|
||||
let FragileX = Math.round(Fragile.x + Fragile.width / 2 - 20)
|
||||
let Fragiley = Math.round(Fragile.y + Fragile.height / 2 + 60)
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
let Fragileres = captureRegion.findMulti(RecognitionObject.ocr(FragileX, Fragiley, 50, 50));
|
||||
captureRegion.dispose();
|
||||
|
||||
if (Fragileres.count === 0) {
|
||||
log.error("OCR识别失败:未能识别到脆弱树脂数量");
|
||||
} else {
|
||||
for (let i = 0; i < Fragileres.count; i++) {
|
||||
let resFragile = Fragileres[i];
|
||||
if (resFragile.text && resFragile.text.trim() !== "") {
|
||||
log.info("脆弱树脂数量: " + resFragile.text);
|
||||
} else {
|
||||
log.warn("OCR识别结果为空或无效");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("未识别到脆弱树脂");
|
||||
await sleep(2000);
|
||||
}
|
||||
// 须臾树脂识别
|
||||
let TemporaryCapture = captureGameRegion();
|
||||
let Temporary = TemporaryCapture.find(TemporaryRo);
|
||||
TemporaryCapture.dispose();
|
||||
let Temporaryres = null;
|
||||
if (Temporary.isExist()) {
|
||||
log.info("识别到须臾树脂");
|
||||
|
||||
let TemporaryX = Math.round(Temporary.x + Temporary.width / 2 - 20)
|
||||
let Temporaryy = Math.round(Temporary.y + Temporary.height / 2 + 40)
|
||||
log.info(`点击坐标: (${TemporaryX}, ${Temporaryy})`);
|
||||
|
||||
let captureRegion = captureGameRegion();
|
||||
Temporaryres = captureRegion.findMulti(RecognitionObject.ocr(TemporaryX, Temporaryy, 50, 50));
|
||||
captureRegion.dispose();
|
||||
} else {
|
||||
log.info("未识别到须臾树脂");
|
||||
}
|
||||
|
||||
if (Temporaryres && Temporaryres.count === 0) {
|
||||
log.error("OCR识别失败:未能识别到须臾树脂数量");
|
||||
} else {
|
||||
for (let i = 0; i < Temporaryres.count; i++) {
|
||||
let resTemporary = Temporaryres[i];
|
||||
if (resTemporary.text && resTemporary.text.trim() !== "") {
|
||||
log.info("须臾树脂数量: " + resTemporary.text);
|
||||
} else {
|
||||
log.warn("OCR识别结果为空或无效");
|
||||
}
|
||||
await sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 尝试调用任务
|
||||
|
||||
|
||||
if (IsOver && Isfive == true) {
|
||||
log.info("需要前往合成台"); // 输出 true
|
||||
} else {
|
||||
log.info("不需要前往合成台");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,75 @@
|
||||
/**
|
||||
* 识别战斗结果
|
||||
* @param {number} timeout - 超时时间
|
||||
* @returns {Promise<boolean>} 战斗是否成功
|
||||
*/
|
||||
this.recognizeTextInRegion =
|
||||
async function (timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
(async () => {
|
||||
try {
|
||||
let startTime = Date.now();
|
||||
let noTextCount = 0;
|
||||
const successKeywords = ["挑战达成", "战斗胜利", "挑战成功"];
|
||||
const failureKeywords = ["挑战失败"];
|
||||
|
||||
// 循环检测直到超时
|
||||
while (Date.now() - startTime < timeout) {
|
||||
let captureRegion = null;
|
||||
try {
|
||||
captureRegion = captureGameRegion();
|
||||
let result = captureRegion.find(ocrRo1);
|
||||
let text = result.text;
|
||||
|
||||
// 检查成功关键词
|
||||
for (let keyword of successKeywords) {
|
||||
if (text.includes(keyword)) {
|
||||
log.debug("检测到战斗成功关键词: {0}", keyword);
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查失败关键词
|
||||
for (let keyword of failureKeywords) {
|
||||
if (text.includes(keyword)) {
|
||||
log.debug("检测到战斗失败关键词: {0}", keyword);
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let foundText = recognizeFightText(captureRegion);
|
||||
if (!foundText) {
|
||||
noTextCount++;
|
||||
log.info(`检测到可能离开战斗区域,当前计数: ${noTextCount}`);
|
||||
|
||||
if (noTextCount >= 10) {
|
||||
log.warn("已离开战斗区域");
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
noTextCount = 0; // 重置计数
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
log.error("OCR过程中出错: {0}", error);
|
||||
}
|
||||
finally {
|
||||
if (captureRegion) {
|
||||
captureRegion.dispose();
|
||||
}
|
||||
}
|
||||
await sleep(1000); // 检查间隔
|
||||
}
|
||||
|
||||
log.warn("在超时时间内未检测到战斗结果");
|
||||
resolve(false);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
})();
|
||||
});
|
||||
/**
|
||||
* 识别战斗结果
|
||||
* @param {number} timeout - 超时时间
|
||||
* @returns {Promise<boolean>} 战斗是否成功
|
||||
*/
|
||||
this.recognizeTextInRegion =
|
||||
async function (timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
(async () => {
|
||||
try {
|
||||
let startTime = Date.now();
|
||||
let noTextCount = 0;
|
||||
const successKeywords = ["挑战达成", "战斗胜利", "挑战成功"];
|
||||
const failureKeywords = ["挑战失败"];
|
||||
|
||||
// 循环检测直到超时
|
||||
while (Date.now() - startTime < timeout) {
|
||||
let captureRegion = null;
|
||||
try {
|
||||
captureRegion = captureGameRegion();
|
||||
let result = captureRegion.find(ocrRo1);
|
||||
let text = result.text;
|
||||
|
||||
// 检查成功关键词
|
||||
for (let keyword of successKeywords) {
|
||||
if (text.includes(keyword)) {
|
||||
log.debug("检测到战斗成功关键词: {0}", keyword);
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查失败关键词
|
||||
for (let keyword of failureKeywords) {
|
||||
if (text.includes(keyword)) {
|
||||
log.debug("检测到战斗失败关键词: {0}", keyword);
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let foundText = recognizeFightText(captureRegion);
|
||||
if (!foundText) {
|
||||
noTextCount++;
|
||||
log.info(`检测到可能离开战斗区域,当前计数: ${noTextCount}`);
|
||||
|
||||
if (noTextCount >= 10) {
|
||||
log.warn("已离开战斗区域");
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
noTextCount = 0; // 重置计数
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
log.error("OCR过程中出错: {0}", error);
|
||||
}
|
||||
finally {
|
||||
if (captureRegion) {
|
||||
captureRegion.dispose();
|
||||
}
|
||||
}
|
||||
await sleep(1000); // 检查间隔
|
||||
}
|
||||
|
||||
log.warn("在超时时间内未检测到战斗结果");
|
||||
resolve(false);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user