From d26de80759950643e54ff8d10bce5a7001f40cbd Mon Sep 17 00:00:00 2001 From: ZareMate <0.zaremate@gmail.com> Date: Wed, 1 Apr 2026 19:37:10 +0200 Subject: [PATCH] feat: enhance AFK retry mechanism with GUI interaction and window handling --- afk.js | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 9 deletions(-) diff --git a/afk.js b/afk.js index 0a241cf..afed4e7 100644 --- a/afk.js +++ b/afk.js @@ -1,4 +1,5 @@ const mineflayer = require("mineflayer"); +const gui = require("mineflayer-gui"); const fs = require("fs"); const path = require("path"); @@ -33,8 +34,6 @@ const LOG_FILE = path.join( const TELEPORT_DETECT_REGEX = /you teleported to\b/i; const AFK_INITIAL_CHECK_DELAY_MS = 5000; const AFK_POST_COMMAND_CHECK_DELAY_MS = 7000; -const AFK_MIN_NUMBER = 1; -const AFK_MAX_NUMBER = 50; let hasDetectedTeleport = false; let afkRetryTimer = null; @@ -47,8 +46,79 @@ function log(message) { fs.appendFileSync(LOG_FILE, logMessage + "\n"); } -function getRandomIntInclusive(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function waitForWindowOpen(timeoutMs = 5000) { + return new Promise((resolve) => { + if (bot.currentWindow) { + resolve(true); + return; + } + + const originalHandler = bot.listenerCount("windowOpen"); + const onWindowOpen = () => { + clearTimeout(timer); + bot.removeListener("windowOpen", onWindowOpen); + resolve(true); + }; + + const timer = setTimeout(() => { + bot.removeListener("windowOpen", onWindowOpen); + resolve(false); + }, timeoutMs); + + bot.on("windowOpen", onWindowOpen); + }); +} + +function closeCurrentWindow() { + if (!bot.currentWindow) return; + if (typeof bot.closeWindow === "function") { + bot.closeWindow(bot.currentWindow); + return; + } + if (typeof bot.currentWindow.close === "function") { + bot.currentWindow.close(); + } +} + +function findWindowSlotByCandidates(candidates) { + if (!bot.currentWindow || !Array.isArray(bot.currentWindow.slots)) + return null; + + const normalizedCandidates = candidates.map((c) => + String(c || "") + .toLowerCase() + .replace(/[_\s]+/g, "") + .trim(), + ); + + for (const item of bot.currentWindow.slots) { + if (!item) continue; + + const itemName = String(item.name || "") + .toLowerCase() + .replace(/[_\s]+/g, ""); + const displayName = String(item.displayName || "") + .toLowerCase() + .replace(/[_\s]+/g, ""); + const nbtName = String(item.customName || "") + .toLowerCase() + .replace(/[_\s]+/g, ""); + + const matched = normalizedCandidates.some( + (candidate) => + itemName.includes(candidate) || + displayName.includes(candidate) || + nbtName.includes(candidate), + ); + + if (matched) return item.slot; + } + + return null; } function clearAfkRetryTimer() { @@ -61,13 +131,38 @@ function clearAfkRetryTimer() { function scheduleAfkRetryCheck(delayMs) { clearAfkRetryTimer(); - afkRetryTimer = setTimeout(() => { + afkRetryTimer = setTimeout(async () => { if (hasDetectedTeleport) return; - const randomNumber = getRandomIntInclusive(AFK_MIN_NUMBER, AFK_MAX_NUMBER); - const command = `/afk ${randomNumber}`; - log(`No teleport detected after ${delayMs}ms; sending: ${command}`); - bot.chat(command); + log(`No teleport detected after ${delayMs}ms; sending /afk command`); + bot.chat("/afk"); + + await sleep(500); + const opened = await waitForWindowOpen(5000); + if (!opened || !bot.currentWindow) { + log("AFk GUI did not open"); + scheduleAfkRetryCheck(AFK_POST_COMMAND_CHECK_DELAY_MS); + return; + } + + log("AFk GUI opened, clicking amethyst block"); + const amethystCandidates = ["Amethyst Block", "amethyst_block", "Amethyst"]; + const slot = findWindowSlotByCandidates(amethystCandidates); + if (slot === null) { + log("Amethyst block not found in AFk GUI"); + closeCurrentWindow(); + scheduleAfkRetryCheck(AFK_POST_COMMAND_CHECK_DELAY_MS); + return; + } + + try { + await bot.clickWindow(slot, 0, 0); + log("Clicked amethyst block"); + } catch (err) { + log(`Failed to click amethyst block: ${err.message}`); + } + + closeCurrentWindow(); // Teleport feedback can lag a few seconds after issuing /afk. scheduleAfkRetryCheck(AFK_POST_COMMAND_CHECK_DELAY_MS); @@ -133,10 +228,13 @@ bot.on("login", () => { bot.on("spawn", () => { log("Bot spawned"); + + log(`Bot username: ${bot.username}`); if (hasDetectedTeleport) { log("Teleport already confirmed before spawn; skipping AFK retry schedule"); return; } + scheduleAfkRetryCheck(AFK_INITIAL_CHECK_DELAY_MS); });