两个狗粮js替换拾取模式 (#1976)

* js:锄地一条龙1.3.1

* js:联机狗粮1.4.0

* Update 509【收尾】枫丹-科学院工坊高塔①-9.json

更新一条路线
This commit is contained in:
mno
2025-09-23 08:22:06 +08:00
committed by GitHub
parent e6ee69f696
commit 92749bd234
50 changed files with 490 additions and 61 deletions

View File

@@ -82,6 +82,10 @@ https://www.kdocs.cn/wo/sl/v13uXscL
## 更新日志
### 1.3.12025.09.22
1.修正等待时间错误
### 1.3.02025.09.21
1.将拾取方式修改为模板匹配拾取
### 1.2.152025.09.20
1.修几条路线305①,632,640,628
### 1.2.142025.09.19

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,23 @@
[
{
"position": {
"x": 14031,
"y": 440
},
"name": "度假村"
},
{
"position": {
"x": 5319,
"y": -2330
},
"name": "智障厅"
},
{
"position": {
"x": -3354,
"y": -3578
},
"name": "踏鞴砂"
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,25 @@
{
"macroEvents": [
{
"type": 6,
"mouseX": 0,
"mouseY": 120,
"time": 0
},
{
"type": 6,
"mouseX": 0,
"mouseY": 0,
"time": 5
}
],
"info": {
"name": "滚轮上翻",
"description": "模拟鼠标滚轮向上滚动120单位",
"x": 0,
"y": 0,
"width": 1920,
"height": 1080,
"recordDpi": 1
}
}

View File

@@ -0,0 +1,25 @@
{
"macroEvents": [
{
"type": 6,
"mouseX": 0,
"mouseY": -120,
"time": 0
},
{
"type": 6,
"mouseX": 0,
"mouseY": 0,
"time": 5
}
],
"info": {
"name": "",
"description": "模拟鼠标滚轮向上滚动120单位",
"x": 0,
"y": 0,
"width": 1920,
"height": 1080,
"recordDpi": 1
}
}

View File

@@ -43,8 +43,18 @@ let failcount = 0;
let autoSalvageCount = 0;
let furinaState = "unknown";
let targetItems;
let pickupDelay = 100;
let timeMove = 1000;
let timeMoveUp = Math.round(timeMove * 0.45);
let timeMoveDown = Math.round(timeMove * 0.55);
let rollingDelay = 25;
let gameRegion;
(async function () {
setGameMetrics(1920, 1080, 1);
targetItems = await loadTargetItems();
state.activatePickUp = false;
{
//校验自定义配置,从未打开过自定义配置时进行警告
if (!settings.accountName) {
@@ -849,8 +859,6 @@ async function writeCDInfo(accountName) {
//运行普通路线
async function runNormalPath(doStop) {
furinaState = "unknown";
//关闭拾取
dispatcher.ClearAllTriggers();
if (state.cancel) return;
const routeMap = { A: normalPathA, B: normalPathB, C: normalPathC };
const normalPath = routeMap[state.runningRoute];
@@ -860,16 +868,14 @@ async function runNormalPath(doStop) {
log.info("填写了清怪队伍,执行清怪路线");
await runPaths(normalCombatPath, combatPartyName, doStop, "black");
}
// 启用自动拾取的实时任务
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
state.activatePickUp = true;
await runPaths(normalExecutePath, artifactPartyName, doStop, "white");
state.activatePickUp = false;
}
async function runActivatePath() {
//furinaState = "unknown";
//关闭拾取
dispatcher.ClearAllTriggers();
if (state.cancel) return;
if (!state.activatedToday) {
log.info("今日未执行过激活路线");
@@ -932,8 +938,6 @@ async function runActivatePath() {
async function runEndingAndExtraPath() {
furinaState = "unknown";
// 启用自动拾取的实时任务
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
if (state.cancel) return;
let endingPath = state.runningEndingAndExtraRoute === "收尾额外A"
? "assets/ArtifactsPath/优先收尾路线"
@@ -958,9 +962,11 @@ async function runEndingAndExtraPath() {
? "assets/ArtifactsPath/额外/所有额外"
: "assets/ArtifactsPath/额外/仅12h额外";
endingPath = endingPath + "/执行";
state.activatePickUp = true;
await runPaths(endingPath, artifactPartyName, false, "white");
extraPath = extraPath + "/执行";
await runPaths(extraPath, artifactPartyName, false, "white");
state.activatePickUp = false;
}
async function runPaths(folderFilePath, PartyName, doStop, furinaRequirement = "") {
@@ -973,7 +979,7 @@ async function runPaths(folderFilePath, PartyName, doStop, furinaRequirement = "
if (new Date() >= state.aimActivateTime && doStop) {
log.info("已经到达预定时间");
break;
} else if ((new Date() >= (state.aimActivateTime - minIntervalTime * 60)) && doStop) {
} else if ((new Date() >= (state.aimActivateTime - minIntervalTime * 60 * 1000)) && doStop) {
log.info(`即将到达预定时间,等待${state.aimActivateTime - new Date()}毫秒`);
await sleep(state.aimActivateTime - new Date())
break;
@@ -1016,11 +1022,10 @@ async function runPaths(folderFilePath, PartyName, doStop, furinaRequirement = "
} else {
autoSalvageCount++;
}
await fakeLog(Path.fileName, false, true, 0);
const pathInfo = await parsePathing(Path.fullPath);
try {
log.info(`当前进度:${Path.fileName}${folderFilePath}${i + 1}/${Paths.length}`);
await pathingScript.runFile(Path.fullPath);
await runPath(Path.fullPath, null);
await sleep(1);
} catch (error) {
skiprecord = true;
@@ -1032,7 +1037,6 @@ async function runPaths(folderFilePath, PartyName, doStop, furinaRequirement = "
success = false;
break;
}
await fakeLog(Path.fileName, false, false, 0);
if (pathInfo.ok) {
await genshin.returnMainUi();
await sleep(500);
@@ -1211,4 +1215,175 @@ async function fakeLog(name, isJs, isStart, duration) {
`------------------------------`;
log.debug(logMessage);
}
}
async function runPath(fullPath, targetItemPath = null) {
state = state || {}; // 若已存在则保持原引用,否则新建空对象
state.running = true;
/* ---------- 主任务 ---------- */
const pathingTask = (async () => {
log.info(`开始执行路线: ${fullPath}`);
await fakeLog(fullPath, false, true, 0);
await pathingScript.runFile(fullPath);
await fakeLog(fullPath, false, false, 0);
state.running = false;
})();
/* ---------- 伴随任务 ---------- */
const pickupTask = (async () => {
if (state.activatePickUp) {
await recognizeAndInteract();
}
})();
const errorProcessTask = (async () => {
const revivalRo1 = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/revival.png"));
let errorCheckCount = 9;
while (state.running) {
await sleep(100);
errorCheckCount++;
if (errorCheckCount > 50) {
errorCheckCount = 0;
//log.info("尝试识别并点击复苏按钮");
if (await findAndClick(revivalRo1, 2)) {
//log.info("识别到复苏按钮,点击复苏");
}
}
}
})();
/* ---------- 并发等待 ---------- */
await Promise.allSettled([pathingTask, pickupTask, errorProcessTask]);
}
//加载拾取物图片
async function loadTargetItems() {
const targetItemPath = 'assets/targetItems'; // 固定目录
const items = await readFolder(targetItemPath, false);
// 统一预加载模板
for (const it of items) {
it.template = file.ReadImageMatSync(it.fullPath);
it.itemName = it.fileName.replace(/\.png$/i, '');
}
return items;
}
// 定义一个函数用于拾取
async function recognizeAndInteract() {
//log.info("调试-开始执行图像识别与拾取任务");
let lastcenterYF = 0;
let lastItemName = "";
let fIcontemplate = file.ReadImageMatSync('assets/F_Dialogue.png');
let mainUITemplate = file.ReadImageMatSync("assets/MainUI.png");
let thisMoveUpTime = 0;
let lastMoveDown = 0;
gameRegion = captureGameRegion();
//主循环
while (state.running) {
gameRegion.dispose();
gameRegion = captureGameRegion();
let centerYF = await findFIcon();
if (!centerYF) {
if (await isMainUI()) await keyMouseScript.runFile(`assets/滚轮下翻.json`);
continue;
}
//log.info(`调试-成功找到f图标,centerYF为${centerYF}`);
let foundTarget = false;
let itemName = await performTemplateMatch(centerYF);
if (itemName) {
//log.info(`调试-识别到物品${itemName}`);
if (Math.abs(lastcenterYF - centerYF) <= 20 && lastItemName === itemName) {
//log.info("调试-相同物品名和相近y坐标本次不拾取");
await sleep(2 * pickupDelay);
lastcenterYF = -20;
lastItemName = null;
} else {
keyPress("F");
log.info(`交互或拾取:"${itemName}"`);
lastcenterYF = centerYF;
lastItemName = itemName;
await sleep(pickupDelay);
}
} else {
/*
log.info("识别失败,尝试截图");
await refreshTargetItems(centerYF);
lastItemName = "";
*/
}
if (!foundTarget) {
//log.info(`调试-执行滚轮动作`);
const currentTime = new Date().getTime();
if (currentTime - lastMoveDown > timeMoveUp) {
await keyMouseScript.runFile(`assets/滚轮下翻.json`);
if (thisMoveUpTime === 0) thisMoveUpTime = currentTime;
if (currentTime - thisMoveUpTime >= timeMoveDown) {
lastMoveDown = currentTime;
thisMoveUpTime = 0;
}
} else {
await keyMouseScript.runFile(`assets/滚轮上翻.json`);
}
await sleep(rollingDelay);
}
}
async function performTemplateMatch(centerYF) {
try {
let result;
let itemName = null;
for (const targetItem of targetItems) {
let recognitionObject = RecognitionObject.TemplateMatch(targetItem.template, 1219, centerYF - 15, 32 + 30 * (targetItem.itemName.length) + 2, 30);
result = gameRegion.find(recognitionObject);
if (result.isExist()) {
itemName = targetItem.itemName;
break;
}
}
return itemName;
} catch (error) {
log.error(`模板匹配时发生异常: ${error.message}`);
return null;
}
}
async function findFIcon() {
let recognitionObject = RecognitionObject.TemplateMatch(fIcontemplate, 1102, 335, 34, 400);
try {
let result = gameRegion.find(recognitionObject);
if (result.isExist()) {
return Math.round(result.y + result.height / 2);
}
} catch (error) {
log.error(`识别图像时发生异常: ${error.message}`);
if (!state.running)
return null;
}
await sleep(100);
return null;
}
async function isMainUI() {
const recognitionObject = RecognitionObject.TemplateMatch(mainUITemplate, 0, 0, 150, 150);
const maxAttempts = 1;
let attempts = 0;
while (attempts < maxAttempts && state.running) {
try {
const result = gameRegion.find(recognitionObject);
if (result.isExist()) return true;
} catch (error) {
log.error(`识别图像时发生异常: ${error.message}`);
if (!state.running) break;
return false;
}
attempts++;
await sleep(50);
}
return false;
}
}

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "AAA狗粮批发",
"version": "1.2.15",
"version": "1.3.1",
"tags": [
"狗粮"
],

View File

@@ -24,6 +24,9 @@
* **预留足够的背包空间**运行AAA狗粮批发将获取约150个圣遗物运行本js将获取约230个圣遗物请确保你的背包有足够的空间容纳这些圣遗物建议在AAA狗粮批发中选择分解或摧毁并预留380+的空间
## 更新日志
### 1.4.02025.09.20
1.将拾取模式修改为模板匹配拾取
### 1.3.22025.09.20
1.修几处路线度假村踩点,624③,509①②,305①
### 1.3.12025.09.19
@@ -46,5 +49,4 @@
### 1.2.12025.09.04
1,修几处路线627,水天丛林,
### 1.2.02025.09.03
1.增加几处错误处理,增加容错
1.增加几处错误处理,增加容错

View File

@@ -9,7 +9,7 @@
"bgi_version": "0.45.0",
"description": "",
"enable_monster_loot_split": false,
"last_modified_time": 1758376990820,
"last_modified_time": 1758555670986,
"map_match_method": "",
"map_name": "Teyvat",
"name": "509【收尾】枫丹-科学院工坊高塔①-9",
@@ -214,25 +214,16 @@
},
{
"action": "combat_script",
"action_params": "keydown(w),keypress(f),attack(4.5),keyup(w)",
"action_params": "keypress(x),a(0.1);万叶 attack(0.08),keydown(E),wait(0.51),keyup(E),attack(0.2),wait(0.5);琴 attack(0.08),keydown(E),wait(0.4),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,-3500),wait(1.8),keyup(E),wait(0.3),click(middle);",
"id": 23,
"move_mode": "climb",
"type": "orientation",
"x": 4397.052734375,
"y": 4920.9658203125
},
{
"action": "combat_script",
"action_params": "keypress(f),a(0.1),keypress(f),keypress(f);万叶 attack(0.08),keydown(E),wait(0.51),keyup(E),attack(0.2),wait(0.5);琴 attack(0.08),keydown(E),wait(0.4),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,-3500),wait(1.8),keyup(E),wait(0.3),click(middle);",
"id": 24,
"move_mode": "climb",
"type": "target",
"x": 4398.31640625,
"y": 4922.1220703125
},
{
"action": "",
"id": 25,
"id": 24,
"move_mode": "walk",
"type": "path",
"x": 4399.093769750416,
@@ -241,7 +232,7 @@
{
"action": "",
"action_params": "",
"id": 26,
"id": 25,
"move_mode": "climb",
"type": "orientation",
"x": 4402.75146484375,
@@ -250,7 +241,7 @@
{
"action": "",
"action_params": "",
"id": 27,
"id": 26,
"move_mode": "climb",
"type": "path",
"x": 4402.75146484375,
@@ -258,8 +249,8 @@
},
{
"action": "combat_script",
"action_params": "keypress(f),wait(0.2),keypress(f),d(0.3),keypress(f),wait(0.2),keypress(x);万叶 attack(0.08),keydown(E),wait(0.51),keyup(E),attack(0.2),wait(0.5);琴 attack(0.08),keydown(E),wait(0.4),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,-3500),wait(1.8),keyup(E),wait(0.3),click(middle);",
"id": 28,
"action_params": "keypress(f),keypress(x),wait(0.2),keypress(f),keypress(x),d(0.3),keypress(f),keypress(x),wait(0.2),keypress(x);万叶 attack(0.08),keydown(E),wait(0.51),keyup(E),attack(0.2),wait(0.5);琴 attack(0.08),keydown(E),wait(0.4),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,-3500),wait(1.8),keyup(E),wait(0.3),click(middle);",
"id": 27,
"move_mode": "climb",
"type": "target",
"x": 4398.71875,
@@ -268,7 +259,7 @@
{
"action": "combat_script",
"action_params": "attack(0.3)",
"id": 29,
"id": 28,
"move_mode": "dash",
"type": "path",
"x": 4397.109375,
@@ -277,7 +268,7 @@
{
"action": "",
"action_params": "",
"id": 30,
"id": 29,
"move_mode": "dash",
"type": "path",
"x": 4409.123046875,
@@ -286,7 +277,7 @@
{
"action": "",
"action_params": "",
"id": 31,
"id": 30,
"move_mode": "dash",
"type": "path",
"x": 4431.09375,
@@ -295,7 +286,7 @@
{
"action": "",
"action_params": "",
"id": 32,
"id": 31,
"move_mode": "dash",
"type": "path",
"x": 4493.9091796875,
@@ -304,7 +295,7 @@
{
"action": "stop_flying",
"action_params": "",
"id": 33,
"id": 32,
"move_mode": "fly",
"type": "path",
"x": 4503.7236328125,
@@ -313,7 +304,7 @@
{
"action": "combat_script",
"action_params": "keypress(f),wait(0.2),keypress(f),wait(0.2),keypress(f)",
"id": 34,
"id": 33,
"move_mode": "dash",
"type": "target",
"x": 4498.919921875,
@@ -322,7 +313,7 @@
{
"action": "",
"action_params": "",
"id": 35,
"id": 34,
"move_mode": "walk",
"type": "path",
"x": 4493.6455078125,
@@ -331,7 +322,7 @@
{
"action": "combat_script",
"action_params": "w(0.3),dash,w(0.7),dash,wait(0.8)",
"id": 36,
"id": 35,
"move_mode": "walk",
"type": "orientation",
"x": 4463.6845703125,
@@ -340,7 +331,7 @@
{
"action": "",
"action_params": "",
"id": 37,
"id": 36,
"move_mode": "dash",
"type": "path",
"x": 4463.6845703125,
@@ -349,7 +340,7 @@
{
"action": "combat_script",
"action_params": "keypress(f),wait(0.2),keypress(f),wait(0.2),keypress(f),wait(0.2),keypress(f),wait(0.2),keypress(f);万叶 attack(0.08),keydown(E),wait(0.7),keyup(E),attack(0.2);琴 attack(0.08),keydown(E),wait(0.4),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,0),wait(0.2),moveby(1000,-3500),wait(1.8),keyup(E),wait(0.3),click(middle);",
"id": 38,
"id": 37,
"move_mode": "dash",
"type": "target",
"x": 4440.625,
@@ -358,7 +349,7 @@
{
"action": "",
"action_params": "",
"id": 39,
"id": 38,
"move_mode": "dash",
"type": "path",
"x": 4422.212890625,

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,25 @@
{
"macroEvents": [
{
"type": 6,
"mouseX": 0,
"mouseY": 120,
"time": 0
},
{
"type": 6,
"mouseX": 0,
"mouseY": 0,
"time": 5
}
],
"info": {
"name": "滚轮上翻",
"description": "模拟鼠标滚轮向上滚动120单位",
"x": 0,
"y": 0,
"width": 1920,
"height": 1080,
"recordDpi": 1
}
}

View File

@@ -0,0 +1,25 @@
{
"macroEvents": [
{
"type": 6,
"mouseX": 0,
"mouseY": -120,
"time": 0
},
{
"type": 6,
"mouseX": 0,
"mouseY": 0,
"time": 5
}
],
"info": {
"name": "",
"description": "模拟鼠标滚轮向上滚动120单位",
"x": 0,
"y": 0,
"width": 1920,
"height": 1080,
"recordDpi": 1
}
}

View File

@@ -1,10 +1,24 @@
const runExtra = settings.runExtra || false;
const leaveTeamRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/leaveTeam.png"));
let targetItems;
let pickupDelay = 100;
let timeMove = 1000;
let timeMoveUp = Math.round(timeMove * 0.45);
let timeMoveDown = Math.round(timeMove * 0.55);
let rollingDelay = 25;
let state;
let gameRegion;
(async function () {
if (settings.groupMode != "按照下列配置自动进入并运行") await runGroupPurchasing(runExtra);
setGameMetrics(1920, 1080, 1);
await genshin.tpToStatueOfTheSeven();
await switchPartyIfNeeded(settings.partyName);
targetItems = await loadTargetItems();
if (settings.groupMode != "按照下列配置自动进入并运行") {
await genshin.clearPartyCache();
await runGroupPurchasing(runExtra);
}
if (settings.groupMode != "手动进入后运行") {
await switchPartyIfNeeded(settings.partyName)
//解析与输出自定义配置
const raw = settings.runningOrder || "1234";
if (!/^[1-4]+$/.test(raw)) {
@@ -25,6 +39,7 @@ const leaveTeamRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("asset
// 按 runningOrder 依次进入世界并执行联机收尾
for (const idx of enteringIndex) {
await genshin.clearPartyCache();
if (settings.usingCharacter) { await sleep(1000); keyPress(`${settings.usingCharacter}`); }
//构造加入idx号世界的autoEnter的settings
let autoEnterSettings;
@@ -32,7 +47,7 @@ const leaveTeamRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("asset
// 1. 先收集真实存在的白名单
const permits = {};
let permitIndex = 1;
for (const otherIdx of enteringIndex) {
for (const otherIdx of [1, 2, 3, 4]) {
if (otherIdx !== yourIndex) {
const pName = settings[`p${otherIdx}Name`];
if (pName) { // 过滤掉空/undefined
@@ -97,6 +112,7 @@ const leaveTeamRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("asset
await runGroupPurchasing(runExtra);
}
}
await genshin.tpToStatueOfTheSeven();
}
)();
@@ -147,8 +163,6 @@ async function runGroupPurchasing(runExtra) {
let running = true;
// ===== 4. 主流程 =====
setGameMetrics(1920, 1080, 1);
await genshin.clearPartyCache();
log.info("开始识别队伍编号");
let groupNumBer = await getPlayerSign();
if (groupNumBer !== 0) log.info(`在队伍中编号为${groupNumBer}`);
@@ -160,7 +174,6 @@ async function runGroupPurchasing(runExtra) {
}
if (groupNumBer === 1) {
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
log.info("是1p检测当前总人数");
const totalNumber = await findTotalNumber();
await waitForReady(totalNumber);
@@ -211,7 +224,6 @@ async function runGroupPurchasing(runExtra) {
}
} else if (runExtra) {
log.info("请确保联机收尾已结束,将开始运行额外路线");
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
await runExtraPath();
}
running = false;
@@ -222,8 +234,6 @@ async function runGroupPurchasing(runExtra) {
* @param {number} timeOut 最长等待毫秒
*/
async function waitForReady(totalNumber, timeOut = 300000) {
await genshin.tpToStatueOfTheSeven();
// 实际需要检测的队友编号2 ~ totalNumber
const needCheck = totalNumber - 1; // 队友人数
const readyFlags = new Array(needCheck).fill(false); // 下标 0 代表 2P1 代表 3P …
@@ -1011,7 +1021,7 @@ async function readFolder(folderPath, onlyJson) {
}
async function runPath(fullPath, targetItemPath) {
const state = { running: true };
state = { running: true };
/* ---------- 主任务 ---------- */
const pathingTask = (async () => {
@@ -1025,13 +1035,7 @@ async function runPath(fullPath, targetItemPath) {
/* ---------- 伴随任务 ---------- */
const pickupTask = (async () => {
//if (!targetItemPath) return; // 没有拾取目录直接跳过
//dispatcher.addTimer(new RealtimeTimer("AutoPick"));
while (state.running) {
await sleep(1000);
}
//dispatcher.ClearAllTriggers();
await recognizeAndInteract();
})();
const errorProcessTask = (async () => {
@@ -1043,7 +1047,7 @@ async function runPath(fullPath, targetItemPath) {
if (errorCheckCount > 50) {
errorCheckCount = 0;
//log.info("尝试识别并点击复苏按钮");
if (await findAndClick(revivalRo1,2)) {
if (await findAndClick(revivalRo1, 2)) {
//log.info("识别到复苏按钮,点击复苏");
}
}
@@ -1052,4 +1056,134 @@ async function runPath(fullPath, targetItemPath) {
/* ---------- 并发等待 ---------- */
await Promise.allSettled([pathingTask, pickupTask, errorProcessTask]);
}
//加载拾取物图片
async function loadTargetItems() {
const targetItemPath = 'assets/targetItems'; // 固定目录
const items = await readFolder(targetItemPath, false);
// 统一预加载模板
for (const it of items) {
it.template = file.ReadImageMatSync(it.fullPath);
it.itemName = it.fileName.replace(/\.png$/i, '');
}
return items;
}
// 定义一个函数用于拾取
async function recognizeAndInteract() {
//log.info("调试-开始执行图像识别与拾取任务");
let lastcenterYF = 0;
let lastItemName = "";
let fIcontemplate = file.ReadImageMatSync('assets/F_Dialogue.png');
let mainUITemplate = file.ReadImageMatSync("assets/MainUI.png");
let thisMoveUpTime = 0;
let lastMoveDown = 0;
gameRegion = captureGameRegion();
//主循环
while (state.running) {
gameRegion.dispose();
gameRegion = captureGameRegion();
let centerYF = await findFIcon();
if (!centerYF) {
if (await isMainUI()) await keyMouseScript.runFile(`assets/滚轮下翻.json`);
continue;
}
//log.info(`调试-成功找到f图标,centerYF为${centerYF}`);
let foundTarget = false;
let itemName = await performTemplateMatch(centerYF);
if (itemName) {
//log.info(`调试-识别到物品${itemName}`);
if (Math.abs(lastcenterYF - centerYF) <= 20 && lastItemName === itemName) {
//log.info("调试-相同物品名和相近y坐标本次不拾取");
await sleep(2 * pickupDelay);
lastcenterYF = -20;
lastItemName = null;
} else {
keyPress("F");
log.info(`交互或拾取:"${itemName}"`);
lastcenterYF = centerYF;
lastItemName = itemName;
await sleep(pickupDelay);
}
} else {
/*
log.info("识别失败,尝试截图");
await refreshTargetItems(centerYF);
lastItemName = "";
*/
}
if (!foundTarget) {
//log.info(`调试-执行滚轮动作`);
const currentTime = new Date().getTime();
if (currentTime - lastMoveDown > timeMoveUp) {
await keyMouseScript.runFile(`assets/滚轮下翻.json`);
if (thisMoveUpTime === 0) thisMoveUpTime = currentTime;
if (currentTime - thisMoveUpTime >= timeMoveDown) {
lastMoveDown = currentTime;
thisMoveUpTime = 0;
}
} else {
await keyMouseScript.runFile(`assets/滚轮上翻.json`);
}
await sleep(rollingDelay);
}
}
async function performTemplateMatch(centerYF) {
try {
let result;
let itemName = null;
for (const targetItem of targetItems) {
let recognitionObject = RecognitionObject.TemplateMatch(targetItem.template, 1219, centerYF - 15, 32 + 30 * (targetItem.itemName.length) + 2, 30);
result = gameRegion.find(recognitionObject);
if (result.isExist()) {
itemName = targetItem.itemName;
break;
}
}
return itemName;
} catch (error) {
log.error(`模板匹配时发生异常: ${error.message}`);
return null;
}
}
async function findFIcon() {
let recognitionObject = RecognitionObject.TemplateMatch(fIcontemplate, 1102, 335, 34, 400);
try {
let result = gameRegion.find(recognitionObject);
if (result.isExist()) {
return Math.round(result.y + result.height / 2);
}
} catch (error) {
log.error(`识别图像时发生异常: ${error.message}`);
if (!state.running)
return null;
}
await sleep(100);
return null;
}
async function isMainUI() {
const recognitionObject = RecognitionObject.TemplateMatch(mainUITemplate, 0, 0, 150, 150);
const maxAttempts = 1;
let attempts = 0;
while (attempts < maxAttempts && state.running) {
try {
const result = gameRegion.find(recognitionObject);
if (result.isExist()) return true;
} catch (error) {
log.error(`识别图像时发生异常: ${error.message}`);
if (!state.running) break;
return false;
}
attempts++;
await sleep(50);
}
return false;
}
}

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "AAA狗粮联机团购",
"version": "1.3.2",
"version": "1.4.0",
"tags": [
"狗粮"
],