Revert "js:锄地一条龙 奇怪普通料理 点击消除新 autoenter 世界权限 (#2901)" (#2910)

This reverts commit d07f8e95b8.
This commit is contained in:
mno
2026-02-22 21:06:54 +08:00
committed by GitHub
parent 5ddbf8ed32
commit f34c749ce0
49 changed files with 456 additions and 789 deletions

View File

@@ -1,2 +1,4 @@
进入特定uid世界或自动批准特定用户进入填写的名字和放在targets文件夹中的截图都会被视为白名单用户放行使用前务必将世界权限设置为确认后加入
自动进入联机状态js测试版本出什么bug都是正常的加qq718135749去超市作者
组队和更多使用说明请加qq群1057307824

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,208 +1,480 @@
//获取自定义配置
const enterMode = settings.enterMode || "进入他人世界";
const enteringUID = settings.enteringUID;
const permissionMode = settings.permissionMode || "无条件通过";
const nameToPermit1 = settings.nameToPermit1;
const nameToPermit2 = settings.nameToPermit2;
const nameToPermit3 = settings.nameToPermit3;
const timeOut = +settings.timeout || 5;
const maxEnterCount = +settings.maxEnterCount || 3;
const enterUIDRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/enterUID.png"));
const searchRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/search.png"));
const requestEnterRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/requestEnter.png"));
const requestEnter2Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/requestEnter.png"), 1480, 300, 280, 600);
const yUIRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/yUI.png"));
const allowEnterRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/allowEnter.png"), 1250, 300, 150, 130);
const targetsPath = "targets";
let enterCount = 0;
let targetsRo;
let checkToEnd = false;
// 先初始化空数组
let targetList = [];
let enteredPlayers = [];
(async function () {
await autoEnter(settings);
}
)();
/**
* 自动联机脚本(整体打包为一个函数)
* @param {Object} autoEnterSettings 配置对象
* enterMode: "进入他人世界" | "等待他人进入"
* enteringUID: string | null
* permissionMode: "无条件通过" | "白名单"
* nameToPermit1/2/3: string | null
* timeout: 分钟
* maxEnterCount: number
*/
async function autoEnter(autoEnterSettings) {
// ===== 配置解析 =====
const enterMode = autoEnterSettings.enterMode || "进入他人世界";
const enteringUID = autoEnterSettings.enteringUID;
const permissionMode = autoEnterSettings.permissionMode || "无条件通过";
const timeout = +autoEnterSettings.timeout || 5;
const maxEnterCount = +autoEnterSettings.maxEnterCount || 3;
// 白名单
const targetList = [];
[autoEnterSettings.nameToPermit1, autoEnterSettings.nameToPermit2, autoEnterSettings.nameToPermit3]
.forEach(v => v && targetList.push(v));
// ===== 模板 / 路径 =====
const enterUIDRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/enterUID.png"));
const searchRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/search.png"));
const requestEnterRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/requestEnter.png"));
const requestEnter2Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/requestEnter.png"), 1480, 300, 280, 600);
const yUIRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/yUI.png"));
const allowEnterRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/allowEnter.png"));
const targetsPath = "targets";
// ===== 状态 =====
let enterCount = 0;
let targetsRo = [];
let checkToEnd = false;
let enteredPlayers = [];
// ===== 初始化 =====
setGameMetrics(1920, 1080, 1);
const start = new Date();
log.info(`当前模式为:${enterMode}`);
// 加载目标 PNG
const targetPngs = await readFolder(targetsPath, ".png");
// 依次判断并加入
if (settings.nameToPermit1) targetList.push(settings.nameToPermit1);
if (settings.nameToPermit2) targetList.push(settings.nameToPermit2);
if (settings.nameToPermit3) targetList.push(settings.nameToPermit3);
// 获取指定文件夹下所有文件
let targetPngs = await readFolder(targetsPath, false);
// 生成 targetsRo使用 for...of
targetsRo = [];
for (const f of targetPngs) {
const mat = file.ReadImageMatSync(f.fullPath);
const ro = RecognitionObject.TemplateMatch(mat, 664, 481, 1355 - 668, 588 - 484);
const baseName = f.fileName.replace(/\.png$/i, '');
targetsRo.push({ ro, baseName });
log.info(`找到文件${f.fullPath}`);
if (f.fullPath.endsWith('.png')) {
const mat = file.ReadImageMatSync(f.fullPath);
const ro = RecognitionObject.TemplateMatch(mat, 650, 320, 350, 60);
const baseName = f.fileName.replace(/\.png$/i, '');
targetsRo.push({ ro, baseName });
}
}
log.info(`加载完成共 ${targetsRo.length} 个目标`);
// ===== 主循环 =====
while (new Date() - start < timeout * 60 * 1000) {
log.info(`加载完成共${targetPngs.length}个目标`);
while (new Date() - start < timeOut * 60 * 1000) {
if (enterMode === "进入他人世界") {
//检验队伍编号
const playerSign = await getPlayerSign();
await sleep(500);
if (playerSign > 1) {
log.info(`加入成功,队伍编号 ${playerSign}`);
if (playerSign != 0) {
log.info(`加入世界成功,队伍中的编号${playerSign}`);
break;
} else if (playerSign === -1) {
log.warn("队伍编号识别异常尝试按0p处理");
} else {
log.error(`不处于多人世界,开始尝试加入`);
await genshin.returnMainUi();
await sleep(500);
}
log.info('不处于多人世界,开始尝试加入');
await genshin.returnMainUi(); await sleep(500);
//反复敲门进入他人世界
//我要cia进来llo
if (enteringUID) {
await keyPress("F2");
//点击输入uid
await sleep(2000);
if (!await findAndClick(enterUIDRo)) {
await genshin.returnMainUi();
continue;
}
await sleep(1000);
inputText(enteringUID);
//点击搜索
await sleep(1000);
if (!await findAndClick(searchRo)) {
await genshin.returnMainUi();
continue;
}
//判断是否成功搜索
if (await confirmSearchResult()) {
await genshin.returnMainUi();
continue;
}
if (!enteringUID) { log.error('未填写有效 UID'); break; }
await keyPress("F2"); await sleep(2000);
if (!await findAndClick(enterUIDRo)) { await genshin.returnMainUi(); continue; }
await sleep(1000); inputText(enteringUID);
await sleep(1000);
if (!await findAndClick(searchRo)) { await genshin.returnMainUi(); continue; }
await sleep(500);
if (!await confirmSearchResult()) { await genshin.returnMainUi(); log.warn("无搜索结果"); continue; }
await sleep(500);
if (!await findAndClick(requestEnterRo)) { await genshin.returnMainUi(); continue; }
await waitForMainUI(true, 20 * 1000);
} else { // 等待他人进入
const playerSign = await getPlayerSign();
if (playerSign > 1) {
log.warn("处于他人世界,先尝试退出");
let leaveAttempts = 0;
while (leaveAttempts < 10) {
if (await getPlayerSign() === 0) {
break;
}
await keyPress("F2");
await sleep(1000);
await findAndClick(leaveTeamRo);
await sleep(1000);
//点击申请加入
await sleep(500);
if (!await findAndClick(requestEnterRo)) {
await genshin.returnMainUi();
continue;
}
//等待加入完成
await waitForMainUI(true, 20 * 1000);
} else {
log.error("未填写有效的uid请检查后重试");
break;
}
} else {
//等待他人进入世界
if (enterCount < maxEnterCount) {
if (await isYUI()) {
keyPress("VK_ESCAPE");
}
await genshin.returnMainUi();
keyPress("Y");
await sleep(250);
if (await isYUI()) {
log.info("处于y界面开始识别");
let attempts = 0;
while (attempts < 5) {
attempts++;
if (permissionMode === "无条件通过") {
//无需筛选,全部通过
if (await findAndClick(allowEnterRo)) {
//等待加入完成
await waitForMainUI(true, 20 * 1000);
enterCount++;
break;
}
} else {
//需要筛选,开始识别第一行申请
const result = await recognizeRequest();
if (result) {
if (await findAndClick(allowEnterRo)) {
//等待加入完成
await waitForMainUI(true, 20 * 1000);
enterCount++;
log.info(`允许${result}加入世界`);
// 把 result 加入 enteredPlayers并立即去重
enteredPlayers = [...new Set([...enteredPlayers, result])];
await sleep(1000);
if (await isYUI()) {
keyPress("VK_ESCAPE");
await genshin.returnMainUi();
}
break;
} else {
if (await isYUI()) {
keyPress("VK_ESCAPE");
await genshin.returnMainUi();
}
}
}
}
await sleep(500);
}
}
if (await isYUI()) {
keyPress("VK_ESCAPE");
await waitForMainUI(true);
await genshin.returnMainUi();
}
}
if (enterCount >= maxEnterCount) break;
if (await isYUI()) keyPress("VK_ESCAPE"); await sleep(500);
await genshin.returnMainUi();
keyPress("Y"); await sleep(250);
if (!await isYUI()) continue;
log.info("处于 Y 界面,开始识别");
let attempts = 0;
while (attempts++ < 5) {
if (permissionMode === "无条件通过") {
if (await findAndClick(allowEnterRo)) {
doRunExtra = true;
await waitForMainUI(true, 20 * 1000);
enterCount++;
break;
}
} else {
const result = await recognizeRequest();
if (result) {
if (await findAndClick(allowEnterRo)) {
await waitForMainUI(true, 20 * 1000);
enterCount++;
enteredPlayers = [...new Set([...enteredPlayers, result])];
log.info(`允许 ${result} 加入`);
notification.send(`允许 ${result} 加入`);
doRunExtra = true;
if (await isYUI()) { keyPress("VK_ESCAPE"); await sleep(500); await genshin.returnMainUi(); }
break;
} else {
if (await isYUI()) { keyPress("VK_ESCAPE"); await sleep(500); await genshin.returnMainUi(); }
}
}
}
await sleep(500);
}
if (await isYUI()) { keyPress("VK_ESCAPE"); await genshin.returnMainUi(); }
if (enterCount >= maxEnterCount || checkToEnd) {
log.info("准备结束js");
checkToEnd = true;
if (await isYUI()) {
keyPress("VK_ESCAPE");
await genshin.returnMainUi();
}
await sleep(20000);
if (await findTotalNumber() === maxEnterCount + 1) {
notification.send(`已达到预定人数:${maxEnterCount + 1}`);
break;
} else {
enterCount--;
}
else enterCount--;
}
}
}
if (new Date() - start >= timeout * 60 * 1000) {
log.warn("超时未达到预定人数");
notification.error(`超时未达到预定人数`);
if (settings.onlyRunPerfectly) {
skipRunning = true;
doRunExtra = false;
}
}
}
)();
async function confirmSearchResult() {
for (let i = 0; i < 4; i++) {
const gameRegion = captureGameRegion();
const res = gameRegion.find(requestEnter2Ro);
//等待主界面状态
async function waitForMainUI(requirement, timeOut = 60 * 1000) {
log.info(`等待至多${timeOut}毫秒`)
const startTime = Date.now();
while (Date.now() - startTime < timeOut) {
const mainUIState = await isMainUI();
if (mainUIState === requirement) return true;
const elapsed = Date.now() - startTime;
const min = Math.floor(elapsed / 60000);
const sec = Math.floor((elapsed % 60000) / 1000);
const ms = elapsed % 1000;
log.info(`已等待 ${min}${sec}${ms}毫秒`);
await sleep(1000);
}
log.error("超时仍未到达指定状态");
return false;
}
//检查是否在主界面
async function isMainUI() {
// 修改后的图像路径
const imagePath = "assets/RecognitionObject/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);
// 尝试次数设置为 5 次
const maxAttempts = 5;
let attempts = 0;
while (attempts < maxAttempts) {
try {
let gameRegion = captureGameRegion();
let result = gameRegion.find(recognitionObject);
gameRegion.dispose();
if (res.isExist()) return false;
if (i < 4) await sleep(250);
}
return true;
}
if (result.isExist()) {
//log.info("处于主界面");
return true; // 如果找到图标,返回 true
}
} catch (error) {
log.error(`识别图像时发生异常: ${error.message}`);
async function isYUI() {
for (let i = 0; i < 5; i++) {
const gameRegion = captureGameRegion();
const res = gameRegion.find(yUIRo);
return false; // 发生异常时返回 false
}
attempts++; // 增加尝试次数
await sleep(50); // 每次检测间隔 50 毫秒
}
return false; // 如果尝试次数达到上限或取消,返回 false
}
//获取联机世界的当前玩家标识
async function getPlayerSign() {
const picDic = {
"1P": "assets/RecognitionObject/1P.png",
"2P": "assets/RecognitionObject/2P.png",
"3P": "assets/RecognitionObject/3P.png",
"4P": "assets/RecognitionObject/4P.png"
}
await genshin.returnMainUi();
await sleep(500);
const p1Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync(picDic["1P"]), 344, 22, 45, 45);
const p2Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync(picDic["2P"]), 344, 22, 45, 45);
const p3Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync(picDic["3P"]), 344, 22, 45, 45);
const p4Ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync(picDic["4P"]), 344, 22, 45, 45);
moveMouseTo(1555, 860); // 移走鼠标,防止干扰识别
const gameRegion = captureGameRegion();
// 当前页面模板匹配
let p1 = gameRegion.Find(p1Ro);
let p2 = gameRegion.Find(p2Ro);
let p3 = gameRegion.Find(p3Ro);
let p4 = gameRegion.Find(p4Ro);
gameRegion.dispose();
if (p1.isExist()) return 1;
if (p2.isExist()) return 2;
if (p3.isExist()) return 3;
if (p4.isExist()) return 4;
return 0;
}
async function confirmSearchResult() {
maxAttempts = 5;
for (let attempts = 0; attempts < maxAttempts; attempts++) {
const gameRegion = captureGameRegion();
try {
const result = gameRegion.find(requestEnter2Ro);
if (result.isExist) {
return false; // 成功立刻返回
}
} catch (err) {
} finally {
gameRegion.dispose();
if (res.isExist()) return true;
}
if (attempts < maxAttempts - 1) { // 最后一次不再 sleep
await sleep(250);
}
return false;
}
return true;
}
async function findAndClick(target, maxAttempts = 20) {
for (let attempts = 0; attempts < maxAttempts; attempts++) {
const gameRegion = captureGameRegion();
try {
const result = gameRegion.find(target);
if (result.isExist) {
await sleep(50);
result.click();
await sleep(50);
return true; // 成功立刻返回
}
log.warn(`识别失败,第 ${attempts + 1} 次重试`);
} catch (err) {
} finally {
gameRegion.dispose();
}
if (attempts < maxAttempts - 1) { // 最后一次不再 sleep
await sleep(250);
}
}
log.error("已达到重试次数上限,仍未找到目标");
return false;
}
//检查是否在主界面
async function isYUI() {
// 尝试次数设置为 5 次
const maxAttempts = 5;
let attempts = 0;
while (attempts < maxAttempts) {
try {
let gameRegion = captureGameRegion();
let result = gameRegion.find(yUIRo);
gameRegion.dispose();
if (result.isExist()) {
//log.info("处于Y界面");
return true; // 如果找到图标,返回 true
}
} catch (error) {
log.error(`识别图像时发生异常: ${error.message}`);
return false; // 发生异常时返回 false
}
attempts++; // 增加尝试次数
await sleep(250); // 每次检测间隔 50 毫秒
}
return false; // 如果尝试次数达到上限或取消,返回 false
}
// 确认当前申请是否为目标
async function recognizeRequest() {
// 1. 模板匹配
try {
const gameRegion = captureGameRegion();
for (const { ro, baseName } of targetsRo) {
if (gameRegion.find(ro).isExist()) {
gameRegion.dispose();
return baseName;
}
}
gameRegion.dispose();
} catch (err) {
log.error(`模板匹配异常: ${err.message}`);
}
async function recognizeRequest() {
try {
const gameRegion = captureGameRegion();
for (const { ro, baseName } of targetsRo) {
if (gameRegion.find(ro).isExist()) { gameRegion.dispose(); return baseName; }
// 2. OCR 仅识别一次,固定区域 650,320,350,60
try {
const gameRegion = captureGameRegion();
const resList = gameRegion.findMulti(
RecognitionObject.ocr(650, 320, 350, 60)
);
gameRegion.dispose();
let hit = null;
for (const res of resList) {
const txt = res.text.trim();
for (const whiteItem of targetList) {
if (txt === whiteItem) {
hit = whiteItem;
break;
}
}
gameRegion.dispose();
} catch { }
try {
const gameRegion = captureGameRegion();
const resList = gameRegion.findMulti(RecognitionObject.ocr(664, 481, 1355 - 668, 588 - 484));
gameRegion.dispose();
let hit = null;
if (hit) break;
}
// 如果未命中,输出所有识别结果
if (!hit) {
for (const res of resList) {
const txt = res.text.trim();
if (targetList.includes(txt)) { hit = txt; break; }
log.warn(`识别到"${res.text.trim()}",不在白名单`);
}
if (!hit) resList.forEach(r => log.warn(`识别到"${r.text.trim()}",不在白名单`));
return hit;
} catch { return null; }
}
return hit; // 命中返回白名单项,未命中返回 null
} catch (err) {
log.error(`OCR 识别异常: ${err.message}`);
}
return null;
}
// 定义 readFolder 函数
async function readFolder(folderPath, onlyJson) {
// 新增一个堆栈,初始时包含 folderPath
const folderStack = [folderPath];
// 新增一个数组,用于存储文件信息对象
const files = [];
// 当堆栈不为空时,继续处理
while (folderStack.length > 0) {
// 从堆栈中弹出一个路径
const currentPath = folderStack.pop();
// 读取当前路径下的所有文件和子文件夹路径
const filesInSubFolder = file.ReadPathSync(currentPath);
// 临时数组,用于存储子文件夹路径
const subFolders = [];
for (const filePath of filesInSubFolder) {
if (file.IsFolder(filePath)) {
// 如果是文件夹,先存储到临时数组中
subFolders.push(filePath);
} else {
// 如果是文件,根据 onlyJson 判断是否存储
if (onlyJson) {
if (filePath.endsWith(".json")) {
const fileName = filePath.split('\\').pop(); // 提取文件名
const folderPathArray = filePath.split('\\').slice(0, -1); // 提取文件夹路径数组
files.push({
fullPath: filePath,
fileName: fileName,
folderPathArray: folderPathArray
});
//log.info(`找到 JSON 文件:${filePath}`);
}
} else {
const fileName = filePath.split('\\').pop(); // 提取文件名
const folderPathArray = filePath.split('\\').slice(0, -1); // 提取文件夹路径数组
files.push({
fullPath: filePath,
fileName: fileName,
folderPathArray: folderPathArray
});
//log.info(`找到文件:${filePath}`);
}
}
}
// 将临时数组中的子文件夹路径按原顺序压入堆栈
folderStack.push(...subFolders.reverse()); // 反转子文件夹路径
}
return files;
}
async function findTotalNumber() {
await genshin.returnMainUi();
await keyPress("F2");
await sleep(2000);
// 定义模板
const kick2pRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/kickButton.png"), 1520, 277, 230, 120);
const kick3pRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/kickButton.png"), 1520, 400, 230, 120);
const kick4pRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/kickButton.png"), 1520, 527, 230, 120);
moveMouseTo(1555, 860); // 防止鼠标干扰
const gameRegion = captureGameRegion();
await sleep(200);
let count = 1; // 先算上自己
// 依次匹配 2P
if (gameRegion.Find(kick2pRo).isExist()) {
log.info("发现 2P");
count++;
}
// 依次匹配 3P
if (gameRegion.Find(kick3pRo).isExist()) {
log.info("发现 3P");
count++;
}
// 依次匹配 4P
if (gameRegion.Find(kick4pRo).isExist()) {
log.info("发现 4P");
count++;
}
gameRegion.dispose();
log.info(`当前联机世界玩家总数(含自己):${count}`);
return count;
}

View File

@@ -1,9 +1,11 @@
{
"manifest_version": 1,
"name": "进入联机状态",
"version": "1.0.0",
"tags": [],
"description": "自动进入指定uid世界或批准别人加入用于进入小号世界采集等",
"version": "0.0.4",
"tags": [
"狗粮"
],
"description": "配合AAA狗粮联机团购使用自动进入别人世界或批准别人加入",
"saved_files": [
"records/*.txt"
],

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -15,11 +15,7 @@
使用即表示您已阅读并同意上述条款。
---
### 琪零、**温馨提示**
- 如果您在包括但不限于频道、群聊等收到包含以下内容的关于使用bgi【锄地】的建议请无视他们给出的建议存在误导不具有参考价值
- 不带芙/不带盾/带双盾/携带并使用大位移角色/打精英不带万叶/400-0 0-2000/带钟离打非传奇/使用世界使用带有q而非keypress(q),keydown(q)的战斗策略的(出现以上任意一条即可说明该账号对于锄地的理解有误区,不具有参考价值)
- 还有写战斗策略如果你连attack()括号里的数字是什么意思、keypress(q)和直接q的区别、配置组设置自动战斗部分的各个配置项的作用都不知道那要么先去看官网文档搞清楚这些东西再写要么别研究了老老实实用万能策略得了点名希诺宁 e,attack(2和希诺宁 e,attack,attack)
如果你觉得你被攻击了,那攻击的就是你,自己瞎打着玩没人管你,别一天天的跑出来误导别人
(简易配置描述部分)
### 一、**快速使用指南 ✅**
@@ -30,7 +26,7 @@
- ⚠️ 关键设置,请务必检查!
- 切换队伍:❌ 关闭(配队请在脚本自定义配置中填写)
- 战斗策略:推荐使用万能策略,不在万能策略中的角色不建议使用
- 扫描掉落物光柱:❌ 强烈建议关闭(易卡死、拖慢速度)
- 自动拾取掉落物:❌ 强烈建议关闭(易卡死、拖慢速度)
- 自动检测战斗结束:✅ 开启,延时设为 0.35-0.5秒默认1.5秒太慢)
- 战斗结束后执行万叶长E✅ 强烈建议开启大幅提升狗粮收益如果你觉得慢你打280精英然后把捡的狗粮摧毁和打400不捡狗粮的收益时一样的
- 战斗超时:小怪路线建议 ≤60秒练度低可适当延长

View File

@@ -70,7 +70,7 @@ let lastEatBuff = 0;
await loadBlacklist(true);
await rotateWarnIfAccountEmpty();
log.info("如果您在包括但不限于频道、群聊等收到包含以下内容的关于使用bgi【锄地】的建议请无视他们给出的建议存在误导不具有参考价值不带芙/不带盾/带双盾/携带并使用大位移角色/打精英不带万叶/400-0 0-2000/带钟离打非传奇/使用世界使用带有q而非keypress(q),keydown(q)的战斗策略的(出现以上任意一条即可说明该账号对于锄地的理解有误区,不具有参考价值)");
if (operationMode === "启用仅指定怪物模式") {
await filterPathingsByTargetMonsters();
await updateRecords(pathings, accountName);

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "锄地一条龙",
"version": "2.3.1",
"version": "2.3.0",
"description": "一站式解决自动化锄地支持只拾取狗粮请仔细阅读README.md后使用",
"authors": [
{

View File

@@ -1,2 +1 @@
适配1080p分辨率其他分辨率不能使用属于正常现象能够使用纯属巧合
1. 适配1080p分辨率其他分辨率不能使用属于正常现象能够使用纯属巧合

View File

@@ -10,7 +10,7 @@ let newCount = 0;
await genshin.returnMainUi();
keyPress("B");
let types = Array.from(settings.executingTypes) || ["全选"];
let types = Array.from(settings.executingTypes);
if (types.includes("全选")) {
types = ["武器",
"圣遗物",
@@ -46,7 +46,7 @@ let newCount = 0;
await sleep(300);
}
let scrolls = 0;
while (scrolls < 145) {
while (scrolls < 200) {
scrolls++
try { await sleep(1) } catch (e) { break; }
while (true) {

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "点击消除新",
"version": "1.1",
"version": "1.0",
"description": "点击消除背包中的新",
"authors": [
{

View File

@@ -4,7 +4,7 @@
"type": "multi-checkbox",
"label": "要执行的物品种类",
"default": [
"全选"
"圣遗物"
],
"options": [
"全选",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -1,41 +0,0 @@
{
"info": {
"authors": [
{
"links": "",
"name": "mno"
}
],
"bgi_version": "0.45.0",
"description": "",
"enable_monster_loot_split": false,
"last_modified_time": 1766237117953,
"map_match_method": "",
"map_name": "Teyvat",
"name": "前往道成林并重新登录",
"tags": [],
"type": "collect",
"version": "1.0"
},
"positions": [
{
"action": "",
"action_params": "",
"id": 1,
"locked": false,
"move_mode": "walk",
"type": "teleport",
"x": 2297.896484375,
"y": -824.2373046875
},
{
"action": "exit_and_relogin",
"action_params": "",
"id": 2,
"move_mode": "walk",
"type": "orientation",
"x": 2297.896484375,
"y": -824.2373046875
}
]
}

View File

@@ -1,99 +0,0 @@
let checkInterval = +settings.checkInterval || 50;
(async function () {
let currentState = "";
let targetState = settings.targetState;
if (!settings.forceCheck) {
log.info(`当前未启用强化确认模式,设置目标为${targetState}`);
while (true) {
await genshin.returnMainUi();
await keyPress("F2");
let attempts = 0;
while (attempts < 20) {
attempts++;
if (await findPNG("确认后可加入", 1)) {
currentState = "确认后可加入";
break;
}
if (await findPNG("直接加入", 1)) {
currentState = "直接加入";
break;
}
if (await findPNG("不允许加入", 1)) {
currentState = "不允许加入";
break;
}
}
if (currentState) {
log.info(`当前世界权限为${currentState}`);
break;
}
}
if (currentState != targetState) {
await clickPNG(currentState);
await clickPNG("设置" + targetState);
}
} else {
log.info(`当前已启用强化确认模式,设置目标为${targetState}`);
let checkCount = 0;
while (checkCount < 2) {
await pathingScript.runFile(`assets/前往道成林并重新登录.json`);
while (true) {
await genshin.returnMainUi();
await keyPress("F2");
let attempts = 0;
while (attempts < 20) {
attempts++;
if (await findPNG("确认后可加入", 1)) {
currentState = "确认后可加入";
break;
}
if (await findPNG("直接加入", 1)) {
currentState = "直接加入";
break;
}
if (await findPNG("不允许加入", 1)) {
currentState = "不允许加入";
break;
}
}
if (currentState) {
log.info(`当前世界权限为${currentState}`);
break;
}
}
if (currentState != targetState) {
await clickPNG(currentState);
await clickPNG("设置" + targetState);
checkCount = 0;
} else {
checkCount++;
}
}
}
await genshin.returnMainUi();
})();
async function clickPNG(png, maxAttempts = 20) {
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`));
return await findAndClick(pngRo, true, maxAttempts);
}
async function findPNG(png, maxAttempts = 20) {
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`));
return await findAndClick(pngRo, false, maxAttempts);
}
async function findAndClick(target, doClick = true, maxAttempts = 20) {
for (let i = 0; i < maxAttempts; i++) {
const rg = captureGameRegion();
try {
const res = rg.find(target);
if (res.isExist()) { await sleep(checkInterval * 2 + 50); if (doClick) { res.click(); } return true; }
} finally { rg.dispose(); }
if (i < maxAttempts - 1) await sleep(checkInterval);
}
return false;
}

View File

@@ -1,13 +0,0 @@
{
"manifest_version": 1,
"name": "世界权限",
"version": "1.1",
"description": "带确认状态的设置世界权限",
"authors": [
{
"name": "mno"
}
],
"settings_ui": "settings.json",
"main": "main.js"
}

View File

@@ -1,24 +0,0 @@
[
{
"name": "targetState",
"type": "select",
"label": "选择要设置的世界权限",
"options": [
"确认后可加入",
"直接加入",
"不允许加入"
],
"default": "确认后可加入"
},
{
"name": "forceCheck",
"type": "checkbox",
"label": "强化确认模式,勾选后将确认切换成功才退出"
},
{
"name": "checkInterval",
"type": "input-text",
"label": "识别间隔(毫秒),设备性能较差经常设置失败时适当调大",
"default": "50"
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,115 +0,0 @@
{
"config": {
"realtime_triggers": {
"AutoPick": true
}
},
"farming_info": {
"allow_farming_count": false,
"duration_seconds": 0,
"elite_details": "",
"elite_mob_count": 0,
"normal_mob_count": 0,
"primary_target": "",
"total_mora": 0
},
"info": {
"authors": [
{
"links": "https://github.com/jiangziyanowo",
"name": "江紫烟owo"
}
],
"bgi_version": "0.45.0",
"description": "蒙德做菜炉子",
"enable_monster_loot_split": false,
"items": [],
"last_modified_time": 1758891203475,
"map_match_method": "",
"map_name": "Teyvat",
"name": "每周做菜",
"order": 0,
"tags": [],
"type": "collect",
"version": "1.0"
},
"positions": [
{
"action": "",
"id": 1,
"move_mode": "run",
"point_ext_params": {
"description": "",
"enable_monster_loot_split": false,
"misidentification": {
"arrival_time": 0,
"handling_mode": "previousDetectedPoint",
"type": [
"unrecognized"
]
}
},
"type": "teleport",
"x": -874.724609375,
"y": 2276.950439453125
},
{
"action": "",
"id": 2,
"move_mode": "run",
"point_ext_params": {
"description": "",
"enable_monster_loot_split": false,
"misidentification": {
"arrival_time": 0,
"handling_mode": "previousDetectedPoint",
"type": [
"unrecognized"
]
}
},
"type": "path",
"x": -881.150390625,
"y": 2268.43115234375
},
{
"action": "",
"id": 3,
"move_mode": "run",
"point_ext_params": {
"description": "",
"enable_monster_loot_split": false,
"misidentification": {
"arrival_time": 0,
"handling_mode": "previousDetectedPoint",
"type": [
"unrecognized"
]
}
},
"type": "path",
"x": -887.611328125,
"y": 2256.250244140625
},
{
"action": "",
"action_params": "",
"id": 4,
"move_mode": "run",
"point_ext_params": {
"description": "",
"enable_monster_loot_split": false,
"misidentification": {
"arrival_time": 0,
"handling_mode": "previousDetectedPoint",
"type": [
"unrecognized"
]
}
},
"type": "target",
"x": -883.83203125,
"y": 2242.46826171875
}
]
}

View File

@@ -1,262 +0,0 @@
let clickDelay = 16;
let sleepTimeRate = +settings.sleepTimeRate || 1;
(async function () {
if (!settings.targetDish) {
log.info("不填名字我怎么知道你要做啥")
}
await enterCook();
var extraTime = (+settings.extraTime || 0);
let i = 0;
let targetNum = +settings.targetNum || 10;
while (i < targetNum) {
let text = ""
if (settings.operationMode === "奇怪料理") {
text = "奇怪的"
}
let progress = `${i + 1}/${targetNum}`;
let percent = Math.round(((i + 1) / targetNum) * 100);
log.info(`[${percent}%]正在制作第${progress}${text}${settings.targetDish}`);
log.debug(`交互或拾取:"${text}${settings.targetDish}"`);
if (await auto_cooking_bgi(extraTime)) {
i++;
}
else await enterCook();
}
})();
async function enterCook() {
const stove = "蒙德炉子";
let attempts = 0;
let enterCooking = false;
try {
while (attempts < 10) {
await genshin.returnMainUi();
let filePath = `assets/${stove}.json`;
await pathingScript.runFile(filePath);
keyPress("F");
if (await findPNG("料理制作")) {
log.info("成功进入料理制作界面");
enterCooking = true;
break;
}
log.warn("进入料理制作界面失败,重试");
attempts++;
await genshin.returnMainUi();
}
} catch (error) {
log.error(`执行 ${stove} 路径时发生错误`);
return;
}
if (enterCooking) {
await clickPNG("筛选");
await clickPNG("重置");
await clickPNG("搜索");
inputText(settings.targetDish);
await sleep(clickDelay * sleepTimeRate);
//keyPress("VK_RETURN");
await clickPNG("确认筛选");
await clickPNG("制作");
}
}
/**
*
* 自动执行手动烹饪(源于JS脚本: 烹饪熟练度一键拉满-(柒叶子-https://github.com/511760049))
*
* @param extraTime
* @returns {Promise<number>}
*/
async function auto_cooking_bgi(extraTime) {
let success = false;
moveMouseTo(400, 750); // 移动到屏幕水平中心垂直750坐标
await clickPNG("手动烹饪", 200);
if (settings.operationMode === "奇怪料理") {
await findPNG("结束", 10);
keyPress("VK_SPACE");
await sleep(50 * sleepTimeRate);
keyPress("VK_SPACE");
if (await clickPNG("确认", 20 * 3)) {
return true;
}
else return false;
}
await sleep(1000); // 等待画面稳定
const checkPoints = [
{ x: 741, y: 772 }, // 原始点1
{ x: 758, y: 766 }, // 中间点1-2
{ x: 776, y: 760 }, // 原始点2
{ x: 793, y: 755 }, // 中间点2-3
{ x: 810, y: 751 }, // 原始点3
{ x: 827, y: 747 }, // 中间点3-4
{ x: 845, y: 744 }, // 原始点4
{ x: 861, y: 742 }, // 中间点4-5
{ x: 878, y: 740 }, // 原始点5
{ x: 897, y: 737 }, // 中间点5-6
{ x: 916, y: 735 }, // 原始点6
{ x: 933, y: 735 }, // 中间点6-7
{ x: 950, y: 736 }, // 原始点7
{ x: 968, y: 736 }, // 中间点7-8
{ x: 986, y: 737 }, // 原始点8
{ x: 1002, y: 738 }, // 中间点8-9
{ x: 1019, y: 740 }, // 原始点9
{ x: 1038, y: 742 }, // 中间点9-10
{ x: 1057, y: 744 }, // 原始点10
{ x: 1074, y: 748 }, // 中间点10-11
{ x: 1092, y: 752 }, // 原始点11
{ x: 1107, y: 757 }, // 中间点11-12
{ x: 1122, y: 762 }, // 原始点12
{ x: 1138, y: 766 }, // 中间点12-13
{ x: 1154, y: 770 }, // 原始点13
{ x: 1170, y: 774 }, // 中间点13-14
{ x: 1193, y: 779 } // 原始点14
];
// 区域大小
const regionSize = 60;
// 加载模板图片
const templateMat0 = file.readImageMatSync(`assets/RecognitionObject/best0.png`);
const templateMat1 = file.readImageMatSync(`assets/RecognitionObject/best1.png`);
const templateMat2 = file.readImageMatSync(`assets/RecognitionObject/best2.png`);
// 创建模板匹配识别对象
const templateRo0 = RecognitionObject.templateMatch(templateMat0);
const templateRo1 = RecognitionObject.templateMatch(templateMat1);
const templateRo2 = RecognitionObject.templateMatch(templateMat2);
templateRo0.threshold = 0.9;
templateRo0.Use3Channels = true;
templateRo1.threshold = 0.9;
templateRo1.Use3Channels = true;
templateRo2.threshold = 0.9;
templateRo2.Use3Channels = true;
// 捕获游戏区域
const gameRegion = captureGameRegion();
// 检查每个点
for (let i = 0; i < checkPoints.length; i++) {
const point = checkPoints[i];
// 裁剪出当前检测区域
const region = gameRegion.deriveCrop(
point.x - regionSize / 2,
point.y - regionSize / 2,
regionSize,
regionSize
);
let result;
if (i < 9) {
result = region.find(templateRo0);
} else if (i >= 18) {
result = region.find(templateRo2);
} else {
result = region.find(templateRo1);
}
region.dispose();
if (!result.isEmpty()) {
const segmentTime = 66;
const waitTime = Math.round(i * segmentTime + extraTime);
//log.info(`找到点位${i}号区域`);
await sleep(waitTime);
keyPress("VK_SPACE");
gameRegion.dispose();
if (await clickPNG("确认", 20 * 3)) {
return true;
}
else return false;
}
}
gameRegion.dispose();
return false;
// log.info(`未找到点位区域,烹饪结束`);
// keyPress("ESCAPE");
// await sleep(1000);
// keyPress("ESCAPE");
// throw new Error("人家才不是错误呢>_<");
}
async function clickPNG(png, maxAttempts = 100, Threshold = 0.9) {
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`));
pngRo.Threshold = Threshold;
pngRo.InitTemplate();
return await findAndClick(pngRo, true, maxAttempts * 50 * sleepTimeRate);
}
async function findPNG(png, maxAttempts = 100) {
const pngRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync(`assets/RecognitionObject/${png}.png`));
pngRo.Threshold = 0.9;
pngRo.InitTemplate();
return await findAndClick(pngRo, false, maxAttempts * 50 * sleepTimeRate);
}
/**
* 通用找图/找RO并可选点击支持单图片文件路径、单RO、图片文件路径数组、RO数组
* @param {string|string[]|RecognitionObject|RecognitionObject[]} target
* @param {boolean} [doClick=true] 是否点击
* @param {number} [timeout=3000] 识别时间上限ms
* @param {number} [interval=50] 识别间隔ms
* @param {number} [retType=0] 0-返回布尔1-返回 Region 结果
* @param {number} [preClickDelay=50] 点击前等待
* @param {number} [postClickDelay=50] 点击后等待
* @returns {boolean|Region} 根据 retType 返回是否成功或最终 Region
*/
async function findAndClick(target,
doClick = true,
timeout = 3000,
interval = 50,
retType = 0,
preClickDelay = 50,
postClickDelay = 50) {
try {
// 1. 统一转成 RecognitionObject 数组
let ros = [];
if (Array.isArray(target)) {
ros = target.map(t =>
(typeof t === 'string')
? RecognitionObject.TemplateMatch(file.ReadImageMatSync(t))
: t
);
} else {
ros = [(typeof target === 'string')
? RecognitionObject.TemplateMatch(file.ReadImageMatSync(target))
: target];
}
const start = Date.now();
let found = null;
while (Date.now() - start <= timeout) {
const gameRegion = captureGameRegion();
try {
// 依次尝试每一个 ro
for (const ro of ros) {
const res = gameRegion.find(ro);
if (!res.isEmpty()) { // 找到
found = res;
if (doClick) {
await sleep(preClickDelay * sleepTimeRate);
res.click();
await sleep(postClickDelay * sleepTimeRate);
}
break; // 成功即跳出 for
}
}
if (found) break; // 成功即跳出 while
} finally {
gameRegion.dispose();
}
await sleep(interval * sleepTimeRate); // 没找到时等待
}
// 3. 按需返回
return retType === 0 ? !!found : (found || null);
} catch (error) {
log.error(`执行通用识图时出现错误:${error.message}`);
return retType === 0 ? false : null;
}
}

View File

@@ -1,16 +0,0 @@
{
"manifest_version": 1,
"name": "普通奇怪料理",
"version": "1.2",
"bgi_version": "0.44.8",
"description": "",
"saved_files": [],
"authors": [
{
"name": "mno",
"links": "https://github.com/Bedrockx"
}
],
"settings_ui": "settings.json",
"main": "main.js"
}

View File

@@ -1,34 +0,0 @@
[
{
"name": "targetDish",
"type": "input-text",
"label": "需要烹饪的料理名称"
},
{
"name": "operationMode",
"type": "select",
"label": "选择烹饪类型",
"options": [
"奇怪料理",
"普通料理"
]
},
{
"name": "targetNum",
"type": "input-text",
"label": "输入目标数量",
"default": "10"
},
{
"name": "extraTime",
"type": "input-text",
"label": "烹饪时间修正(毫秒)\n制作普通料理时按空格的时机将延后该值(负数则提前)",
"default": "0"
},
{
"name": "sleepTimeRate",
"type": "input-text",
"label": "识别间隔修正,各种等待时间将被调整为原来的该数值倍\n仅建议在设备较差出现明显问题时调大",
"default": "1"
}
]