mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-13 19:43:40 +08:00
@@ -43,16 +43,23 @@ const scrollRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/
|
||||
//全局通用变量声明
|
||||
let gameRegion;
|
||||
let targetItems;
|
||||
let doFurinaSwitch = false;
|
||||
let lastRoll = new Date();
|
||||
let shouldSwitchFurina = false;
|
||||
let lastRollTime = new Date();
|
||||
let blacklist = [];
|
||||
let blacklistSet = new Set();
|
||||
let state;
|
||||
let pathings;
|
||||
let localeWorks;
|
||||
let lastEatBuff = 0;
|
||||
let localeTimeSupported;
|
||||
let lastBuffTime = 0;
|
||||
let currentFood = "";
|
||||
let monsterInfoObject;
|
||||
const gameRegionManager = {
|
||||
newGameRegion: null,
|
||||
oldGameRegion: null,
|
||||
lastCapture: new Date(),
|
||||
isDisposing: false,
|
||||
isCapturing: false
|
||||
};
|
||||
|
||||
(async function () {
|
||||
//通用预处理
|
||||
@@ -65,7 +72,7 @@ let monsterInfoObject;
|
||||
await switchPartyTask;
|
||||
}
|
||||
targetItems = await loadTargetItems();
|
||||
localeWorks = await checkLocaleTimeSupport();
|
||||
localeTimeSupported = await checkLocaleTimeSupport();
|
||||
dispatcher.AddTrigger(new RealtimeTimer("AutoSkip"));
|
||||
await loadBlacklist(true);
|
||||
await rotateWarnIfAccountEmpty();
|
||||
@@ -956,17 +963,17 @@ async function copyPathingsByGroup(pathings) {
|
||||
* - blacklistTask:背包满时OCR识别并拉黑多余物品
|
||||
* - dumperTask(可选):接近战斗坐标时自动切人放E
|
||||
* 3. 全部子任务完成后返回,state.running 被置 false
|
||||
* 依赖全局:settings、state、pathings、targetItems、dumpers、doFurinaSwitch、lastEatBuff 等
|
||||
* 依赖全局:settings、state、pathings、targetItems、dumpers、shouldSwitchFurina、lastBuffTime 等
|
||||
*/
|
||||
async function runPath(fullPath, map_name, pm, pe) {
|
||||
//当需要切换芙宁娜形态时,执行一次强制黑芙
|
||||
if (doFurinaSwitch) {
|
||||
if (shouldSwitchFurina) {
|
||||
log.info("上条路线识别到白芙,开始强制切换黑芙")
|
||||
doFurinaSwitch = false;
|
||||
shouldSwitchFurina = false;
|
||||
await pathingScript.runFile("assets/强制黑芙.json");
|
||||
}
|
||||
if (settings.eatBuff) {
|
||||
if (new Date() - lastEatBuff > 300 * 1000) {
|
||||
if (new Date() - lastBuffTime > 300 * 1000) {
|
||||
// 1. 数据预处理:分割、去空、去重
|
||||
let res = settings.eatBuff
|
||||
.split(',')
|
||||
@@ -1009,7 +1016,7 @@ async function runPath(fullPath, map_name, pm, pe) {
|
||||
await findAndClick("assets/使用.png");
|
||||
}
|
||||
await genshin.returnMainUi();
|
||||
lastEatBuff = new Date();
|
||||
lastBuffTime = new Date();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1142,10 +1149,10 @@ async function runPath(fullPath, map_name, pm, pe) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!doFurinaSwitch) {
|
||||
if (!shouldSwitchFurina) {
|
||||
if (await findAndClick(whiteFurinaRo, false, 2, 3)) {
|
||||
log.info("检测到白芙,本路线运行结束后切换芙宁娜形态");
|
||||
doFurinaSwitch = true;
|
||||
shouldSwitchFurina = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1175,8 +1182,7 @@ async function runPath(fullPath, map_name, pm, pe) {
|
||||
let attempts = 0;
|
||||
while (attempts < maxAttempts && state.running) {
|
||||
try {
|
||||
gameRegion.dispose();
|
||||
gameRegion = captureGameRegion();
|
||||
gameRegion = await getGameRegion();
|
||||
const result = gameRegion.find(itemFullRo);
|
||||
if (result.isExist()) {
|
||||
return true;
|
||||
@@ -1304,18 +1310,16 @@ async function recognizeAndInteract() {
|
||||
let lastItemName = "";
|
||||
let thisMoveUpTime = 0;
|
||||
let lastMoveDown = 0;
|
||||
gameRegion = captureGameRegion();
|
||||
let itemName;
|
||||
//主循环
|
||||
while (state.running) {
|
||||
//log.info("调试-交互拾取进行中");
|
||||
gameRegion.dispose();
|
||||
gameRegion = captureGameRegion();
|
||||
gameRegion = await getGameRegion();
|
||||
let centerYF = await findFIcon();
|
||||
|
||||
if (!centerYF) {
|
||||
if (new Date() - lastRoll >= 200) {
|
||||
lastRoll = new Date();
|
||||
if (new Date() - lastRollTime >= 200) {
|
||||
lastRollTime = new Date();
|
||||
if (await hasScroll()) {
|
||||
await keyMouseScript.runFile(`assets/滚轮下翻.json`);
|
||||
}
|
||||
@@ -1578,13 +1582,9 @@ async function dumper(pathFilePath, map_name) {
|
||||
const maxAttempts = 10;
|
||||
|
||||
let attempts = 0;
|
||||
let dodispose = false;
|
||||
while (attempts < maxAttempts && state.running) {
|
||||
try {
|
||||
if (!gameRegion) {
|
||||
gameRegion = captureGameRegion();
|
||||
dodispose = true;
|
||||
}
|
||||
gameRegion = await getGameRegion()
|
||||
let result = gameRegion.find(recognitionObject);
|
||||
if (result.isExist()) {
|
||||
return true; // 如果找到图标,返回 true
|
||||
@@ -1595,9 +1595,6 @@ async function dumper(pathFilePath, map_name) {
|
||||
}
|
||||
attempts++; // 增加尝试次数
|
||||
await sleep(200); // 每次检测间隔 200 毫秒
|
||||
if (dodispose) {
|
||||
gameRegion.dispose();
|
||||
}
|
||||
}
|
||||
return false; // 如果尝试次数达到上限或取消,返回 false
|
||||
}
|
||||
@@ -1811,7 +1808,7 @@ async function processPathingsByGroup(pathings, accountName) {
|
||||
}
|
||||
// 更新路径的 cdTime
|
||||
pathing.cdTime = newCDTime.toLocaleString();
|
||||
if (!localeWorks) pathing.cdTime = newCDTime.toISOString();
|
||||
if (!localeTimeSupported) pathing.cdTime = newCDTime.toISOString();
|
||||
|
||||
await updateRecords(pathings, accountName);
|
||||
}
|
||||
@@ -1824,7 +1821,7 @@ async function processPathingsByGroup(pathings, accountName) {
|
||||
* - 为每条路线赋予 cdTime(本地或UTC)与最近7次运行时长
|
||||
* - 拾取历史仅保留最后20个不重复项
|
||||
* 若记录文件缺失则初始化为7条-1
|
||||
* 依赖:file、accountName、localeWorks
|
||||
* 依赖:file、accountName、localeTimeSupported
|
||||
*/
|
||||
async function initializeCdTime(pathings, accountName) {
|
||||
try {
|
||||
@@ -1845,7 +1842,7 @@ async function initializeCdTime(pathings, accountName) {
|
||||
? new Date(entry.cdTime).toLocaleString()
|
||||
: new Date(0).toLocaleString();
|
||||
|
||||
if (!localeWorks) pathing.cdTime = entry
|
||||
if (!localeTimeSupported) pathing.cdTime = entry
|
||||
? new Date(entry.cdTime).toISOString()
|
||||
: new Date(0).toISOString();
|
||||
// 确保当前 records 是数组
|
||||
@@ -1867,7 +1864,7 @@ async function initializeCdTime(pathings, accountName) {
|
||||
pathing.cdTime = new Date(0).toLocaleString();
|
||||
pathing.records = new Array(7).fill(-1);
|
||||
});
|
||||
if (!localeWorks) pathings.forEach(pathing => {
|
||||
if (!localeTimeSupported) pathings.forEach(pathing => {
|
||||
pathing.cdTime = new Date(0).toISOString();
|
||||
pathing.records = new Array(7).fill(-1);
|
||||
});
|
||||
@@ -1957,12 +1954,8 @@ async function switchPartyIfNeeded(partyName) {
|
||||
*/
|
||||
async function isMainUI(maxDuration = 10) {
|
||||
const start = Date.now();
|
||||
let dodispose = false;
|
||||
while (Date.now() - start < maxDuration) {
|
||||
if (!gameRegion) {
|
||||
gameRegion = captureGameRegion();
|
||||
dodispose = true;
|
||||
}
|
||||
gameRegion = await getGameRegion();
|
||||
try {
|
||||
const result = gameRegion.find(mainUIRo);
|
||||
if (result.isExist()) return true;
|
||||
@@ -1971,10 +1964,6 @@ async function isMainUI(maxDuration = 10) {
|
||||
return false; // 一旦出现异常直接退出,不再重试
|
||||
}
|
||||
await sleep(checkDelay); // 识别间隔
|
||||
if (dodispose) {
|
||||
gameRegion.dispose();
|
||||
dodispose = false; // 已经释放,标记避免重复 dispose
|
||||
}
|
||||
}
|
||||
/* 超时仍未识别到,返回失败 */
|
||||
return false;
|
||||
@@ -1986,12 +1975,8 @@ async function isMainUI(maxDuration = 10) {
|
||||
*/
|
||||
async function hasScroll(maxDuration = 10) {
|
||||
const start = Date.now();
|
||||
let dodispose = false;
|
||||
while (Date.now() - start < maxDuration) {
|
||||
if (!gameRegion) {
|
||||
gameRegion = captureGameRegion();
|
||||
dodispose = true;
|
||||
}
|
||||
gameRegion = await getGameRegion();
|
||||
try {
|
||||
const result = gameRegion.find(scrollRo);
|
||||
if (result.isExist()) return true;
|
||||
@@ -2000,10 +1985,6 @@ async function hasScroll(maxDuration = 10) {
|
||||
return false; // 一旦出现异常直接退出,不再重试
|
||||
}
|
||||
await sleep(checkDelay); // 识别间隔
|
||||
if (dodispose) {
|
||||
gameRegion.dispose();
|
||||
dodispose = false; // 已经释放,标记避免重复 dispose
|
||||
}
|
||||
}
|
||||
/* 超时仍未识别到,返回失败 */
|
||||
return false;
|
||||
@@ -2341,25 +2322,21 @@ async function findAndClick(target,
|
||||
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);
|
||||
res.click();
|
||||
await sleep(postClickDelay);
|
||||
}
|
||||
break; // 成功即跳出 for
|
||||
const gameRegion = await getGameRegion();
|
||||
// 依次尝试每一个 ro
|
||||
for (const ro of ros) {
|
||||
const res = gameRegion.find(ro);
|
||||
if (!res.isEmpty()) { // 找到
|
||||
found = res;
|
||||
if (doClick) {
|
||||
await sleep(preClickDelay);
|
||||
res.click();
|
||||
await sleep(postClickDelay);
|
||||
}
|
||||
break; // 成功即跳出 for
|
||||
}
|
||||
if (found) break; // 成功即跳出 while
|
||||
} finally {
|
||||
gameRegion.dispose();
|
||||
}
|
||||
if (found) break; // 成功即跳出 while
|
||||
await sleep(interval); // 没找到时等待
|
||||
}
|
||||
|
||||
@@ -2370,4 +2347,65 @@ async function findAndClick(target,
|
||||
log.error(`执行通用识图时出现错误:${error.message}`);
|
||||
return retType === 0 ? false : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取游戏区域截图,根据时间间隔决定是否重新捕获
|
||||
*
|
||||
* @param {number} [minInterval=17] - 最小截图间隔(毫秒),默认17ms(约60fps)
|
||||
* @param {boolean} [asyncDispose=false] - 是否异步释放旧截图,默认false
|
||||
* @returns {Promise<Object>} 游戏区域截图对象
|
||||
*
|
||||
* @description
|
||||
* 使用 gameRegionManager 对象管理以下属性:
|
||||
* - newGameRegion: 存储最新的游戏区域截图对象
|
||||
* - oldGameRegion: 存储上一个游戏区域截图对象,用于资源释放
|
||||
* - lastCapture: 上一次捕获游戏区域的时间戳
|
||||
* - isDisposing: 标记是否正在释放旧截图,用于安全锁
|
||||
* - isCapturing: 标记是否正在执行截图操作,用于全局锁
|
||||
*/
|
||||
async function getGameRegion(minInterval = 17, asyncDispose = false) {
|
||||
async function disposeOldGameRegion() {
|
||||
if (gameRegionManager.oldGameRegion) {
|
||||
gameRegionManager.isDisposing = true;
|
||||
try {
|
||||
gameRegionManager.oldGameRegion.dispose();
|
||||
} catch (error) {
|
||||
log.error(`释放旧游戏区域截图失败: ${error.message}`);
|
||||
} finally {
|
||||
gameRegionManager.isDisposing = false;
|
||||
gameRegionManager.oldGameRegion = gameRegionManager.newGameRegion;
|
||||
}
|
||||
} else {
|
||||
gameRegionManager.oldGameRegion = gameRegionManager.newGameRegion;
|
||||
}
|
||||
}
|
||||
|
||||
// 等待其他任务完成截图
|
||||
while (gameRegionManager.isCapturing) {
|
||||
await sleep(1);
|
||||
}
|
||||
|
||||
gameRegionManager.isCapturing = true;
|
||||
try {
|
||||
if (new Date() - gameRegionManager.lastCapture >= minInterval || !gameRegionManager.newGameRegion) {
|
||||
while (gameRegionManager.isDisposing) {
|
||||
await sleep(1);
|
||||
}
|
||||
gameRegionManager.lastCapture = new Date();
|
||||
gameRegionManager.newGameRegion = captureGameRegion();
|
||||
|
||||
// 根据参数决定是否等待释放完成
|
||||
if (asyncDispose) {
|
||||
disposeOldGameRegion();
|
||||
} else {
|
||||
await disposeOldGameRegion();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`获取游戏区域截图失败: ${error.message}`);
|
||||
} finally {
|
||||
gameRegionManager.isCapturing = false;
|
||||
return gameRegionManager.newGameRegion;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "锄地一条龙",
|
||||
"version": "2.6.13",
|
||||
"version": "2.7.0",
|
||||
"description": "一站式解决自动化锄地,支持只拾取狗粮,请仔细阅读README.md后使用",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -62,15 +62,6 @@
|
||||
"type": "path",
|
||||
"x": 9666.83203125,
|
||||
"y": 5347.07421875
|
||||
},
|
||||
{
|
||||
"action": "",
|
||||
"action_params": "",
|
||||
"id": 6,
|
||||
"move_mode": "walk",
|
||||
"type": "teleport",
|
||||
"x": 9364.5771484375,
|
||||
"y": 1427.001953125
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user