js:锄地一条龙1.4.0 (#1568)
* js:锄地一条龙1.4.0 ### 1.4.0(2025.08.12) 1.增加拾取模式,模板匹配拾取并设为默认项,之前的拾取模式改名为ocr拾取 * js:性能测试 增加自定义配置选择测试项目和识图区域大小 * js:锄地一条龙 适当增加拾取后延时
This commit is contained in:
@@ -35,9 +35,13 @@
|
||||
- - 默认选择 **运行锄地路线** ,选择该模式会按照后续设置选择并运行相应路线
|
||||
- - 选项 **输出地图追踪文件** ,会将选择的路线读取并分组输出到js文件夹下pathingOut文件夹
|
||||
- - 选项 **强制刷新所有运行记录** ,用于清除js记录的运行历史
|
||||
- **选择执行第几个路径组:** 本js会分组运行地图追踪,分组方式详见后续选项,需要分组运行时请确保精英目标数量,小怪目标数量,各个路径组的标签等信息【完全相同】,复制配置组时未知原因无法正确复制配置,请不要使用
|
||||
- **选择执行第几个路径组:** 本js支持分组运行地图追踪,分组方式详见后续选项,需要分组运行时请确保精英目标数量,小怪目标数量,各个路径组的标签等信息【完全相同】,复制配置组时未知原因无法正确复制配置,请不要使用
|
||||
- **本路径组使用配队名称:** 填写该路径组使用的配队名称,js会自动切换
|
||||
- **拾取模式:** 本js采用黑白名单结合的方式实现仅拾取部分物品(默认只拾取狗粮和晶蝶),如果你想要使用bgi默认的拾取以拾取绝大部分物品,请选择bgi拾取,如果不想拾取任何物品,请选择不拾取任何物品
|
||||
- **拾取模式:**
|
||||
- - ocr拾取:使用ocr识别掉落物进行拾取,自定义拾取名单【仅在此模式下生效】
|
||||
- - 模板匹配拾取:测试中,速度最快,性能消耗最低,只拾取四种锄地会掉落的狗粮
|
||||
- - bgi原版拾取
|
||||
- - 不拾取
|
||||
- **效率降序运行:**当你时间不足以刷完所有怪物且不确定时,建议通过开启该项和配置下一项来实现在指定时间前尽可能多刷效率高的路线并按时终止
|
||||
- **输入不运行的时间或时间段的小时数** 当你需要让js在特定的时间终止运行时,按描述填写,js会在距离目标时间小于五分钟时终止运行并等待到目标时间
|
||||
- **泥头车模式(实验性功能):** 接近战斗地点(距离5-30)时,提前让指定序号的角色开e,建议以下角色开启:芙宁娜,爱可菲,雷电将军。警告,可能会增加性能开销和降低稳定性。
|
||||
@@ -50,7 +54,7 @@
|
||||
- - 蕈兽 :表明路线含有蕈兽,蕈兽遇到雷火元素时会发生转化,转化后占据精英怪物的名额却只掉落少量摩拉,通常建议禁用
|
||||
- - 小怪 :表明路线只含小怪,战斗强度低,且无需携带万叶来拾取可能掉落的狗粮,可以适当携带等级较低或不上场的角色来获取经验收益
|
||||
- - 分组逻辑:不含路径组1排除标签和任何其他组标签的路径会进入路径组1,剩余路径若含有路径组x的标签之一,则会进入路径组x
|
||||
- - 使用示例:路径组一填写蕈兽,禁用蕈兽路线,路径组二填写次数盾,水免,处理路径组一的配队难以处理的次数盾和水免怪物,路径组三填写小怪,队伍中放升级中角色获取经验
|
||||
- - 使用示例:路径组一填写蕈兽,禁用蕈兽路线,路径组二填写次数盾,水免,处理路径组一的配队难以处理的次数盾和水免怪物,路径组三填写小怪,队伍中放升级中角色获取经验,将本js添加到【多个配置组】中,根据路径组的具体情况配置每个配置组的设置
|
||||
- **路线效率计算权重:** 影响js评估路线价值,计算公式如下,权重越大越看重总收益
|
||||
- $$ 怪均^k \times 秒均 $$
|
||||
- **自动优化:** js将根据运行记录调整每条路线的预期运行时间,具体逻辑为,至多6条记录,去除一个最大值、一个最小值后,每条记录占据20%的权重,剩余权重由默认数据填充。如果你不想要这个功能,请禁用。
|
||||
@@ -74,6 +78,8 @@
|
||||
|
||||
---
|
||||
### 更新日志
|
||||
### 1.4.0(2025.08.12)
|
||||
1.增加拾取模式,模板匹配拾取并设为默认项,之前的拾取模式改名为ocr拾取
|
||||
### 1.3.8(2025.08.11)
|
||||
1.优化精英部分点位
|
||||
### 1.3.7(2025.08.10)
|
||||
|
||||
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/战狂.png
Normal file
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/战狂.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/教官.png
Normal file
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/教官.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/流放.png
Normal file
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/流放.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/游医.png
Normal file
BIN
repo/js/AutoHoeingOneDragon/assets/targetItems/游医.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -10,7 +10,7 @@
|
||||
"type": 6,
|
||||
"mouseX": 0,
|
||||
"mouseY": 0,
|
||||
"time": 49
|
||||
"time": 5
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"type": 6,
|
||||
"mouseX": 0,
|
||||
"mouseY": 0,
|
||||
"time": 49
|
||||
"time": 5
|
||||
}
|
||||
],
|
||||
"info": {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//当前js版本 1.3.8
|
||||
//当前js版本 1.4.0
|
||||
|
||||
//拾取时上下滑动的时间
|
||||
const timeMoveUp = 500;
|
||||
const timeMoveDown = 1000;
|
||||
const pickupMode = settings.pickupMode || "js拾取,默认只拾取狗粮和晶蝶";
|
||||
let timeMoveUp = 500;
|
||||
let timeMoveDown = 1000;
|
||||
let pickupMode = settings.pickupMode || "模板匹配拾取,默认只拾取狗粮";
|
||||
if (settings.activeDumperMode) { //处理泥头车信息
|
||||
dumpers = settings.activeDumperMode.split(',').map(Number).filter(num => num === 1 || num === 2 || num === 3 || num === 4);
|
||||
} else {
|
||||
@@ -11,10 +11,13 @@ if (settings.activeDumperMode) { //处理泥头车信息
|
||||
}
|
||||
trigger = (+settings.trigger || 50);
|
||||
let gameRegion;
|
||||
let targetItemPath = "assets/targetItems";
|
||||
let targetItems;
|
||||
|
||||
(async function () {
|
||||
//自定义配置处理
|
||||
const operationMode = settings.operationMode || "运行锄地路线";
|
||||
if (pickupMode === "js拾取,默认只拾取狗粮和晶蝶") pickupMode = "模板匹配拾取,默认只拾取狗粮";
|
||||
|
||||
let k = settings.efficiencyIndex;
|
||||
// 空字符串、null、undefined 或非数字 → 0.5
|
||||
@@ -53,6 +56,16 @@ let gameRegion;
|
||||
const whitelistKeywords = ocrPickupJson["白名单"];
|
||||
const blacklistKeywords = ocrPickupJson["黑名单"];
|
||||
|
||||
targetItems = await readFolder(targetItemPath, false);
|
||||
//模板匹配对象处理
|
||||
if (settings.pickupMode === "模板匹配拾取,默认只拾取狗粮") {
|
||||
for (const targetItem of targetItems) {
|
||||
targetItem.template = file.ReadImageMatSync(targetItem.fullPath);
|
||||
targetItem.itemName = targetItem.fileName.replace(/\.png$/, '');
|
||||
}
|
||||
timeMoveUp = trigger * 8;
|
||||
timeMoveDown = trigger * 8;
|
||||
}
|
||||
if (!settings.accountName) {
|
||||
for (let i = 0; i < 120; i++) {
|
||||
// 原始文本
|
||||
@@ -487,12 +500,13 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
async function isMainUI() {
|
||||
// 修改后的图像路径
|
||||
const imagePath = "assets/MainUI.png";
|
||||
|
||||
// 修改后的识别区域(左上角区域)
|
||||
const xMin = 0;
|
||||
const yMin = 0;
|
||||
const width = 150; // 识别区域宽度
|
||||
const height = 150; // 识别区域高度
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height);
|
||||
|
||||
// 尝试次数设置为 3 次
|
||||
const maxAttempts = 3;
|
||||
@@ -500,8 +514,7 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
let attempts = 0;
|
||||
while (attempts < maxAttempts && !state.cancelRequested) {
|
||||
try {
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height);
|
||||
|
||||
gameRegion = captureGameRegion();
|
||||
let result = gameRegion.find(recognitionObject);
|
||||
gameRegion.dispose();
|
||||
@@ -534,15 +547,14 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
const yMin = 200;
|
||||
const width = 1000; // 识别区域宽度
|
||||
const height = 250; // 识别区域高度
|
||||
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height);
|
||||
// 尝试次数设置为 10 次
|
||||
const maxAttempts = 10;
|
||||
|
||||
let attempts = 0;
|
||||
while (attempts < maxAttempts && !state.cancelRequested) {
|
||||
try {
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height);
|
||||
gameRegion = captureGameRegion();
|
||||
let result = gameRegion.find(recognitionObject);
|
||||
gameRegion.dispose();
|
||||
@@ -578,11 +590,10 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
}
|
||||
|
||||
// 定义一个函数用于执行OCR识别和交互
|
||||
async function performOcrAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance) {
|
||||
async function recoginzeAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance) {
|
||||
async function performOcr(whitelistKeywords, xRange, yRange) {
|
||||
try {
|
||||
// 在捕获的区域内进行OCR识别
|
||||
gameRegion = captureGameRegion();
|
||||
let resList = gameRegion.findMulti(RecognitionObject.ocr(
|
||||
xRange.min, yRange.min,
|
||||
xRange.max - xRange.min, yRange.max - yRange.min
|
||||
@@ -614,14 +625,36 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
}
|
||||
}
|
||||
|
||||
async function performTemplateMatch(centerYF) {
|
||||
try {
|
||||
let result;
|
||||
let itemName = null;
|
||||
// 在捕获的区域内进行模板匹配识别
|
||||
for (const targetItem of targetItems) {
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(targetItem.template, 1220, centerYF - 35, 70, 70);
|
||||
result = gameRegion.find(recognitionObject);
|
||||
if (result.isExist()) {
|
||||
itemName = targetItem.itemName;
|
||||
//log.info(`调试-距离为${result.y + result.height / 2 - centerYF}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gameRegion.dispose();
|
||||
return itemName;
|
||||
} catch (error) {
|
||||
log.error(`模板匹配时发生异常: ${error.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
while (!state.completed && !state.cancelRequested) {
|
||||
// 尝试找到 F 图标并返回其坐标
|
||||
async function findFIcon(imagePath, xMin, yMin, width, height, timeout = 500) {
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height);
|
||||
let startTime = Date.now();
|
||||
while (Date.now() - startTime < timeout && !state.cancelRequested) {
|
||||
try {
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, xMin, yMin, width, height);
|
||||
gameRegion = captureGameRegion();
|
||||
let result = gameRegion.find(recognitionObject);
|
||||
if (result.isExist()) {
|
||||
@@ -655,39 +688,47 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let foundTarget = false;
|
||||
// 获取 F 图标的中心点 Y 坐标
|
||||
let centerYF = fRes.y + fRes.height / 2;
|
||||
|
||||
let centerYF = Math.round(fRes.y + fRes.height / 2);
|
||||
if (settings.pickupMode === "ocr拾取,默认只拾取狗粮和晶蝶") {
|
||||
// 在当前屏幕范围内进行 OCR 识别
|
||||
let ocrResults = await performOcr(whitelistKeywords, textxRange, { min: fRes.y - texttolerance, max: fRes.y + fRes.height + texttolerance * 2 });
|
||||
|
||||
// 检查所有目标文本是否在当前页面中
|
||||
let foundTarget = false;
|
||||
for (let ocrResult of ocrResults) {
|
||||
// 检查是否包含黑名单关键词
|
||||
let containsBlacklistKeyword = blacklistKeywords.some(blacklistKeyword => ocrResult.text.includes(blacklistKeyword));
|
||||
if (containsBlacklistKeyword) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算目标文本的中心Y坐标
|
||||
let centerYTargetText = ocrResult.y + ocrResult.height / 2;
|
||||
if (Math.abs(centerYTargetText - centerYF) <= texttolerance) {
|
||||
keyPress("F"); // 执行交互操作
|
||||
await sleep(trigger); // 操作后暂停 50 毫秒
|
||||
await sleep(2 * trigger); // 操作后暂停 2*trigger 毫秒
|
||||
foundTarget = true;
|
||||
|
||||
if ((new Date() - lastPickupTime) > 1000 || ocrResult.text != lastPickupItem) {
|
||||
log.info(`交互或拾取:"${ocrResult.text}"`);
|
||||
lastPickupTime = new Date();
|
||||
lastPickupItem = ocrResult.text;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (settings.pickupMode === "模板匹配拾取,默认只拾取狗粮") {
|
||||
let start = new Date();
|
||||
let itemName = await performTemplateMatch(centerYF);
|
||||
let end = new Date();
|
||||
//log.info(`调试-匹配用时${end - start}毫秒`)
|
||||
if (itemName) {
|
||||
keyPress("F"); // 执行交互操作
|
||||
log.info(`交互或拾取:"${itemName}"`);
|
||||
await sleep(2 * trigger); // 操作后暂停 2*trigger 毫秒
|
||||
foundTarget = true;
|
||||
}
|
||||
|
||||
}
|
||||
// 如果在当前页面中没有找到任何目标文本,则根据时间决定滚动方向
|
||||
if (!foundTarget) {
|
||||
const currentTime = new Date().getTime(); // 获取当前时间(毫秒)
|
||||
@@ -710,6 +751,7 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
// 否则执行下翻
|
||||
await keyMouseScript.runFile(`assets/滚轮上翻.json`);
|
||||
}
|
||||
await sleep(Math.round(trigger / 5));
|
||||
}
|
||||
|
||||
if (state.cancelRequested) {
|
||||
@@ -832,8 +874,8 @@ async function runPath(pathFilePath, map_name, whitelistKeywords, blacklistKeywo
|
||||
|
||||
// 根据条件决定是否启动 OCR 检测和交互任务
|
||||
let ocrTask = null;
|
||||
if (pickupMode === "js拾取,默认只拾取狗粮和晶蝶") {
|
||||
ocrTask = performOcrAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance);
|
||||
if (pickupMode === "ocr拾取,默认只拾取狗粮和晶蝶" || pickupMode === "模板匹配拾取,默认只拾取狗粮") {
|
||||
ocrTask = recoginzeAndInteract(imagePath, whitelistKeywords, textxRange, texttolerance);
|
||||
}
|
||||
|
||||
// 启动泥头车
|
||||
|
||||
@@ -32,11 +32,12 @@
|
||||
"type": "select",
|
||||
"label": "拾取模式",
|
||||
"options": [
|
||||
"js拾取,默认只拾取狗粮和晶蝶",
|
||||
"模板匹配拾取,默认只拾取狗粮",
|
||||
"ocr拾取,默认只拾取狗粮和晶蝶",
|
||||
"bgi原版拾取",
|
||||
"不拾取任何物品"
|
||||
],
|
||||
"default": "js拾取,默认只拾取狗粮和晶蝶"
|
||||
"default": "模板匹配拾取,默认只拾取狗粮"
|
||||
},
|
||||
{
|
||||
"name": "trigger",
|
||||
|
||||
BIN
repo/js/ComputerBlower/assets/流放.png
Normal file
BIN
repo/js/ComputerBlower/assets/流放.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -1,29 +1,79 @@
|
||||
// 主函数
|
||||
(async function () {
|
||||
operationMode = settings.operationMode || "截图";
|
||||
const xRange = parseInt(+settings.xRange || 1920, 10);
|
||||
const yRange = parseInt(+settings.yRange || 1920, 10);
|
||||
let startTime = Date.now();
|
||||
const interval = +settings.interval || 1000;
|
||||
const timeout = +settings.timeout || 60;
|
||||
let lastCheck = startTime;
|
||||
let ocrcount = 0;
|
||||
let loopCount = 0;
|
||||
let logCount = 0;
|
||||
//let store = [];
|
||||
const imagePath = "assets/流放.png";
|
||||
let template = file.ReadImageMatSync(imagePath);
|
||||
if (operationMode === "截图") {
|
||||
while (Date.now() - startTime < timeout * 1000) {
|
||||
loopCount++;
|
||||
try {
|
||||
let GameRegion = captureGameRegion();
|
||||
// store[loopCount] = GameRegion;
|
||||
if (settings.dispose) GameRegion.dispose();
|
||||
ocrcount++;
|
||||
if (Date.now() - lastCheck >= interval) {
|
||||
loopCount++;
|
||||
await sleep(1);
|
||||
lastCheck = Date.now();
|
||||
log.info(`在第${loopCount}个${interval}毫秒内执行了${ocrcount}次截图`);
|
||||
ocrcount = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`运行时发生异常: ${error.message}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (operationMode === "模板匹配") {
|
||||
let GameRegion = captureGameRegion();
|
||||
while (Date.now() - startTime < timeout * 1000) {
|
||||
try {
|
||||
|
||||
let recognitionObject = RecognitionObject.TemplateMatch(template, 0, 0, xRange, yRange);
|
||||
let result = GameRegion.find(recognitionObject);
|
||||
ocrcount++;
|
||||
if (Date.now() - lastCheck >= interval) {
|
||||
loopCount++;
|
||||
await sleep(1);
|
||||
lastCheck = Date.now();
|
||||
log.info(`在第${loopCount}个${interval}毫秒内执行了${ocrcount}次模板匹配`);
|
||||
ocrcount = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`运行时发生异常: ${error.message}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (settings.dispose) GameRegion.dispose();
|
||||
}
|
||||
if (operationMode === "ocr") {
|
||||
let GameRegion = captureGameRegion();
|
||||
while (Date.now() - startTime < timeout * 1000) {
|
||||
try {
|
||||
let result = GameRegion.findMulti(RecognitionObject.ocr(
|
||||
0, 0,
|
||||
xRange, yRange
|
||||
));
|
||||
ocrcount++;
|
||||
} catch (error) {
|
||||
log.error(`运行时发生异常: ${error.message}`);
|
||||
break;
|
||||
}
|
||||
if (Date.now() - lastCheck >= interval) {
|
||||
logCount++;
|
||||
loopCount++;
|
||||
lastCheck = Date.now();
|
||||
log.info(`在第${logCount}个${interval}毫秒内执行了${ocrcount}次截图`);
|
||||
await sleep(1);
|
||||
log.info(`在第${loopCount}个${interval}毫秒内执行了${ocrcount}次OCR`);
|
||||
ocrcount = 0;
|
||||
}
|
||||
}
|
||||
if (settings.dispose) GameRegion.dispose();
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "截图性能测试",
|
||||
"version": "0.1",
|
||||
"name": "性能测试",
|
||||
"version": "1.0",
|
||||
"tags": [],
|
||||
"bgi_version": "0.46.0",
|
||||
"description": "测测你的",
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
[
|
||||
{
|
||||
"name": "operationMode",
|
||||
"type": "select",
|
||||
"label": "测试项目",
|
||||
"options": [
|
||||
"截图",
|
||||
"模板匹配",
|
||||
"ocr"
|
||||
],
|
||||
"default": "只截图"
|
||||
},
|
||||
{
|
||||
"name": "dispose",
|
||||
"type": "checkbox",
|
||||
@@ -15,5 +26,17 @@
|
||||
"type": "input-text",
|
||||
"label": "间隔多久输出一次(毫秒)",
|
||||
"default": "1000"
|
||||
},
|
||||
{
|
||||
"name": "xRange",
|
||||
"type": "input-text",
|
||||
"label": "区域大小x",
|
||||
"default": "1920"
|
||||
},
|
||||
{
|
||||
"name": "yRange",
|
||||
"type": "input-text",
|
||||
"label": "区域大小y",
|
||||
"default": "1080"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user